Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 5 Feb 2020 16:53:02 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r357577 - in head/sys: amd64/linux amd64/linux32 arm/linux arm64/linux compat/linux i386/linux
Message-ID:  <202002051653.015Gr2Mr057831@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Wed Feb  5 16:53:02 2020
New Revision: 357577
URL: https://svnweb.freebsd.org/changeset/base/357577

Log:
  linuxulator: implement sendfile
  
  Submitted by:	Bora Özarslan <borako.ozarslan@gmail.com>
  Submitted by:	Yang Wang <2333@outlook.jp>
  Reviewed by:	markj
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D19917

Modified:
  head/sys/amd64/linux/linux_dummy.c
  head/sys/amd64/linux32/linux32_dummy.c
  head/sys/amd64/linux32/syscalls.master
  head/sys/arm/linux/syscalls.master
  head/sys/arm64/linux/linux_dummy.c
  head/sys/compat/linux/linux_socket.c
  head/sys/compat/linux/linux_socket.h
  head/sys/i386/linux/linux_dummy.c
  head/sys/i386/linux/syscalls.master

Modified: head/sys/amd64/linux/linux_dummy.c
==============================================================================
--- head/sys/amd64/linux/linux_dummy.c	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/amd64/linux/linux_dummy.c	Wed Feb  5 16:53:02 2020	(r357577)
@@ -59,7 +59,6 @@ UNIMPLEMENTED(set_thread_area);
 UNIMPLEMENTED(uselib);
 UNIMPLEMENTED(vserver);
 
-DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);
 DUMMY(sysfs);

Modified: head/sys/amd64/linux32/linux32_dummy.c
==============================================================================
--- head/sys/amd64/linux32/linux32_dummy.c	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/amd64/linux32/linux32_dummy.c	Wed Feb  5 16:53:02 2020	(r357577)
@@ -72,7 +72,6 @@ DUMMY(delete_module);
 DUMMY(quotactl);
 DUMMY(bdflush);
 DUMMY(sysfs);
-DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);
 DUMMY(pivot_root);

Modified: head/sys/amd64/linux32/syscalls.master
==============================================================================
--- head/sys/amd64/linux32/syscalls.master	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/amd64/linux32/syscalls.master	Wed Feb  5 16:53:02 2020	(r357577)
@@ -338,7 +338,8 @@
 				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
-187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
+187	AUE_SENDFILE	STD	{ int linux_sendfile(l_int out, l_int in, \
+				    l_long *offset, l_size_t count); }
 188	AUE_GETPMSG	UNIMPL	getpmsg
 189	AUE_PUTPMSG	UNIMPL	putpmsg
 190	AUE_VFORK	STD	{ int linux_vfork(void); }
@@ -412,7 +413,8 @@
 236	AUE_NULL	STD	{ int linux_lremovexattr(void); }
 237	AUE_NULL	STD	{ int linux_fremovexattr(void); }
 238	AUE_NULL	STD	{ int linux_tkill(int tid, int sig); }
-239	AUE_SENDFILE	UNIMPL	linux_sendfile64
+239	AUE_SENDFILE	STD	{ int linux_sendfile64(l_int out, l_int in, \
+				    l_loff_t *offset, l_size_t count); }
 240	AUE_NULL	STD	{ int linux_sys_futex(void *uaddr, int op, uint32_t val, \
 					struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); }
 241	AUE_NULL	STD	{ int linux_sched_setaffinity(l_pid_t pid, l_uint len, \

Modified: head/sys/arm/linux/syscalls.master
==============================================================================
--- head/sys/arm/linux/syscalls.master	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/arm/linux/syscalls.master	Wed Feb  5 16:53:02 2020	(r357577)
@@ -868,7 +868,12 @@
 		);
 	}
 187	AUE_SENDFILE	STD	{
-		int linux_sendfile(void);
+		int linux_sendfile(
+			l_int out,
+			l_int in,
+			l_long *offset,
+			l_size_t count
+		);
 	}
 188	AUE_NULL	UNIMPL	; was getpmsg
 189	AUE_NULL	UNIMPL	; was putpmsg
@@ -1090,7 +1095,14 @@
 		    int sig
 		);
 	}
-239	AUE_SENDFILE	UNIMPL	linux_sendfile64
+239	AUE_SENDFILE	STD	{
+		int linux_sendfile64(
+			l_int out,
+			l_int in,
+			l_loff_t *offset,
+			l_size_t count
+		);
+	}
 240	AUE_NULL	STD	{
 		int linux_sys_futex(void *uaddr,
 		    int op,

Modified: head/sys/arm64/linux/linux_dummy.c
==============================================================================
--- head/sys/arm64/linux/linux_dummy.c	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/arm64/linux/linux_dummy.c	Wed Feb  5 16:53:02 2020	(r357577)
@@ -64,7 +64,6 @@ UNIMPLEMENTED(tuxcall);
 UNIMPLEMENTED(uselib);
 UNIMPLEMENTED(vserver);
 
-DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);
 DUMMY(vhangup);

Modified: head/sys/compat/linux/linux_socket.c
==============================================================================
--- head/sys/compat/linux/linux_socket.c	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/compat/linux/linux_socket.c	Wed Feb  5 16:53:02 2020	(r357577)
@@ -49,9 +49,13 @@ __FBSDID("$FreeBSD$");
 #include <sys/socketvar.h>
 #include <sys/syscallsubr.h>
 #include <sys/uio.h>
+#include <sys/stat.h>
 #include <sys/syslog.h>
 #include <sys/un.h>
+#include <sys/unistd.h>
 
+#include <security/audit/audit.h>
+
 #include <net/if.h>
 #include <net/vnet.h>
 #include <netinet/in.h>
@@ -1581,8 +1585,135 @@ out:
 	return (error);
 }
 
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+static int
+linux_sendfile_common(struct thread *td, l_int out, l_int in,
+    l_loff_t *offset, l_size_t count)
+{
+	off_t bytes_read;
+	int error;
+	l_loff_t current_offset;
+	struct file *fp;
 
+	AUDIT_ARG_FD(in);
+	error = fget_read(td, in, &cap_pread_rights, &fp);
+	if (error != 0)
+		return (error);
+
+	if (offset != NULL) {
+		current_offset = *offset;
+	} else {
+		error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
+		    fo_seek(fp, 0, SEEK_CUR, td) : ESPIPE;
+		if (error != 0)
+			goto drop;
+		current_offset = td->td_uretoff.tdu_off;
+	}
+
+	bytes_read = 0;
+
+	/* Linux cannot have 0 count. */
+	if (count <= 0 || current_offset < 0) {
+		error = EINVAL;
+		goto drop;
+	}
+
+	error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
+	    &bytes_read, 0, td);
+	if (error != 0)
+		goto drop;
+	current_offset += bytes_read;
+
+	if (offset != NULL) {
+		*offset = current_offset;
+	} else {
+		error = fo_seek(fp, current_offset, SEEK_SET, td);
+		if (error != 0)
+			goto drop;
+	}
+
+	td->td_retval[0] = (ssize_t)bytes_read;
+drop:
+	fdrop(fp, td);
+	return (error);
+}
+
+int
+linux_sendfile(struct thread *td, struct linux_sendfile_args *arg)
+{
+	/*
+	 * Differences between FreeBSD and Linux sendfile:
+	 * - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to
+	 *   mean send the whole file.)  In linux_sendfile given fds are still
+	 *   checked for validity when the count is 0.
+	 * - Linux can send to any fd whereas FreeBSD only supports sockets.
+	 *   The same restriction follows for linux_sendfile.
+	 * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
+	 * - Linux takes an offset pointer and updates it to the read location.
+	 *   FreeBSD takes in an offset and a 'bytes read' parameter which is
+	 *   only filled if it isn't NULL.  We use this parameter to update the
+	 *   offset pointer if it exists.
+	 * - Linux sendfile returns bytes read on success while FreeBSD
+	 *   returns 0.  We use the 'bytes read' parameter to get this value.
+	 */
+
+	l_loff_t offset64;
+	l_long offset;
+	int ret;
+	int error;
+
+	if (arg->offset != NULL) {
+		error = copyin(arg->offset, &offset, sizeof(offset));
+		if (error != 0)
+			return (error);
+		offset64 = (l_loff_t)offset;
+	}
+
+	ret = linux_sendfile_common(td, arg->out, arg->in,
+	    arg->offset != NULL ? &offset64 : NULL, arg->count);
+
+	if (arg->offset != NULL) {
+#if defined(__i386__) || defined(__arm__) || \
+    (defined(__amd64__) && defined(COMPAT_LINUX32))
+		if (offset64 > INT32_MAX)
+			return (EOVERFLOW);
+#endif
+		offset = (l_long)offset64;
+		error = copyout(&offset, arg->offset, sizeof(offset));
+		if (error != 0)
+			return (error);
+	}
+
+	return (ret);
+}
+
+#if defined(__i386__) || defined(__arm__) || \
+    (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+int
+linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg)
+{
+	l_loff_t offset;
+	int ret;
+	int error;
+
+	if (arg->offset != NULL) {
+		error = copyin(arg->offset, &offset, sizeof(offset));
+		if (error != 0)
+			return (error);
+	}
+
+	ret = linux_sendfile_common(td, arg->out, arg->in,
+		arg->offset != NULL ? &offset : NULL, arg->count);
+
+	if (arg->offset != NULL) {
+		error = copyout(&offset, arg->offset, sizeof(offset));
+		if (error != 0)
+			return (error);
+	}
+
+	return (ret);
+}
+
 /* Argument list sizes for linux_socketcall */
 static const unsigned char lxs_args_cnt[] = {
 	0 /* unused*/,		3 /* socket */,
@@ -1595,7 +1726,7 @@ static const unsigned char lxs_args_cnt[] = {
 	5 /* setsockopt */,	5 /* getsockopt */,
 	3 /* sendmsg */,	3 /* recvmsg */,
 	4 /* accept4 */,	5 /* recvmmsg */,
-	4 /* sendmmsg */
+	4 /* sendmmsg */,	4 /* sendfile */
 };
 #define	LINUX_ARGS_CNT		(nitems(lxs_args_cnt) - 1)
 #define	LINUX_ARG_SIZE(x)	(lxs_args_cnt[x] * sizeof(l_ulong))
@@ -1664,9 +1795,11 @@ linux_socketcall(struct thread *td, struct linux_socke
 		return (linux_recvmmsg(td, arg));
 	case LINUX_SENDMMSG:
 		return (linux_sendmmsg(td, arg));
+	case LINUX_SENDFILE:
+		return (linux_sendfile(td, arg));
 	}
 
 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
 	return (ENOSYS);
 }
-#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */

Modified: head/sys/compat/linux/linux_socket.h
==============================================================================
--- head/sys/compat/linux/linux_socket.h	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/compat/linux/linux_socket.h	Wed Feb  5 16:53:02 2020	(r357577)
@@ -132,7 +132,9 @@ struct l_ucred {
 	uint32_t	gid;
 };
 
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+#if defined(__i386__) || defined(__arm__) || \
+    (defined(__amd64__) && defined(COMPAT_LINUX32))
+
 struct linux_accept_args {
 	register_t s;
 	register_t addr;
@@ -162,7 +164,9 @@ int linux_accept(struct thread *td, struct linux_accep
 #define	LINUX_ACCEPT4		18
 #define	LINUX_RECVMMSG		19
 #define	LINUX_SENDMMSG		20
-#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+#define	LINUX_SENDFILE		21
+
+#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
 
 /* Socket defines */
 #define	LINUX_SOL_SOCKET	1

Modified: head/sys/i386/linux/linux_dummy.c
==============================================================================
--- head/sys/i386/linux/linux_dummy.c	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/i386/linux/linux_dummy.c	Wed Feb  5 16:53:02 2020	(r357577)
@@ -75,7 +75,6 @@ DUMMY(quotactl);
 DUMMY(bdflush);
 DUMMY(sysfs);
 DUMMY(vm86);
-DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);
 DUMMY(pivot_root);

Modified: head/sys/i386/linux/syscalls.master
==============================================================================
--- head/sys/i386/linux/syscalls.master	Wed Feb  5 16:10:09 2020	(r357576)
+++ head/sys/i386/linux/syscalls.master	Wed Feb  5 16:53:02 2020	(r357577)
@@ -341,7 +341,8 @@
 				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
-187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
+187	AUE_SENDFILE	STD	{ int linux_sendfile(l_int out, l_int in, \
+				    l_long *offset, l_size_t count); }
 188	AUE_GETPMSG	UNIMPL	getpmsg
 189	AUE_PUTPMSG	UNIMPL	putpmsg
 190	AUE_VFORK	STD	{ int linux_vfork(void); }
@@ -415,7 +416,8 @@
 236	AUE_NULL	STD	{ int linux_lremovexattr(void); }
 237	AUE_NULL	STD	{ int linux_fremovexattr(void); }
 238	AUE_NULL	STD	{ int linux_tkill(int tid, int sig); }
-239	AUE_SENDFILE	UNIMPL	linux_sendfile64
+239	AUE_SENDFILE	STD	{ int linux_sendfile64(l_int out, l_int in, \
+				    l_loff_t *offset, l_size_t count); }
 240	AUE_NULL	STD	{ int linux_sys_futex(void *uaddr, int op, uint32_t val, \
 					struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); }
 241	AUE_NULL	STD	{ int linux_sched_setaffinity(l_pid_t pid, l_uint len, \



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202002051653.015Gr2Mr057831>