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-head mailing list