svn commit: r357577 - in head/sys: amd64/linux amd64/linux32 arm/linux arm64/linux compat/linux i386/linux
Ed Maste
emaste at FreeBSD.org
Wed Feb 5 16:53:04 UTC 2020
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 at gmail.com>
Submitted by: Yang Wang <2333 at 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, \
More information about the svn-src-all
mailing list