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.ozars...@gmail.com> Submitted by: Yang Wang <2...@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, \ _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"