Date: Wed, 10 Dec 2008 20:56:19 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r185878 - in head/sys: compat/freebsd32 kern modules/aio Message-ID: <200812102056.mBAKuJ97042379@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812102056.mBAKuJ97042379>