Date: Thu, 11 Dec 2008 11:46:21 -0700 From: James Gritton <jamie@gritton.org> To: John Baldwin <jhb@freebsd.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r185878 - in head/sys: compat/freebsd32 kern modules/aio Message-ID: <49415FFD.5070400@gritton.org> In-Reply-To: <200812102056.mBAKuJ97042379@svn.freebsd.org> References: <200812102056.mBAKuJ97042379@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
freebsd32_aio_waitcomplete() has a small error: @@ -2824,7 +2824,7 @@ freebsd32_aio_waitcomplete(struct thread *td, struct freebsd32_aio_waitcomplete_args *uap) { - struct timespec ts32; + struct timespec32 ts32; struct timespec ts, *tsp; int error; - Jamie John Baldwin wrote: > Author: jhb > Date: Wed Dec 10 20:56:19 2008 > New Revision: 185878 > URL: http://svn.freebsd.org/changeset/base/185878 > > Log: > - Add 32-bit compat system calls for VFS_AIO. The system calls live in the > aio code and are registered via the recently added SYSCALL32_*() helpers. > - Since the aio code likes to invoke fuword and suword a lot down in the > "bowels" of system calls, add a structure holding a set of operations for > things like storing errors, copying in the aiocb structure, storing > status, etc. The 32-bit system calls use a separate operations vector to > handle fuword32 vs fuword, etc. Also, the oldsigevent handling is now > done by having seperate operation vectors with different aiocb copyin > routines. > - Split out kern_foo() functions for the various AIO system calls so the > 32-bit front ends can manage things like copying in and converting > timespec structures, etc. > - For both the native and 32-bit aio_suspend() and lio_listio() calls, > just use copyin() to read the array of aiocb pointers instead of using > a for loop that iterated over fuword/fuword32. The error handling in > the old case was incomplete (lio_listio() just ignored any aiocb's that > it got an EFAULT trying to read rather than reporting an error), and > possibly slower. > > MFC after: 1 month > > Modified: > head/sys/compat/freebsd32/syscalls.master > head/sys/kern/vfs_aio.c > head/sys/modules/aio/Makefile > > Modified: head/sys/compat/freebsd32/syscalls.master > ============================================================================== > --- head/sys/compat/freebsd32/syscalls.master Wed Dec 10 20:55:44 2008 (r185877) > +++ head/sys/compat/freebsd32/syscalls.master Wed Dec 10 20:56:19 2008 (r185878) > @@ -454,9 +454,13 @@ > u_int nfds, int timeout); } > 253 AUE_ISSETUGID NOPROTO { int issetugid(void); } > 254 AUE_LCHOWN NOPROTO { int lchown(char *path, int uid, int gid); } > -255 AUE_NULL UNIMPL nosys > -256 AUE_NULL UNIMPL nosys > -257 AUE_NULL UNIMPL nosys > +255 AUE_NULL NOSTD { int freebsd32_aio_read( \ > + struct aiocb32 *aiocbp); } > +256 AUE_NULL NOSTD { int freebsd32_aio_write( \ > + struct aiocb32 *aiocbp); } > +257 AUE_NULL NOSTD { int freebsd32_lio_listio(int mode, \ > + struct aiocb32 * const *acb_list, \ > + int nent, struct sigevent *sig); } > 258 AUE_NULL UNIMPL nosys > 259 AUE_NULL UNIMPL nosys > 260 AUE_NULL UNIMPL nosys > @@ -535,13 +539,22 @@ > 312 AUE_SETRESGID NOPROTO { int setresgid(gid_t rgid, gid_t egid, \ > gid_t sgid); } > 313 AUE_NULL OBSOL signanosleep > -314 AUE_NULL UNIMPL aio_return > -315 AUE_NULL UNIMPL aio_suspend > -316 AUE_NULL UNIMPL aio_cancel > -317 AUE_NULL UNIMPL aio_error > -318 AUE_NULL UNIMPL aio_read > -319 AUE_NULL UNIMPL aio_write > -320 AUE_NULL UNIMPL lio_listio > +314 AUE_NULL NOSTD { int freebsd32_aio_return( \ > + struct aiocb32 *aiocbp); } > +315 AUE_NULL NOSTD { int freebsd32_aio_suspend( \ > + struct aiocb32 * const * aiocbp, int nent, \ > + const struct timespec32 *timeout); } > +316 AUE_NULL NOSTD { int freebsd32_aio_cancel(int fd, \ > + struct aiocb32 *aiocbp); } > +317 AUE_NULL NOSTD { int freebsd32_aio_error( \ > + struct aiocb32 *aiocbp); } > +318 AUE_NULL NOSTD { int freebsd32_oaio_read( \ > + struct oaiocb32 *aiocbp); } > +319 AUE_NULL NOSTD { int freebsd32_oaio_write( \ > + struct oaiocb32 *aiocbp); } > +320 AUE_NULL NOSTD { int freebsd32_olio_listio(int mode, \ > + struct oaiocb32 * const *acb_list, \ > + int nent, struct osigevent32 *sig); } > 321 AUE_NULL NOPROTO { int yield(void); } > 322 AUE_NULL OBSOL thr_sleep > 323 AUE_NULL OBSOL thr_wakeup > @@ -618,7 +631,9 @@ > 358 AUE_EXTATTR_DELETE_FILE NOPROTO { int extattr_delete_file( \ > const char *path, int attrnamespace, \ > const char *attrname); } > -359 AUE_NULL UNIMPL aio_waitcomplete > +359 AUE_NULL NOSTD { int freebsd32_aio_waitcomplete( \ > + struct aiocb32 **aiocbp, \ > + struct timespec32 *timeout); } > 360 AUE_GETRESUID NOPROTO { int getresuid(uid_t *ruid, uid_t *euid, \ > uid_t *suid); } > 361 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \ > @@ -766,7 +781,8 @@ > 462 AUE_NULL UNIMPL kmq_unlink > 463 AUE_NULL NOPROTO { int abort2(const char *why, int nargs, void **args); } > 464 AUE_NULL NOPROTO { int thr_set_name(long id, const char *name); } > -465 AUE_NULL UNIMPL aio_fsync > +465 AUE_NULL NOSTD { int freebsd32_aio_fsync(int op, \ > + struct aiocb32 *aiocbp); } > 466 AUE_RTPRIO NOPROTO { int rtprio_thread(int function, \ > lwpid_t lwpid, struct rtprio *rtp); } > 467 AUE_NULL UNIMPL nosys > > Modified: head/sys/kern/vfs_aio.c > ============================================================================== > --- head/sys/kern/vfs_aio.c Wed Dec 10 20:55:44 2008 (r185877) > +++ head/sys/kern/vfs_aio.c Wed Dec 10 20:56:19 2008 (r185878) > @@ -21,6 +21,8 @@ > #include <sys/cdefs.h> > __FBSDID("$FreeBSD$"); > > +#include "opt_compat.h" > + > #include <sys/param.h> > #include <sys/systm.h> > #include <sys/malloc.h> > @@ -121,6 +123,8 @@ static uint64_t jobseqno; > > FEATURE(aio, "Asynchronous I/O"); > > +static MALLOC_DEFINE(M_LIO, "lio", "listio aio control block list"); > + > static SYSCTL_NODE(_vfs, OID_AUTO, aio, CTLFLAG_RW, 0, "Async IO management"); > > static int max_aio_procs = MAX_AIO_PROCS; > @@ -308,6 +312,20 @@ struct kaioinfo { > #define KAIO_RUNDOWN 0x1 /* process is being run down */ > #define KAIO_WAKEUP 0x2 /* wakeup process when there is a significant event */ > > +/* > + * Operations used to interact with userland aio control blocks. > + * Different ABIs provide their own operations. > + */ > +struct aiocb_ops { > + int (*copyin)(struct aiocb *ujob, struct aiocb *kjob); > + long (*fetch_status)(struct aiocb *ujob); > + long (*fetch_error)(struct aiocb *ujob); > + int (*store_status)(struct aiocb *ujob, long status); > + int (*store_error)(struct aiocb *ujob, long error); > + int (*store_kernelinfo)(struct aiocb *ujob, long jobref); > + int (*store_aiocb)(struct aiocb **ujobp, struct aiocb *ujob); > +}; > + > static TAILQ_HEAD(,aiothreadlist) aio_freeproc; /* (c) Idle daemons */ > static struct sema aio_newproc_sem; > static struct mtx aio_job_mtx; > @@ -321,7 +339,7 @@ static int aio_free_entry(struct aiocbli > static void aio_process(struct aiocblist *aiocbe); > static int aio_newproc(int *); > int aio_aqueue(struct thread *td, struct aiocb *job, > - struct aioliojob *lio, int type, int osigev); > + struct aioliojob *lio, int type, struct aiocb_ops *ops); > static void aio_physwakeup(struct buf *bp); > static void aio_proc_rundown(void *arg, struct proc *p); > static void aio_proc_rundown_exec(void *arg, struct proc *p, struct image_params *imgp); > @@ -333,7 +351,6 @@ static int aio_unload(void); > static void aio_bio_done_notify(struct proc *userp, struct aiocblist *aiocbe, int type); > #define DONE_BUF 1 > #define DONE_QUEUE 2 > -static int do_lio_listio(struct thread *td, struct lio_listio_args *uap, int oldsigev); > static int aio_kick(struct proc *userp); > static void aio_kick_nowait(struct proc *userp); > static void aio_kick_helper(void *context, int pending); > @@ -1322,13 +1339,122 @@ aio_swake_cb(struct socket *so, struct s > SOCKBUF_UNLOCK(sb); > } > > +static int > +convert_old_sigevent(struct osigevent *osig, struct sigevent *nsig) > +{ > + > + /* > + * Only SIGEV_NONE, SIGEV_SIGNAL, and SIGEV_KEVENT are > + * supported by AIO with the old sigevent structure. > + */ > + nsig->sigev_notify = osig->sigev_notify; > + switch (nsig->sigev_notify) { > + case SIGEV_NONE: > + break; > + case SIGEV_SIGNAL: > + nsig->sigev_signo = osig->__sigev_u.__sigev_signo; > + break; > + case SIGEV_KEVENT: > + nsig->sigev_notify_kqueue = > + osig->__sigev_u.__sigev_notify_kqueue; > + nsig->sigev_value.sival_ptr = osig->sigev_value.sival_ptr; > + break; > + default: > + return (EINVAL); > + } > + return (0); > +} > + > +static int > +aiocb_copyin_old_sigevent(struct aiocb *ujob, struct aiocb *kjob) > +{ > + struct oaiocb *ojob; > + int error; > + > + bzero(kjob, sizeof(struct aiocb)); > + error = copyin(ujob, kjob, sizeof(struct oaiocb)); > + if (error) > + return (error); > + ojob = (struct oaiocb *)kjob; > + return (convert_old_sigevent(&ojob->aio_sigevent, &kjob->aio_sigevent)); > +} > + > +static int > +aiocb_copyin(struct aiocb *ujob, struct aiocb *kjob) > +{ > + > + return (copyin(ujob, kjob, sizeof(struct aiocb))); > +} > + > +static long > +aiocb_fetch_status(struct aiocb *ujob) > +{ > + > + return (fuword(&ujob->_aiocb_private.status)); > +} > + > +static long > +aiocb_fetch_error(struct aiocb *ujob) > +{ > + > + return (fuword(&ujob->_aiocb_private.error)); > +} > + > +static int > +aiocb_store_status(struct aiocb *ujob, long status) > +{ > + > + return (suword(&ujob->_aiocb_private.status, status)); > +} > + > +static int > +aiocb_store_error(struct aiocb *ujob, long error) > +{ > + > + return (suword(&ujob->_aiocb_private.error, error)); > +} > + > +static int > +aiocb_store_kernelinfo(struct aiocb *ujob, long jobref) > +{ > + > + return (suword(&ujob->_aiocb_private.kernelinfo, jobref)); > +} > + > +static int > +aiocb_store_aiocb(struct aiocb **ujobp, struct aiocb *ujob) > +{ > + > + return (suword(ujobp, (long)ujob)); > +} > + > +static struct aiocb_ops aiocb_ops = { > + .copyin = aiocb_copyin, > + .fetch_status = aiocb_fetch_status, > + .fetch_error = aiocb_fetch_error, > + .store_status = aiocb_store_status, > + .store_error = aiocb_store_error, > + .store_kernelinfo = aiocb_store_kernelinfo, > + .store_aiocb = aiocb_store_aiocb, > +}; > + > +static struct aiocb_ops aiocb_ops_osigevent = { > + .copyin = aiocb_copyin_old_sigevent, > + .fetch_status = aiocb_fetch_status, > + .fetch_error = aiocb_fetch_error, > + .store_status = aiocb_store_status, > + .store_error = aiocb_store_error, > + .store_kernelinfo = aiocb_store_kernelinfo, > + .store_aiocb = aiocb_store_aiocb, > +}; > + > /* > * Queue a new AIO request. Choosing either the threaded or direct physio VCHR > * technique is done in this code. > */ > int > aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, > - int type, int oldsigev) > + int type, struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > struct file *fp; > @@ -1347,13 +1473,13 @@ aio_aqueue(struct thread *td, struct aio > > ki = p->p_aioinfo; > > - suword(&job->_aiocb_private.status, -1); > - suword(&job->_aiocb_private.error, 0); > - suword(&job->_aiocb_private.kernelinfo, -1); > + ops->store_status(job, -1); > + ops->store_error(job, 0); > + ops->store_kernelinfo(job, -1); > > if (num_queue_count >= max_queue_count || > ki->kaio_count >= ki->kaio_qallowed_count) { > - suword(&job->_aiocb_private.error, EAGAIN); > + ops->store_error(job, EAGAIN); > return (EAGAIN); > } > > @@ -1362,16 +1488,9 @@ aio_aqueue(struct thread *td, struct aio > aiocbe->outputcharge = 0; > knlist_init(&aiocbe->klist, AIO_MTX(ki), NULL, NULL, NULL); > > - if (oldsigev) { > - bzero(&aiocbe->uaiocb, sizeof(struct aiocb)); > - error = copyin(job, &aiocbe->uaiocb, sizeof(struct oaiocb)); > - bcopy(&aiocbe->uaiocb.__spare__, &aiocbe->uaiocb.aio_sigevent, > - sizeof(struct osigevent)); > - } else { > - error = copyin(job, &aiocbe->uaiocb, sizeof(struct aiocb)); > - } > + error = ops->copyin(job, &aiocbe->uaiocb); > if (error) { > - suword(&job->_aiocb_private.error, error); > + ops->store_error(job, error); > uma_zfree(aiocb_zone, aiocbe); > return (error); > } > @@ -1380,11 +1499,11 @@ aio_aqueue(struct thread *td, struct aio > aiocbe->uaiocb.aio_sigevent.sigev_notify != SIGEV_SIGNAL && > aiocbe->uaiocb.aio_sigevent.sigev_notify != SIGEV_THREAD_ID && > aiocbe->uaiocb.aio_sigevent.sigev_notify != SIGEV_NONE) { > - suword(&job->_aiocb_private.error, EINVAL); > + ops->store_error(job, EINVAL); > uma_zfree(aiocb_zone, aiocbe); > return (EINVAL); > } > - > + > if ((aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL || > aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_THREAD_ID) && > !_SIG_VALID(aiocbe->uaiocb.aio_sigevent.sigev_signo)) { > @@ -1416,7 +1535,7 @@ aio_aqueue(struct thread *td, struct aio > } > if (error) { > uma_zfree(aiocb_zone, aiocbe); > - suword(&job->_aiocb_private.error, error); > + ops->store_error(job, error); > return (error); > } > > @@ -1436,7 +1555,7 @@ aio_aqueue(struct thread *td, struct aio > jid = jobrefid++; > aiocbe->seqno = jobseqno++; > mtx_unlock(&aio_job_mtx); > - error = suword(&job->_aiocb_private.kernelinfo, jid); > + error = ops->store_kernelinfo(job, jid); > if (error) { > error = EINVAL; > goto aqueue_fail; > @@ -1467,12 +1586,12 @@ aqueue_fail: > if (error) { > fdrop(fp, td); > uma_zfree(aiocb_zone, aiocbe); > - suword(&job->_aiocb_private.error, error); > + ops->store_error(job, error); > goto done; > } > no_kqueue: > > - suword(&job->_aiocb_private.error, EINPROGRESS); > + ops->store_error(job, EINPROGRESS); > aiocbe->uaiocb._aiocb_private.error = EINPROGRESS; > aiocbe->userproc = p; > aiocbe->cred = crhold(td->td_ucred); > @@ -1528,7 +1647,7 @@ no_kqueue: > #if 0 > if (error > 0) { > aiocbe->uaiocb._aiocb_private.error = error; > - suword(&job->_aiocb_private.error, error); > + ops->store_error(job, error); > goto done; > } > #endif > @@ -1643,19 +1762,17 @@ aio_kick_helper(void *context, int pendi > * Support the aio_return system call, as a side-effect, kernel resources are > * released. > */ > -int > -aio_return(struct thread *td, struct aio_return_args *uap) > +static int > +kern_aio_return(struct thread *td, struct aiocb *uaiocb, struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > struct aiocblist *cb; > - struct aiocb *uaiocb; > struct kaioinfo *ki; > int status, error; > > ki = p->p_aioinfo; > if (ki == NULL) > return (EINVAL); > - uaiocb = uap->aiocbp; > AIO_LOCK(ki); > TAILQ_FOREACH(cb, &ki->kaio_done, plist) { > if (cb->uuaiocb == uaiocb) > @@ -1675,8 +1792,8 @@ aio_return(struct thread *td, struct aio > } > aio_free_entry(cb); > AIO_UNLOCK(ki); > - suword(&uaiocb->_aiocb_private.error, error); > - suword(&uaiocb->_aiocb_private.status, status); > + ops->store_error(uaiocb, error); > + ops->store_status(uaiocb, status); > } else { > error = EINVAL; > AIO_UNLOCK(ki); > @@ -1684,37 +1801,32 @@ aio_return(struct thread *td, struct aio > return (error); > } > > +int > +aio_return(struct thread *td, struct aio_return_args *uap) > +{ > + > + return (kern_aio_return(td, uap->aiocbp, &aiocb_ops)); > +} > + > /* > * Allow a process to wakeup when any of the I/O requests are completed. > */ > -int > -aio_suspend(struct thread *td, struct aio_suspend_args *uap) > +static int > +kern_aio_suspend(struct thread *td, int njoblist, struct aiocb **ujoblist, > + struct timespec *ts) > { > struct proc *p = td->td_proc; > struct timeval atv; > - struct timespec ts; > - struct aiocb *const *cbptr, *cbp; > struct kaioinfo *ki; > struct aiocblist *cb, *cbfirst; > - struct aiocb **ujoblist; > - int njoblist; > - int error; > - int timo; > - int i; > - > - if (uap->nent < 0 || uap->nent > AIO_LISTIO_MAX) > - return (EINVAL); > + int error, i, timo; > > timo = 0; > - if (uap->timeout) { > - /* Get timespec struct. */ > - if ((error = copyin(uap->timeout, &ts, sizeof(ts))) != 0) > - return (error); > - > - if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) > + if (ts) { > + if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) > return (EINVAL); > > - TIMESPEC_TO_TIMEVAL(&atv, &ts); > + TIMESPEC_TO_TIMEVAL(&atv, ts); > if (itimerfix(&atv)) > return (EINVAL); > timo = tvtohz(&atv); > @@ -1724,22 +1836,8 @@ aio_suspend(struct thread *td, struct ai > if (ki == NULL) > return (EAGAIN); > > - njoblist = 0; > - ujoblist = uma_zalloc(aiol_zone, M_WAITOK); > - cbptr = uap->aiocbp; > - > - for (i = 0; i < uap->nent; i++) { > - cbp = (struct aiocb *)(intptr_t)fuword(&cbptr[i]); > - if (cbp == 0) > - continue; > - ujoblist[njoblist] = cbp; > - njoblist++; > - } > - > - if (njoblist == 0) { > - uma_zfree(aiol_zone, ujoblist); > + if (njoblist == 0) > return (0); > - } > > AIO_LOCK(ki); > for (;;) { > @@ -1769,6 +1867,31 @@ aio_suspend(struct thread *td, struct ai > } > RETURN: > AIO_UNLOCK(ki); > + return (error); > +} > + > +int > +aio_suspend(struct thread *td, struct aio_suspend_args *uap) > +{ > + struct timespec ts, *tsp; > + struct aiocb **ujoblist; > + int error; > + > + if (uap->nent < 0 || uap->nent > AIO_LISTIO_MAX) > + return (EINVAL); > + > + if (uap->timeout) { > + /* Get timespec struct. */ > + if ((error = copyin(uap->timeout, &ts, sizeof(ts))) != 0) > + return (error); > + tsp = &ts; > + } else > + tsp = NULL; > + > + ujoblist = uma_zalloc(aiol_zone, M_WAITOK); > + error = copyin(uap->aiocbp, ujoblist, uap->nent * sizeof(ujoblist[0])); > + if (error == 0) > + error = kern_aio_suspend(td, uap->nent, ujoblist, tsp); > uma_zfree(aiol_zone, ujoblist); > return (error); > } > @@ -1876,8 +1999,8 @@ done: > * only. For a user mode async implementation, it would be best to do it in > * a userland subroutine. > */ > -int > -aio_error(struct thread *td, struct aio_error_args *uap) > +static int > +kern_aio_error(struct thread *td, struct aiocb *aiocbp, struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > struct aiocblist *cb; > @@ -1892,7 +2015,7 @@ aio_error(struct thread *td, struct aio_ > > AIO_LOCK(ki); > TAILQ_FOREACH(cb, &ki->kaio_all, allist) { > - if (cb->uuaiocb == uap->aiocbp) { > + if (cb->uuaiocb == aiocbp) { > if (cb->jobstate == JOBST_JOBFINISHED) > td->td_retval[0] = > cb->uaiocb._aiocb_private.error; > @@ -1907,9 +2030,9 @@ aio_error(struct thread *td, struct aio_ > /* > * Hack for failure of aio_aqueue. > */ > - status = fuword(&uap->aiocbp->_aiocb_private.status); > + status = ops->fetch_status(aiocbp); > if (status == -1) { > - td->td_retval[0] = fuword(&uap->aiocbp->_aiocb_private.error); > + td->td_retval[0] = ops->fetch_error(aiocbp); > return (0); > } > > @@ -1917,19 +2040,27 @@ aio_error(struct thread *td, struct aio_ > return (0); > } > > +int > +aio_error(struct thread *td, struct aio_error_args *uap) > +{ > + > + return (kern_aio_error(td, uap->aiocbp, &aiocb_ops)); > +} > + > /* syscall - asynchronous read from a file (REALTIME) */ > int > oaio_read(struct thread *td, struct oaio_read_args *uap) > { > > - return aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_READ, 1); > + return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_READ, > + &aiocb_ops_osigevent)); > } > > int > aio_read(struct thread *td, struct aio_read_args *uap) > { > > - return aio_aqueue(td, uap->aiocbp, NULL, LIO_READ, 0); > + return (aio_aqueue(td, uap->aiocbp, NULL, LIO_READ, &aiocb_ops)); > } > > /* syscall - asynchronous write to a file (REALTIME) */ > @@ -1937,47 +2068,34 @@ int > oaio_write(struct thread *td, struct oaio_write_args *uap) > { > > - return aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_WRITE, 1); > + return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_WRITE, > + &aiocb_ops_osigevent)); > } > > int > aio_write(struct thread *td, struct aio_write_args *uap) > { > > - return aio_aqueue(td, uap->aiocbp, NULL, LIO_WRITE, 0); > -} > - > -/* syscall - list directed I/O (REALTIME) */ > -int > -olio_listio(struct thread *td, struct olio_listio_args *uap) > -{ > - return do_lio_listio(td, (struct lio_listio_args *)uap, 1); > -} > - > -/* syscall - list directed I/O (REALTIME) */ > -int > -lio_listio(struct thread *td, struct lio_listio_args *uap) > -{ > - return do_lio_listio(td, uap, 0); > + return (aio_aqueue(td, uap->aiocbp, NULL, LIO_WRITE, &aiocb_ops)); > } > > static int > -do_lio_listio(struct thread *td, struct lio_listio_args *uap, int oldsigev) > +kern_lio_listio(struct thread *td, int mode, struct aiocb * const *uacb_list, > + struct aiocb **acb_list, int nent, struct sigevent *sig, > + struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > - struct aiocb *iocb, * const *cbptr; > + struct aiocb *iocb; > struct kaioinfo *ki; > struct aioliojob *lj; > struct kevent kev; > - int nent; > int error; > int nerror; > int i; > > - if ((uap->mode != LIO_NOWAIT) && (uap->mode != LIO_WAIT)) > + if ((mode != LIO_NOWAIT) && (mode != LIO_WAIT)) > return (EINVAL); > > - nent = uap->nent; > if (nent < 0 || nent > AIO_LISTIO_MAX) > return (EINVAL); > > @@ -1996,21 +2114,13 @@ do_lio_listio(struct thread *td, struct > /* > * Setup signal. > */ > - if (uap->sig && (uap->mode == LIO_NOWAIT)) { > - bzero(&lj->lioj_signal, sizeof(&lj->lioj_signal)); > - error = copyin(uap->sig, &lj->lioj_signal, > - oldsigev ? sizeof(struct osigevent) : > - sizeof(struct sigevent)); > - if (error) { > - uma_zfree(aiolio_zone, lj); > - return (error); > - } > - > + if (sig && (mode == LIO_NOWAIT)) { > + bcopy(sig, &lj->lioj_signal, sizeof(lj->lioj_signal)); > if (lj->lioj_signal.sigev_notify == SIGEV_KEVENT) { > /* Assume only new style KEVENT */ > kev.filter = EVFILT_LIO; > kev.flags = EV_ADD | EV_ENABLE | EV_FLAG1; > - kev.ident = (uintptr_t)uap->acb_list; /* something unique */ > + kev.ident = (uintptr_t)uacb_list; /* something unique */ > kev.data = (intptr_t)lj; > /* pass user defined sigval data */ > kev.udata = lj->lioj_signal.sigev_value.sival_ptr; > @@ -2050,11 +2160,10 @@ do_lio_listio(struct thread *td, struct > * Get pointers to the list of I/O requests. > */ > nerror = 0; > - cbptr = uap->acb_list; > - for (i = 0; i < uap->nent; i++) { > - iocb = (struct aiocb *)(intptr_t)fuword(&cbptr[i]); > - if (((intptr_t)iocb != -1) && ((intptr_t)iocb != 0)) { > - error = aio_aqueue(td, iocb, lj, LIO_NOP, oldsigev); > + for (i = 0; i < nent; i++) { > + iocb = acb_list[i]; > + if (iocb != NULL) { > + error = aio_aqueue(td, iocb, lj, LIO_NOP, ops); > if (error != 0) > nerror++; > } > @@ -2062,7 +2171,7 @@ do_lio_listio(struct thread *td, struct > > error = 0; > AIO_LOCK(ki); > - if (uap->mode == LIO_WAIT) { > + if (mode == LIO_WAIT) { > while (lj->lioj_count - 1 != lj->lioj_finished_count) { > ki->kaio_flags |= KAIO_WAKEUP; > error = msleep(&p->p_aioinfo, AIO_MTX(ki), > @@ -2105,6 +2214,75 @@ do_lio_listio(struct thread *td, struct > return (error); > } > > +/* syscall - list directed I/O (REALTIME) */ > +int > +olio_listio(struct thread *td, struct olio_listio_args *uap) > +{ > + struct aiocb **acb_list; > + struct sigevent *sigp, sig; > + struct osigevent osig; > + int error, nent; > + > + if ((uap->mode != LIO_NOWAIT) && (uap->mode != LIO_WAIT)) > + return (EINVAL); > + > + nent = uap->nent; > + if (nent < 0 || nent > AIO_LISTIO_MAX) > + return (EINVAL); > + > + if (uap->sig && (uap->mode == LIO_NOWAIT)) { > + error = copyin(uap->sig, &osig, sizeof(osig)); > + if (error) > + return (error); > + error = convert_old_sigevent(&osig, &sig); > + if (error) > + return (error); > + sigp = &sig; > + } else > + sigp = NULL; > + > + acb_list = malloc(sizeof(struct aiocb *) * nent, M_LIO, M_WAITOK); > + error = copyin(uap->acb_list, acb_list, nent * sizeof(acb_list[0])); > + if (error == 0) > + error = kern_lio_listio(td, uap->mode, > + (struct aiocb * const *)uap->acb_list, acb_list, nent, sigp, > + &aiocb_ops_osigevent); > + free(acb_list, M_LIO); > + return (error); > +} > + > +/* syscall - list directed I/O (REALTIME) */ > +int > +lio_listio(struct thread *td, struct lio_listio_args *uap) > +{ > + struct aiocb **acb_list; > + struct sigevent *sigp, sig; > + int error, nent; > + > + if ((uap->mode != LIO_NOWAIT) && (uap->mode != LIO_WAIT)) > + return (EINVAL); > + > + nent = uap->nent; > + if (nent < 0 || nent > AIO_LISTIO_MAX) > + return (EINVAL); > + > + if (uap->sig && (uap->mode == LIO_NOWAIT)) { > + error = copyin(uap->sig, &sig, sizeof(sig)); > + if (error) > + return (error); > + sigp = &sig; > + } else > + sigp = NULL; > + > + acb_list = malloc(sizeof(struct aiocb *) * nent, M_LIO, M_WAITOK); > + error = copyin(uap->acb_list, acb_list, nent * sizeof(acb_list[0])); > + if (error == 0) > + error = kern_lio_listio(td, uap->mode, uap->acb_list, acb_list, > + nent, sigp, &aiocb_ops); > + free(acb_list, M_LIO); > + return (error); > +} > + > /* > * Called from interrupt thread for physio, we should return as fast > * as possible, so we schedule a biohelper task. > @@ -2156,30 +2334,25 @@ biohelper(void *context, int pending) > } > > /* syscall - wait for the next completion of an aio request */ > -int > -aio_waitcomplete(struct thread *td, struct aio_waitcomplete_args *uap) > +static int > +kern_aio_waitcomplete(struct thread *td, struct aiocb **aiocbp, > + struct timespec *ts, struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > struct timeval atv; > - struct timespec ts; > struct kaioinfo *ki; > struct aiocblist *cb; > struct aiocb *uuaiocb; > int error, status, timo; > > - suword(uap->aiocbp, (long)NULL); > + ops->store_aiocb(aiocbp, NULL); > > timo = 0; > - if (uap->timeout) { > - /* Get timespec struct. */ > - error = copyin(uap->timeout, &ts, sizeof(ts)); > - if (error) > - return (error); > - > - if ((ts.tv_nsec < 0) || (ts.tv_nsec >= 1000000000)) > + if (ts) { > + if ((ts->tv_nsec < 0) || (ts->tv_nsec >= 1000000000)) > return (EINVAL); > > - TIMESPEC_TO_TIMEVAL(&atv, &ts); > + TIMESPEC_TO_TIMEVAL(&atv, ts); > if (itimerfix(&atv)) > return (EINVAL); > timo = tvtohz(&atv); > @@ -2217,9 +2390,9 @@ aio_waitcomplete(struct thread *td, stru > } > aio_free_entry(cb); > AIO_UNLOCK(ki); > - suword(uap->aiocbp, (long)uuaiocb); > - suword(&uuaiocb->_aiocb_private.error, error); > - suword(&uuaiocb->_aiocb_private.status, status); > + ops->store_aiocb(aiocbp, uuaiocb); > + ops->store_error(uuaiocb, error); > + ops->store_status(uuaiocb, status); > } else > AIO_UNLOCK(ki); > > @@ -2227,17 +2400,43 @@ aio_waitcomplete(struct thread *td, stru > } > > int > -aio_fsync(struct thread *td, struct aio_fsync_args *uap) > +aio_waitcomplete(struct thread *td, struct aio_waitcomplete_args *uap) > +{ > + struct timespec ts, *tsp; > + int error; > + > + if (uap->timeout) { > + /* Get timespec struct. */ > + error = copyin(uap->timeout, &ts, sizeof(ts)); > + if (error) > + return (error); > + tsp = &ts; > + } else > + tsp = NULL; > + > + return (kern_aio_waitcomplete(td, uap->aiocbp, tsp, &aiocb_ops)); > +} > + > +static int > +kern_aio_fsync(struct thread *td, int op, struct aiocb *aiocbp, > + struct aiocb_ops *ops) > { > struct proc *p = td->td_proc; > struct kaioinfo *ki; > > - if (uap->op != O_SYNC) /* XXX lack of O_DSYNC */ > + if (op != O_SYNC) /* XXX lack of O_DSYNC */ > return (EINVAL); > ki = p->p_aioinfo; > if (ki == NULL) > aio_init_aioinfo(p); > - return aio_aqueue(td, uap->aiocbp, NULL, LIO_SYNC, 0); > + return (aio_aqueue(td, aiocbp, NULL, LIO_SYNC, ops)); > +} > + > +int > +aio_fsync(struct thread *td, struct aio_fsync_args *uap) > +{ > + > + return (kern_aio_fsync(td, uap->op, uap->aiocbp, &aiocb_ops)); > } > > /* kqueue attach function */ > @@ -2325,3 +2524,433 @@ filt_lio(struct knote *kn, long hint) > > return (lj->lioj_flags & LIOJ_KEVENT_POSTED); > } > + > +#ifdef COMPAT_IA32 > +#include <sys/mount.h> > +#include <sys/socket.h> > +#include <compat/freebsd32/freebsd32.h> > +#include <compat/freebsd32/freebsd32_proto.h> > +#include <compat/freebsd32/freebsd32_signal.h> > +#include <compat/freebsd32/freebsd32_syscall.h> > +#include <compat/freebsd32/freebsd32_util.h> > + > +struct __aiocb_private32 { > + int32_t status; > + int32_t error; > + uint32_t kernelinfo; > +}; > + > +typedef struct oaiocb32 { > + int aio_fildes; /* File descriptor */ > + uint64_t aio_offset __packed; /* File offset for I/O */ > + uint32_t aio_buf; /* I/O buffer in process space */ > + uint32_t aio_nbytes; /* Number of bytes for I/O */ > + struct osigevent32 aio_sigevent; /* Signal to deliver */ > + int aio_lio_opcode; /* LIO opcode */ > + int aio_reqprio; /* Request priority -- ignored */ > + struct __aiocb_private32 _aiocb_private; > +} oaiocb32_t; > + > +typedef struct aiocb32 { > + int32_t aio_fildes; /* File descriptor */ > + uint64_t aio_offset __packed; /* File offset for I/O */ > + uint32_t aio_buf; /* I/O buffer in process space */ > + uint32_t aio_nbytes; /* Number of bytes for I/O */ > + int __spare__[2]; > + uint32_t __spare2__; > + int aio_lio_opcode; /* LIO opcode */ > + int aio_reqprio; /* Request priority -- ignored */ > + struct __aiocb_private32 _aiocb_private; > + struct sigevent32 aio_sigevent; /* Signal to deliver */ > +} aiocb32_t; > + > +static int > +convert_old_sigevent32(struct osigevent32 *osig, struct sigevent *nsig) > +{ > + > + /* > + * Only SIGEV_NONE, SIGEV_SIGNAL, and SIGEV_KEVENT are > + * supported by AIO with the old sigevent structure. > + */ > + CP(*osig, *nsig, sigev_notify); > + switch (nsig->sigev_notify) { > + case SIGEV_NONE: > + break; > + case SIGEV_SIGNAL: > + nsig->sigev_signo = osig->__sigev_u.__sigev_signo; > + break; > + case SIGEV_KEVENT: > + nsig->sigev_notify_kqueue = > + osig->__sigev_u.__sigev_notify_kqueue; > + PTRIN_CP(*osig, *nsig, sigev_value.sival_ptr); > + break; > + default: > + return (EINVAL); > + } > + return (0); > +} > + > +static int > +aiocb32_copyin_old_sigevent(struct aiocb *ujob, struct aiocb *kjob) > +{ > + struct oaiocb32 job32; > + int error; > + > + bzero(kjob, sizeof(struct aiocb)); > + error = copyin(ujob, &job32, sizeof(job32)); > + if (error) > + return (error); > + > + CP(job32, *kjob, aio_fildes); > + CP(job32, *kjob, aio_offset); > + PTRIN_CP(job32, *kjob, aio_buf); > + CP(job32, *kjob, aio_nbytes); > + CP(job32, *kjob, aio_lio_opcode); > + CP(job32, *kjob, aio_reqprio); > + CP(job32, *kjob, _aiocb_private.status); > + CP(job32, *kjob, _aiocb_private.error); > + PTRIN_CP(job32, *kjob, _aiocb_private.kernelinfo); > + return (convert_old_sigevent32(&job32.aio_sigevent, > + &kjob->aio_sigevent)); > +} > + > +static int > +convert_sigevent32(struct sigevent32 *sig32, struct sigevent *sig) > +{ > + > + CP(*sig32, *sig, sigev_notify); > + switch (sig->sigev_notify) { > + case SIGEV_NONE: > + break; > + case SIGEV_THREAD_ID: > + CP(*sig32, *sig, sigev_notify_thread_id); > + /* FALLTHROUGH */ > + case SIGEV_SIGNAL: > + CP(*sig32, *sig, sigev_signo); > + break; > + case SIGEV_KEVENT: > + CP(*sig32, *sig, sigev_notify_kqueue); > + PTRIN_CP(*sig32, *sig, sigev_value.sival_ptr); > + break; > + default: > + return (EINVAL); > + } > + return (0); > +} > + > +static int > +aiocb32_copyin(struct aiocb *ujob, struct aiocb *kjob) > +{ > + struct aiocb32 job32; > + int error; > + > + error = copyin(ujob, &job32, sizeof(job32)); > + if (error) > + return (error); > + CP(job32, *kjob, aio_fildes); > + CP(job32, *kjob, aio_offset); > + PTRIN_CP(job32, *kjob, aio_buf); > + CP(job32, *kjob, aio_nbytes); > + CP(job32, *kjob, aio_lio_opcode); > + CP(job32, *kjob, aio_reqprio); > + CP(job32, *kjob, _aiocb_private.status); > + CP(job32, *kjob, _aiocb_private.error); > + PTRIN_CP(job32, *kjob, _aiocb_private.kernelinfo); > + return (convert_sigevent32(&job32.aio_sigevent, &kjob->aio_sigevent)); > +} > + > +static long > +aiocb32_fetch_status(struct aiocb *ujob) > +{ > + struct aiocb32 *ujob32; > + > + ujob32 = (struct aiocb32 *)ujob; > + return (fuword32(&ujob32->_aiocb_private.status)); > +} > + > +static long > +aiocb32_fetch_error(struct aiocb *ujob) > +{ > + struct aiocb32 *ujob32; > + > + ujob32 = (struct aiocb32 *)ujob; > + return (fuword32(&ujob32->_aiocb_private.error)); > +} > + > +static int > +aiocb32_store_status(struct aiocb *ujob, long status) > +{ > + struct aiocb32 *ujob32; > + > + ujob32 = (struct aiocb32 *)ujob; > + return (suword32(&ujob32->_aiocb_private.status, status)); > +} > + > +static int > +aiocb32_store_error(struct aiocb *ujob, long error) > +{ > + struct aiocb32 *ujob32; > + > + ujob32 = (struct aiocb32 *)ujob; > > *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** > _______________________________________________ > svn-src-all@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/svn-src-all > To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?49415FFD.5070400>