Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map (revision 252610) +++ lib/libc/sys/Symbol.map (working copy) @@ -380,6 +380,7 @@ FBSD_1.3 { accept4; aio_mlock; + aio_sendfile; bindat; cap_fcntls_get; cap_fcntls_limit; Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master (revision 252610) +++ sys/compat/freebsd32/syscalls.master (working copy) @@ -1046,3 +1046,5 @@ 542 AUE_PIPE NOPROTO { int pipe2(int *fildes, int flags); } 543 AUE_NULL NOSTD { int freebsd32_aio_mlock( \ struct aiocb32 *aiocbp); } +544 AUE_NULL NOSTD { int freebsd32_aio_sendfile( \ + struct aiocb32 *aiocbp); } Index: sys/kern/init_sysent.c =================================================================== --- sys/kern/init_sysent.c (revision 252610) +++ sys/kern/init_sysent.c (working copy) @@ -578,4 +578,5 @@ { AS(accept4_args), (sy_call_t *)sys_accept4, AUE_ACCEPT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 541 = accept4 */ { AS(pipe2_args), (sy_call_t *)sys_pipe2, AUE_PIPE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 542 = pipe2 */ { AS(aio_mlock_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 543 = aio_mlock */ + { AS(aio_sendfile_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 544 = aio_sendfile */ }; Index: sys/kern/syscalls.c =================================================================== --- sys/kern/syscalls.c (revision 252610) +++ sys/kern/syscalls.c (working copy) @@ -551,4 +551,5 @@ "accept4", /* 541 = accept4 */ "pipe2", /* 542 = pipe2 */ "aio_mlock", /* 543 = aio_mlock */ + "aio_sendfile", /* 544 = aio_sendfile */ }; Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master (revision 252610) +++ sys/kern/syscalls.master (working copy) @@ -978,5 +978,6 @@ int flags); } 542 AUE_PIPE STD { int pipe2(int *fildes, int flags); } 543 AUE_NULL NOSTD { int aio_mlock(struct aiocb *aiocbp); } +544 AUE_NULL NOSTD { int aio_sendfile(struct aiocb *aiocbp); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/kern/systrace_args.c =================================================================== --- sys/kern/systrace_args.c (revision 252610) +++ sys/kern/systrace_args.c (working copy) @@ -3383,6 +3383,13 @@ *n_args = 1; break; } + /* aio_sendfile */ + case 544: { + struct aio_sendfile_args *p = params; + uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb * */ + *n_args = 1; + break; + } default: *n_args = 0; break; @@ -9012,6 +9019,16 @@ break; }; break; + /* aio_sendfile */ + case 544: + switch(ndx) { + case 0: + p = "struct aiocb *"; + break; + default: + break; + }; + break; default: break; }; @@ -10960,6 +10977,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* aio_sendfile */ + case 544: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; Index: sys/kern/uipc_syscalls.c =================================================================== --- sys/kern/uipc_syscalls.c (revision 252610) +++ sys/kern/uipc_syscalls.c (working copy) @@ -1877,8 +1877,10 @@ struct sf_hdtr hdtr; struct uio *hdr_uio, *trl_uio; int error; + off_t ret_sbytes; hdr_uio = trl_uio = NULL; + ret_sbytes = 0; if (uap->hdtr != NULL) { error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); @@ -1897,7 +1899,12 @@ } } - error = kern_sendfile(td, uap, hdr_uio, trl_uio, compat); + error = kern_sendfile(td, uap, hdr_uio, trl_uio, &ret_sbytes, compat); + + if (uap->sbytes != NULL) { + copyout(&ret_sbytes, uap->sbytes, sizeof(off_t)); + } + out: if (hdr_uio) free(hdr_uio, M_IOV); @@ -1926,7 +1933,8 @@ int kern_sendfile(struct thread *td, struct sendfile_args *uap, - struct uio *hdr_uio, struct uio *trl_uio, int compat) + struct uio *hdr_uio, struct uio *trl_uio, off_t *ret_sbytes, + int compat) { struct file *sock_fp; struct vnode *vp; @@ -2393,8 +2401,8 @@ if (error == 0) { td->td_retval[0] = 0; } - if (uap->sbytes != NULL) { - copyout(&sbytes, uap->sbytes, sizeof(off_t)); + if (ret_sbytes != NULL) { + (*ret_sbytes) = sbytes; } if (obj != NULL) vm_object_deallocate(obj); Index: sys/kern/vfs_aio.c =================================================================== --- sys/kern/vfs_aio.c (revision 252610) +++ sys/kern/vfs_aio.c (working copy) @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -236,8 +237,11 @@ * buffer pointer */ struct proc *userproc; /* (*) user process */ + struct thread *usertd; /* (*) user thread */ struct ucred *cred; /* (*) active credential when created */ struct file *fd_file; /* (*) pointer to file structure */ + struct file *fd_sendfile_src; /* (*) sendfile - "from" file */ + struct file *fd_sendfile_dst; /* (*) sendfile - "to" socket */ struct aioliojob *lio; /* (*) optional lio job */ struct aiocb *uuaiocb; /* (*) pointer in userspace of aiocb */ struct knlist klist; /* (a) list of knotes */ @@ -341,6 +345,7 @@ static void aio_process_rw(struct aiocblist *aiocbe); static void aio_process_sync(struct aiocblist *aiocbe); static void aio_process_mlock(struct aiocblist *aiocbe); +static void aio_process_sendfile(struct aiocblist *aiocbe); static int aio_newproc(int *); int aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lio, int type, struct aiocb_ops *ops); @@ -428,6 +433,7 @@ SYSCALL_INIT_HELPER(aio_error), SYSCALL_INIT_HELPER(aio_fsync), SYSCALL_INIT_HELPER(aio_mlock), + SYSCALL_INIT_HELPER(aio_sendfile), SYSCALL_INIT_HELPER(aio_read), SYSCALL_INIT_HELPER(aio_return), SYSCALL_INIT_HELPER(aio_suspend), @@ -456,6 +462,7 @@ SYSCALL32_INIT_HELPER(freebsd32_aio_error), SYSCALL32_INIT_HELPER(freebsd32_aio_fsync), SYSCALL32_INIT_HELPER(freebsd32_aio_mlock), + SYSCALL32_INIT_HELPER(freebsd32_aio_sendfile), SYSCALL32_INIT_HELPER(freebsd32_aio_read), SYSCALL32_INIT_HELPER(freebsd32_aio_write), SYSCALL32_INIT_HELPER(freebsd32_aio_waitcomplete), @@ -707,6 +714,10 @@ */ if (aiocbe->fd_file) fdrop(aiocbe->fd_file, curthread); + if (aiocbe->fd_sendfile_src) + fdrop(aiocbe->fd_sendfile_src, curthread); + if (aiocbe->fd_sendfile_dst) + fdrop(aiocbe->fd_sendfile_dst, curthread); crfree(aiocbe->cred); uma_zfree(aiocb_zone, aiocbe); AIO_LOCK(ki); @@ -987,6 +998,101 @@ } static void +aio_process_sendfile(struct aiocblist *aiocbe) +{ + struct thread *td; + struct ucred *td_savedcred; + struct aiocb *cb = &aiocbe->uaiocb; + struct sf_hdtr hdtr; + struct uio *hdr_uio, *trl_uio; + struct sendfile_args sa; + int error; + off_t ret_sbytes; + + ret_sbytes = 0; /* In case of error */ + + KASSERT(aiocbe->uaiocb.aio_lio_opcode == LIO_SENDFILE, + ("%s: opcode %d", __func__, aiocbe->uaiocb.aio_lio_opcode)); + + hdr_uio = trl_uio = NULL; + ret_sbytes = 0; + + /* + * XXX TODO: save/restore thread credentials when doing this + * IO. + */ + td = curthread; + td_savedcred = td->td_ucred; + td->td_ucred = aiocbe->cred; + + /* + * "Fake" a sendfile() syscall by populating the args struct + * from the aiocb. This keeps kern_sendfile() happy. + */ + sa.fd = cb->aio_sendfile_srcfd; + sa.s = cb->aio_fildes; + sa.offset = cb->aio_offset; + sa.nbytes = cb->aio_nbytes; + sa.hdtr = cb->aio_sendfile_hdtr; + sa.sbytes = NULL; /* XXX no copyout() of this! */ + sa.flags = cb->aio_sendfile_flags; + +#if 0 + printf("%s: fd=%d, s=%d, offset=%d, nbytes=%d, flags=%d\n", + __func__, + (int) sa.fd, + (int) sa.s, + (int) sa.offset, + (int) sa.nbytes, + (int) sa.flags); +#endif + + /* + * Copy in the sendfile arguments as required. + */ + if (sa.hdtr != NULL) { + error = copyin(sa.hdtr, &hdtr, sizeof(hdtr)); + if (error) + goto out; + if (hdtr.headers != NULL) { + error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); + if (error) + goto out; + } + if (hdtr.trailers != NULL) { + error = copyinuio(hdtr.trailers, hdtr.trl_cnt, &trl_uio); + if (error) + goto out; + } + } + + /* + * Call kern_sendfile(). It will use the provided + * copyin'ed args as needed. It's a shame it requires + * the rest of the fields in the syscall struct; alas.. + */ + error = kern_sendfile(aiocbe->usertd, &sa, hdr_uio, trl_uio, + &ret_sbytes, 0); + +out: + if (hdr_uio) + free(hdr_uio, M_IOV); + if (trl_uio) + free(trl_uio, M_IOV); + + cb->_aiocb_private.error = error; + if (error == 0) + cb->_aiocb_private.status = (int) ret_sbytes; + else + cb->_aiocb_private.status = 0; + + /* + * Restore credentials. + */ + td->td_ucred = td_savedcred; +} + +static void aio_bio_done_notify(struct proc *userp, struct aiocblist *aiocbe, int type) { struct aioliojob *lj; @@ -1165,6 +1271,9 @@ case LIO_MLOCK: aio_process_mlock(aiocbe); break; + case LIO_SENDFILE: + aio_process_sendfile(aiocbe); + break; } mtx_lock(&aio_job_mtx); @@ -1567,7 +1676,7 @@ int type, struct aiocb_ops *ops) { struct proc *p = td->td_proc; - struct file *fp; + struct file *fp, *fp_sendfile_src, *fp_sendfile_dst; struct socket *so; struct aiocblist *aiocbe, *cb; struct kaioinfo *ki; @@ -1660,6 +1769,14 @@ case LIO_MLOCK: fp = NULL; break; + case LIO_SENDFILE: + fp = NULL; + error = fget(td, fd, CAP_PWRITE, &fp_sendfile_dst); + if (error != 0) + break; + error = fget(td, aiocbe->uaiocb.aio_sendfile_srcfd, + CAP_PREAD, &fp_sendfile_src); + break; case LIO_NOP: error = fget(td, fd, CAP_NONE, &fp); break; @@ -1683,6 +1800,8 @@ } aiocbe->fd_file = fp; + aiocbe->fd_sendfile_src = fp_sendfile_src; + aiocbe->fd_sendfile_dst = fp_sendfile_dst; mtx_lock(&aio_job_mtx); jid = jobrefid++; @@ -1719,6 +1838,10 @@ if (error) { if (fp) fdrop(fp, td); + if (fp_sendfile_src) + fdrop(fp_sendfile_src, td); + if (fp_sendfile_dst) + fdrop(fp_sendfile_dst, td); uma_zfree(aiocb_zone, aiocbe); ops->store_error(job, error); goto done; @@ -1728,6 +1851,7 @@ ops->store_error(job, EINPROGRESS); aiocbe->uaiocb._aiocb_private.error = EINPROGRESS; aiocbe->userproc = p; + aiocbe->usertd = td; /* XXX is there any guarantee this thread won't go away? */ aiocbe->cred = crhold(td->td_ucred); aiocbe->jobflags = 0; aiocbe->lio = lj; @@ -2220,6 +2344,13 @@ return (aio_aqueue(td, uap->aiocbp, NULL, LIO_MLOCK, &aiocb_ops)); } +int +sys_aio_sendfile(struct thread *td, struct aio_sendfile_args *uap) +{ + + return (aio_aqueue(td, uap->aiocbp, NULL, LIO_SENDFILE, &aiocb_ops)); +} + static int kern_lio_listio(struct thread *td, int mode, struct aiocb * const *uacb_list, struct aiocb **acb_list, int nent, struct sigevent *sig, @@ -2970,6 +3101,14 @@ } int +freebsd32_aio_sendfile(struct thread *td, struct freebsd32_aio_sendfile_args *uap) +{ + + return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_SENDFILE, + &aiocb32_ops)); +} + +int freebsd32_aio_waitcomplete(struct thread *td, struct freebsd32_aio_waitcomplete_args *uap) { Index: sys/sys/aio.h =================================================================== --- sys/sys/aio.h (revision 252610) +++ sys/sys/aio.h (working copy) @@ -38,6 +38,7 @@ #ifdef _KERNEL #define LIO_SYNC 0x3 #define LIO_MLOCK 0x4 +#define LIO_SENDFILE 0x5 #endif /* @@ -61,6 +62,18 @@ void *kernelinfo; }; +#if 0 +typedef struct aiocb_sendfile { + int aio_source_fd; /* "from" file descriptor */ + int aio_dest_fd; /* "to" file descriptor */ + /* use 'aio_offset' for offset */ + /* use 'aio_nbytes' for nbytes */ + struct sf_hdtr *aio_hdtr; /* sendfile header/trailer info */ + int aio_flags; /* flags to sendfile() */ + /* sbytes will be returned via aio_return() */ +} aiocb_sendfile_t; +#endif + /* * I/O control block */ @@ -69,8 +82,9 @@ off_t aio_offset; /* File offset for I/O */ volatile void *aio_buf; /* I/O buffer in process space */ size_t aio_nbytes; /* Number of bytes for I/O */ - int __spare__[2]; - void *__spare2__; + int aio_sendfile_srcfd; /* source fd for sendfile() */ + int aio_sendfile_flags; /* sendfile() flags */ + struct sf_hdtr *aio_sendfile_hdtr; /* sendfile state */ int aio_lio_opcode; /* LIO opcode */ int aio_reqprio; /* Request priority -- ignored */ struct __aiocb_private _aiocb_private; @@ -130,6 +144,11 @@ */ int aio_mlock(struct aiocb *); +/* + * Asynchronous sendfile + */ +int aio_sendfile(struct aiocb *); + #ifdef __BSD_VISIBLE int aio_waitcomplete(struct aiocb **, struct timespec *); #endif Index: sys/sys/syscall.h =================================================================== --- sys/sys/syscall.h (revision 252610) +++ sys/sys/syscall.h (working copy) @@ -463,4 +463,5 @@ #define SYS_accept4 541 #define SYS_pipe2 542 #define SYS_aio_mlock 543 -#define SYS_MAXSYSCALL 544 +#define SYS_aio_sendfile 544 +#define SYS_MAXSYSCALL 545 Index: sys/sys/syscall.mk =================================================================== --- sys/sys/syscall.mk (revision 252610) +++ sys/sys/syscall.mk (working copy) @@ -411,4 +411,5 @@ chflagsat.o \ accept4.o \ pipe2.o \ - aio_mlock.o + aio_mlock.o \ + aio_sendfile.o Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h (revision 252610) +++ sys/sys/syscallsubr.h (working copy) @@ -190,7 +190,8 @@ int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits); int kern_sendfile(struct thread *td, struct sendfile_args *uap, - struct uio *hdr_uio, struct uio *trl_uio, int compat); + struct uio *hdr_uio, struct uio *trl_uio, off_t *ret_sbytes, + int compat); int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct mbuf *control, enum uio_seg segflg); int kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups); Index: sys/sys/sysproto.h =================================================================== --- sys/sys/sysproto.h (revision 252610) +++ sys/sys/sysproto.h (working copy) @@ -1815,6 +1815,9 @@ struct aio_mlock_args { char aiocbp_l_[PADL_(struct aiocb *)]; struct aiocb * aiocbp; char aiocbp_r_[PADR_(struct aiocb *)]; }; +struct aio_sendfile_args { + char aiocbp_l_[PADL_(struct aiocb *)]; struct aiocb * aiocbp; char aiocbp_r_[PADR_(struct aiocb *)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_sys_exit(struct thread *, struct sys_exit_args *); int sys_fork(struct thread *, struct fork_args *); @@ -2208,6 +2211,7 @@ int sys_accept4(struct thread *, struct accept4_args *); int sys_pipe2(struct thread *, struct pipe2_args *); int sys_aio_mlock(struct thread *, struct aio_mlock_args *); +int sys_aio_sendfile(struct thread *, struct aio_sendfile_args *); #ifdef COMPAT_43 @@ -2915,6 +2919,7 @@ #define SYS_AUE_accept4 AUE_ACCEPT #define SYS_AUE_pipe2 AUE_PIPE #define SYS_AUE_aio_mlock AUE_NULL +#define SYS_AUE_aio_sendfile AUE_NULL #undef PAD_ #undef PADL_