Index: sys/amd64/linux/linux_dummy.c =================================================================== --- sys/amd64/linux/linux_dummy.c +++ sys/amd64/linux/linux_dummy.c @@ -59,7 +59,6 @@ UNIMPLEMENTED(uselib); UNIMPLEMENTED(vserver); -DUMMY(sendfile); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(sysfs); Index: sys/amd64/linux32/linux32_dummy.c =================================================================== --- sys/amd64/linux32/linux32_dummy.c +++ sys/amd64/linux32/linux32_dummy.c @@ -72,7 +72,6 @@ DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); -DUMMY(sendfile); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); Index: sys/amd64/linux32/linux32_proto.h =================================================================== --- sys/amd64/linux32/linux32_proto.h +++ sys/amd64/linux32/linux32_proto.h @@ -604,7 +604,10 @@ char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_sendfile_args { - register_t dummy; + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_long *)]; l_long * offset; char offset_r_[PADR_(l_long *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; }; struct linux_vfork_args { register_t dummy; @@ -733,6 +736,12 @@ char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; +struct linux_sendfile64_args { + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t *)]; l_loff_t * offset; char offset_r_[PADR_(l_loff_t *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; +}; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; @@ -1687,6 +1696,7 @@ int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); +int linux_sendfile64(struct thread *, struct linux_sendfile64_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); @@ -2081,6 +2091,7 @@ #define LINUX32_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX32_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX32_SYS_AUE_linux_tkill AUE_NULL +#define LINUX32_SYS_AUE_linux_sendfile64 AUE_SENDFILE #define LINUX32_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX32_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX32_SYS_AUE_linux_sched_getaffinity AUE_NULL Index: sys/amd64/linux32/linux32_syscall.h =================================================================== --- sys/amd64/linux32/linux32_syscall.h +++ sys/amd64/linux32/linux32_syscall.h @@ -216,6 +216,7 @@ #define LINUX32_SYS_linux_lremovexattr 236 #define LINUX32_SYS_linux_fremovexattr 237 #define LINUX32_SYS_linux_tkill 238 +#define LINUX32_SYS_linux_sendfile64 239 #define LINUX32_SYS_linux_sys_futex 240 #define LINUX32_SYS_linux_sched_setaffinity 241 #define LINUX32_SYS_linux_sched_getaffinity 242 Index: sys/amd64/linux32/linux32_syscalls.c =================================================================== --- sys/amd64/linux32/linux32_syscalls.c +++ sys/amd64/linux32/linux32_syscalls.c @@ -246,7 +246,7 @@ "linux_lremovexattr", /* 236 = linux_lremovexattr */ "linux_fremovexattr", /* 237 = linux_fremovexattr */ "linux_tkill", /* 238 = linux_tkill */ - "#239", /* 239 = linux_sendfile64 */ + "linux_sendfile64", /* 239 = linux_sendfile64 */ "linux_sys_futex", /* 240 = linux_sys_futex */ "linux_sched_setaffinity", /* 241 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 242 = linux_sched_getaffinity */ Index: sys/amd64/linux32/linux32_sysent.c =================================================================== --- sys/amd64/linux32/linux32_sysent.c +++ sys/amd64/linux32/linux32_sysent.c @@ -204,7 +204,7 @@ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_capset */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_sigaltstack */ - { 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ + { AS(linux_sendfile_args), (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = getpmsg */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = putpmsg */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_vfork */ @@ -256,7 +256,7 @@ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_tkill */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = linux_sendfile64 */ + { AS(linux_sendfile64_args), (sy_call_t *)linux_sendfile64, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 239 = linux_sendfile64 */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_sched_getaffinity */ Index: sys/amd64/linux32/linux32_systrace_args.c =================================================================== --- sys/amd64/linux32/linux32_systrace_args.c +++ sys/amd64/linux32/linux32_systrace_args.c @@ -1292,7 +1292,12 @@ } /* linux_sendfile */ case 187: { - *n_args = 0; + struct linux_sendfile_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_long * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; break; } /* linux_vfork */ @@ -1616,6 +1621,16 @@ *n_args = 2; break; } + /* linux_sendfile64 */ + case 239: { + struct linux_sendfile64_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_loff_t * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; + break; + } /* linux_sys_futex */ case 240: { struct linux_sys_futex_args *p = params; @@ -4970,6 +4985,22 @@ break; /* linux_sendfile */ case 187: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_long *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; break; /* linux_vfork */ case 190: @@ -5409,6 +5440,25 @@ break; }; break; + /* linux_sendfile64 */ + case 239: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_loff_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; /* linux_sys_futex */ case 240: switch(ndx) { @@ -8261,6 +8311,9 @@ break; /* linux_sendfile */ case 187: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_vfork */ case 190: /* linux_getrlimit */ @@ -8434,6 +8487,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* linux_sendfile64 */ + case 239: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_sys_futex */ case 240: if (ndx == 0 || ndx == 1) Index: sys/amd64/linux32/syscalls.master =================================================================== --- sys/amd64/linux32/syscalls.master +++ sys/amd64/linux32/syscalls.master @@ -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, \ Index: sys/arm/linux/linux_proto.h =================================================================== --- sys/arm/linux/linux_proto.h +++ sys/arm/linux/linux_proto.h @@ -509,7 +509,10 @@ char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_sendfile_args { - register_t dummy; + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_long *)]; l_long * offset; char offset_r_[PADR_(l_long *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; }; struct linux_vfork_args { register_t dummy; @@ -638,6 +641,12 @@ char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; +struct linux_sendfile64_args { + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t *)]; l_loff_t * offset; char offset_r_[PADR_(l_loff_t *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; +}; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; @@ -1371,6 +1380,7 @@ int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); +int linux_sendfile64(struct thread *, struct linux_sendfile64_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); @@ -1696,6 +1706,7 @@ #define LINUX_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_tkill AUE_NULL +#define LINUX_SYS_AUE_linux_sendfile64 AUE_SENDFILE #define LINUX_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX_SYS_AUE_linux_sched_getaffinity AUE_NULL Index: sys/arm/linux/linux_syscall.h =================================================================== --- sys/arm/linux/linux_syscall.h +++ sys/arm/linux/linux_syscall.h @@ -195,6 +195,7 @@ #define LINUX_SYS_linux_lremovexattr 236 #define LINUX_SYS_linux_fremovexattr 237 #define LINUX_SYS_linux_tkill 238 +#define LINUX_SYS_linux_sendfile64 239 #define LINUX_SYS_linux_sys_futex 240 #define LINUX_SYS_linux_sched_setaffinity 241 #define LINUX_SYS_linux_sched_getaffinity 242 Index: sys/arm/linux/linux_syscalls.c =================================================================== --- sys/arm/linux/linux_syscalls.c +++ sys/arm/linux/linux_syscalls.c @@ -246,7 +246,7 @@ "linux_lremovexattr", /* 236 = linux_lremovexattr */ "linux_fremovexattr", /* 237 = linux_fremovexattr */ "linux_tkill", /* 238 = linux_tkill */ - "#239", /* 239 = linux_sendfile64 */ + "linux_sendfile64", /* 239 = linux_sendfile64 */ "linux_sys_futex", /* 240 = linux_sys_futex */ "linux_sched_setaffinity", /* 241 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 242 = linux_sched_getaffinity */ Index: sys/arm/linux/linux_sysent.c =================================================================== --- sys/arm/linux/linux_sysent.c +++ sys/arm/linux/linux_sysent.c @@ -204,7 +204,7 @@ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_capset */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_sigaltstack */ - { 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ + { AS(linux_sendfile_args), (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = ; */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = ; */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_vfork */ @@ -256,7 +256,7 @@ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_tkill */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = linux_sendfile64 */ + { AS(linux_sendfile64_args), (sy_call_t *)linux_sendfile64, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 239 = linux_sendfile64 */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_sched_getaffinity */ Index: sys/arm/linux/linux_systrace_args.c =================================================================== --- sys/arm/linux/linux_systrace_args.c +++ sys/arm/linux/linux_systrace_args.c @@ -1135,7 +1135,12 @@ } /* linux_sendfile */ case 187: { - *n_args = 0; + struct linux_sendfile_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_long * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; break; } /* linux_vfork */ @@ -1459,6 +1464,16 @@ *n_args = 2; break; } + /* linux_sendfile64 */ + case 239: { + struct linux_sendfile64_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_loff_t * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; + break; + } /* linux_sys_futex */ case 240: { struct linux_sys_futex_args *p = params; @@ -4248,6 +4263,22 @@ break; /* linux_sendfile */ case 187: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_long *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; break; /* linux_vfork */ case 190: @@ -4687,6 +4718,25 @@ break; }; break; + /* linux_sendfile64 */ + case 239: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_loff_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; /* linux_sys_futex */ case 240: switch(ndx) { @@ -6978,6 +7028,9 @@ break; /* linux_sendfile */ case 187: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_vfork */ case 190: /* linux_getrlimit */ @@ -7151,6 +7204,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* linux_sendfile64 */ + case 239: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_sys_futex */ case 240: if (ndx == 0 || ndx == 1) Index: sys/arm/linux/syscalls.master =================================================================== --- sys/arm/linux/syscalls.master +++ sys/arm/linux/syscalls.master @@ -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, Index: sys/arm64/linux/linux_dummy.c =================================================================== --- sys/arm64/linux/linux_dummy.c +++ sys/arm64/linux/linux_dummy.c @@ -64,7 +64,6 @@ UNIMPLEMENTED(uselib); UNIMPLEMENTED(vserver); -DUMMY(sendfile); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(vhangup); Index: sys/compat/linux/linux_socket.h =================================================================== --- sys/compat/linux/linux_socket.h +++ sys/compat/linux/linux_socket.h @@ -132,7 +132,9 @@ 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 @@ #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 Index: sys/compat/linux/linux_socket.c =================================================================== --- sys/compat/linux/linux_socket.c +++ sys/compat/linux/linux_socket.c @@ -49,8 +49,12 @@ #include #include #include +#include #include #include +#include + +#include #include #include @@ -1570,7 +1574,145 @@ 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) +{ + /* handles sandfile in kernel space */ + + 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; + + /* liunx 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) +{ + /* XXX: The differences between freebsd and linux sendfile: + * - linux_sendfile doesn't send anything when count is 0 + * whereas freebsd_sendfile sends the whole file. However, + * in linux_sendfile given fds are still checked for if they + * are valid or not when count is 0. + * - linux_sendfile can send to any fd whereas freebsd_sendfile + * only sends to a socket stream. The same restriction follows + * for linux_sendfile. + * - linux_sendfile doesn't have equivalents of flags and sf_hdtr of + * freebsd_sendfile. + * - linux_sendfile takes in an offset pointer and updates it to where it + * was read until. freebsd_sendfile 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_sendfile + * returns 0. We use the 'bytes read' parameter to get this value. + */ + + /* YYY: The only difference between sendfile and sendfile64 (for 32bit + * platform where LFS is enabled) is offset type. The latter must be + * 64 bit + * If no offset pointer is given, in_fd's offset detail is read and + * updated, otherwise given pointer is used + */ + + 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[] = { @@ -1584,7 +1726,7 @@ 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)) @@ -1653,9 +1795,11 @@ 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) */ Index: sys/i386/linux/linux_dummy.c =================================================================== --- sys/i386/linux/linux_dummy.c +++ sys/i386/linux/linux_dummy.c @@ -75,7 +75,6 @@ DUMMY(bdflush); DUMMY(sysfs); DUMMY(vm86); -DUMMY(sendfile); /* different semantics */ DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); Index: sys/i386/linux/linux_proto.h =================================================================== --- sys/i386/linux/linux_proto.h +++ sys/i386/linux/linux_proto.h @@ -605,7 +605,10 @@ char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; }; struct linux_sendfile_args { - register_t dummy; + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_long *)]; l_long * offset; char offset_r_[PADR_(l_long *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; }; struct linux_vfork_args { register_t dummy; @@ -734,6 +737,12 @@ char tid_l_[PADL_(int)]; int tid; char tid_r_[PADR_(int)]; char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; +struct linux_sendfile64_args { + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t *)]; l_loff_t * offset; char offset_r_[PADR_(l_loff_t *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; +}; struct linux_sys_futex_args { char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)]; char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; @@ -1706,6 +1715,7 @@ int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); int linux_tkill(struct thread *, struct linux_tkill_args *); +int linux_sendfile64(struct thread *, struct linux_sendfile64_args *); int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); @@ -2102,6 +2112,7 @@ #define LINUX_SYS_AUE_linux_lremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_fremovexattr AUE_NULL #define LINUX_SYS_AUE_linux_tkill AUE_NULL +#define LINUX_SYS_AUE_linux_sendfile64 AUE_SENDFILE #define LINUX_SYS_AUE_linux_sys_futex AUE_NULL #define LINUX_SYS_AUE_linux_sched_setaffinity AUE_NULL #define LINUX_SYS_AUE_linux_sched_getaffinity AUE_NULL Index: sys/i386/linux/linux_syscall.h =================================================================== --- sys/i386/linux/linux_syscall.h +++ sys/i386/linux/linux_syscall.h @@ -222,6 +222,7 @@ #define LINUX_SYS_linux_lremovexattr 236 #define LINUX_SYS_linux_fremovexattr 237 #define LINUX_SYS_linux_tkill 238 +#define LINUX_SYS_linux_sendfile64 239 #define LINUX_SYS_linux_sys_futex 240 #define LINUX_SYS_linux_sched_setaffinity 241 #define LINUX_SYS_linux_sched_getaffinity 242 Index: sys/i386/linux/linux_syscalls.c =================================================================== --- sys/i386/linux/linux_syscalls.c +++ sys/i386/linux/linux_syscalls.c @@ -246,7 +246,7 @@ "linux_lremovexattr", /* 236 = linux_lremovexattr */ "linux_fremovexattr", /* 237 = linux_fremovexattr */ "linux_tkill", /* 238 = linux_tkill */ - "#239", /* 239 = linux_sendfile64 */ + "linux_sendfile64", /* 239 = linux_sendfile64 */ "linux_sys_futex", /* 240 = linux_sys_futex */ "linux_sched_setaffinity", /* 241 = linux_sched_setaffinity */ "linux_sched_getaffinity", /* 242 = linux_sched_getaffinity */ Index: sys/i386/linux/linux_sysent.c =================================================================== --- sys/i386/linux/linux_sysent.c +++ sys/i386/linux/linux_sysent.c @@ -204,7 +204,7 @@ { AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 184 = linux_capget */ { AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = linux_capset */ { AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = linux_sigaltstack */ - { 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ + { AS(linux_sendfile_args), (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 187 = linux_sendfile */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = getpmsg */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = putpmsg */ { 0, (sy_call_t *)linux_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = linux_vfork */ @@ -256,7 +256,7 @@ { 0, (sy_call_t *)linux_lremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = linux_lremovexattr */ { 0, (sy_call_t *)linux_fremovexattr, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = linux_fremovexattr */ { AS(linux_tkill_args), (sy_call_t *)linux_tkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = linux_tkill */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = linux_sendfile64 */ + { AS(linux_sendfile64_args), (sy_call_t *)linux_sendfile64, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 239 = linux_sendfile64 */ { AS(linux_sys_futex_args), (sy_call_t *)linux_sys_futex, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = linux_sys_futex */ { AS(linux_sched_setaffinity_args), (sy_call_t *)linux_sched_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = linux_sched_setaffinity */ { AS(linux_sched_getaffinity_args), (sy_call_t *)linux_sched_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = linux_sched_getaffinity */ Index: sys/i386/linux/linux_systrace_args.c =================================================================== --- sys/i386/linux/linux_systrace_args.c +++ sys/i386/linux/linux_systrace_args.c @@ -1335,7 +1335,12 @@ } /* linux_sendfile */ case 187: { - *n_args = 0; + struct linux_sendfile_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_long * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; break; } /* linux_vfork */ @@ -1659,6 +1664,16 @@ *n_args = 2; break; } + /* linux_sendfile64 */ + case 239: { + struct linux_sendfile64_args *p = params; + iarg[0] = p->out; /* l_int */ + iarg[1] = p->in; /* l_int */ + uarg[2] = (intptr_t) p->offset; /* l_loff_t * */ + iarg[3] = p->count; /* l_size_t */ + *n_args = 4; + break; + } /* linux_sys_futex */ case 240: { struct linux_sys_futex_args *p = params; @@ -5107,6 +5122,22 @@ break; /* linux_sendfile */ case 187: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_long *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; break; /* linux_vfork */ case 190: @@ -5546,6 +5577,25 @@ break; }; break; + /* linux_sendfile64 */ + case 239: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_loff_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; /* linux_sys_futex */ case 240: switch(ndx) { @@ -8516,6 +8566,9 @@ break; /* linux_sendfile */ case 187: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_vfork */ case 190: /* linux_getrlimit */ @@ -8689,6 +8742,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* linux_sendfile64 */ + case 239: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_sys_futex */ case 240: if (ndx == 0 || ndx == 1) Index: sys/i386/linux/syscalls.master =================================================================== --- sys/i386/linux/syscalls.master +++ sys/i386/linux/syscalls.master @@ -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, \