svn commit: r185878 - in head/sys: compat/freebsd32 kern
modules/aio
James Gritton
jamie at gritton.org
Thu Dec 11 10:46:29 PST 2008
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 at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/svn-src-all
> To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
>
More information about the svn-src-all
mailing list