- Make aio_listio_max and aio_max changeable via sysctl.

- Set a lower priority for AIO-worker thread, because current could cause
  interactivity problems (eg. with qemu - thanks <xtraeme> for testing).
  Mark it as XXX for now - after priority model change, this should
  be reconsidered anyway.
- Do not copyout() with lock held in sys_aio_cancel().
- Fix a leak of the lock in aio_process().
- Check for any error of cv_wait_sig().
- Cache p->p_aio in aio_exit().

Thanks <ad> for catching the issues!
This commit is contained in:
rmind 2007-05-03 22:03:40 +00:00
parent f867968153
commit 29cb26a639
2 changed files with 92 additions and 45 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_aio.c,v 1.2 2007/05/01 01:01:36 rmind Exp $ */
/* $NetBSD: vfs_aio.c,v 1.3 2007/05/03 22:03:40 rmind Exp $ */
/*
* Copyright (c) 2007, Mindaugas Rasiukevicius <rmind at NetBSD org>
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_aio.c,v 1.2 2007/05/01 01:01:36 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_aio.c,v 1.3 2007/05/03 22:03:40 rmind Exp $");
#include <sys/param.h>
@ -57,9 +57,12 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_aio.c,v 1.2 2007/05/01 01:01:36 rmind Exp $");
#include <uvm/uvm_extern.h>
/*
* System-wide counter of AIO operations.
* System-wide limits and counter of AIO operations.
* XXXSMP: We should spin-lock it, or modify atomically.
*/
static unsigned long aio_listio_max = AIO_LISTIO_MAX;
static unsigned long aio_max = AIO_MAX;
static unsigned long aio_jobs_count = 0;
/* Prototypes */
@ -129,7 +132,7 @@ aio_init(struct proc *p)
p->p_nrlwps++;
lwp_lock(l);
l->l_stat = LSRUN;
l->l_usrpri = PRIBIO;
l->l_usrpri = PUSER - 1; /* XXX */
setrunqueue(l);
lwp_unlock(l);
mutex_exit(&p->p_smutex);
@ -143,28 +146,30 @@ aio_init(struct proc *p)
void
aio_exit(struct proc *p)
{
struct aioproc *aio;
struct aio_job *a_job;
if (p->p_aio == NULL)
return;
aio = p->p_aio;
KASSERT(p->p_aio->aio_worker == NULL);
/* Free AIO queue */
while (!TAILQ_EMPTY(&p->p_aio->jobs_queue)) {
a_job = TAILQ_FIRST(&p->p_aio->jobs_queue);
TAILQ_REMOVE(&p->p_aio->jobs_queue, a_job, list);
pool_put(&p->p_aio->jobs_pool, a_job);
while (!TAILQ_EMPTY(&aio->jobs_queue)) {
a_job = TAILQ_FIRST(&aio->jobs_queue);
TAILQ_REMOVE(&aio->jobs_queue, a_job, list);
pool_put(&aio->jobs_pool, a_job);
aio_jobs_count--; /* XXXSMP */
}
/* Destroy and free the entire AIO data structure */
cv_destroy(&p->p_aio->aio_worker_cv);
cv_destroy(&p->p_aio->done_cv);
mutex_destroy(&p->p_aio->aio_mtx);
pool_destroy(&p->p_aio->jobs_pool);
pool_destroy(&p->p_aio->lio_pool);
kmem_free(p->p_aio, sizeof(struct aioproc));
cv_destroy(&aio->aio_worker_cv);
cv_destroy(&aio->done_cv);
mutex_destroy(&aio->aio_mtx);
pool_destroy(&aio->jobs_pool);
pool_destroy(&aio->lio_pool);
kmem_free(aio, sizeof(struct aioproc));
p->p_aio = NULL;
}
@ -198,8 +203,7 @@ aio_worker(void *arg)
*/
mutex_enter(&aio->aio_mtx);
while ((a_job = TAILQ_FIRST(&aio->jobs_queue)) == NULL) {
if (cv_wait_sig(&aio->aio_worker_cv,
&aio->aio_mtx) == EINTR) {
if (cv_wait_sig(&aio->aio_worker_cv, &aio->aio_mtx)) {
/*
* Thread was interrupted by the
* signal - check for exit.
@ -283,6 +287,11 @@ aio_process(struct aio_job *a_job)
struct iovec aiov;
struct uio auio;
if (aiocbp->aio_nbytes > SSIZE_MAX) {
error = EINVAL;
goto done;
}
fp = fd_getfile(fdp, fd);
if (fp == NULL) {
error = EBADF;
@ -296,11 +305,6 @@ aio_process(struct aio_job *a_job)
auio.uio_resid = aiocbp->aio_nbytes;
auio.uio_vmspace = p->p_vmspace;
if (auio.uio_resid > SSIZE_MAX) {
error = EINVAL;
goto done;
}
FILE_USE(fp);
if (a_job->aio_op & AIO_READ) {
/*
@ -415,7 +419,7 @@ aio_enqueue_job(int op, void *aiocb_uptr, struct lio_req *lio)
int error;
/* Check for the limit */
if (aio_jobs_count + 1 > AIO_MAX) /* XXXSMP */
if (aio_jobs_count + 1 > aio_max) /* XXXSMP */
return EAGAIN;
/* Get the data structure from user-space */
@ -512,7 +516,7 @@ aio_enqueue_job(int op, void *aiocb_uptr, struct lio_req *lio)
mutex_enter(&aio->aio_mtx);
/* Fail, if the limit was reached */
if (aio->jobs_count >= AIO_LISTIO_MAX) {
if (aio->jobs_count >= aio_listio_max) {
mutex_exit(&aio->aio_mtx);
pool_put(&aio->jobs_pool, a_job);
return EAGAIN;
@ -551,7 +555,7 @@ sys_aio_cancel(struct lwp *l, void *v, register_t *retval)
struct aiocb *aiocbp_ptr;
struct lio_req *lio;
struct filedesc *fdp = p->p_fd;
unsigned int cn, error, fildes;
unsigned int cn, errcnt, fildes;
TAILQ_HEAD(, aio_job) tmp_jobs_list;
@ -585,16 +589,6 @@ sys_aio_cancel(struct lwp *l, void *v, register_t *retval)
} else if (a_job->aiocbp.aio_fildes != fildes)
continue;
/* Set the errno and copy structures back to the user-space */
a_job->aiocbp._errno = ECANCELED;
a_job->aiocbp._state = JOB_DONE;
error = copyout(&a_job->aiocbp, a_job->aiocb_uptr,
sizeof(struct aiocb));
if (error) {
mutex_exit(&aio->aio_mtx);
return error;
}
TAILQ_REMOVE(&aio->jobs_queue, a_job, list);
TAILQ_INSERT_TAIL(&tmp_jobs_list, a_job, list);
@ -626,9 +620,16 @@ sys_aio_cancel(struct lwp *l, void *v, register_t *retval)
mutex_exit(&aio->aio_mtx);
/* Free the jobs after the lock */
errcnt = 0;
while (!TAILQ_EMPTY(&tmp_jobs_list)) {
a_job = TAILQ_FIRST(&tmp_jobs_list);
TAILQ_REMOVE(&tmp_jobs_list, a_job, list);
/* Set the errno and copy structures back to the user-space */
a_job->aiocbp._errno = ECANCELED;
a_job->aiocbp._state = JOB_DONE;
if (copyout(&a_job->aiocbp, a_job->aiocb_uptr,
sizeof(struct aiocb)))
errcnt++;
/* Send a signal if any */
aio_sendsig(p, &a_job->aiocbp.aio_sigevent);
if (a_job->lio)
@ -636,6 +637,9 @@ sys_aio_cancel(struct lwp *l, void *v, register_t *retval)
pool_put(&aio->jobs_pool, a_job);
}
if (errcnt)
return EFAULT;
/* Set a correct return value */
if (*retval == 0)
*retval = AIO_ALLDONE;
@ -748,7 +752,7 @@ sys_aio_suspend(struct lwp *l, void *v, register_t *retval)
aio = p->p_aio;
nent = SCARG(uap, nent);
if (nent <= 0 || nent > AIO_LISTIO_MAX)
if (nent <= 0 || nent > aio_listio_max)
return EAGAIN;
if (SCARG(uap, timeout)) {
@ -857,9 +861,9 @@ sys_lio_listio(struct lwp *l, void *v, register_t *retval)
nent = SCARG(uap, nent);
/* Check for the limits, and invalid values */
if (nent < 1 || nent > AIO_LISTIO_MAX)
if (nent < 1 || nent > aio_listio_max)
return EINVAL;
if (aio_jobs_count + nent > AIO_MAX) /* XXXSMP */
if (aio_jobs_count + nent > aio_max) /* XXXSMP */
return EAGAIN;
if (mode != LIO_NOWAIT && mode != LIO_WAIT)
return EINVAL;
@ -945,6 +949,50 @@ err:
* SysCtl
*/
static int
sysctl_aio_listio_max(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int error, newsize;
node = *rnode;
node.sysctl_data = &newsize;
newsize = aio_listio_max;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
/* XXXSMP */
if (newsize < 1 || newsize > aio_max)
return EINVAL;
aio_listio_max = newsize;
return 0;
}
static int
sysctl_aio_max(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int error, newsize;
node = *rnode;
node.sysctl_data = &newsize;
newsize = aio_max;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
/* XXXSMP */
if (newsize < 1 || newsize < aio_listio_max)
return EINVAL;
aio_max = newsize;
return 0;
}
SYSCTL_SETUP(sysctl_aio_setup, "sysctl aio setup")
{
@ -954,7 +1002,7 @@ SYSCTL_SETUP(sysctl_aio_setup, "sysctl aio setup")
NULL, 0, NULL, 0,
CTL_KERN, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLFLAG_PERMANENT | CTLFLAG_IMMEDIATE,
CTLTYPE_INT, "posix_aio",
SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
"Asynchronous I/O option to which the "
@ -962,18 +1010,18 @@ SYSCTL_SETUP(sysctl_aio_setup, "sysctl aio setup")
NULL, _POSIX_ASYNCHRONOUS_IO, NULL, 0,
CTL_KERN, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
CTLTYPE_INT, "aio_listio_max",
SYSCTL_DESCR("Maximum number of asynchronous I/O "
"operations in a single list I/O call"),
NULL, AIO_LISTIO_MAX, NULL, 0,
sysctl_aio_listio_max, 0, &aio_listio_max, 0,
CTL_KERN, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
CTLTYPE_INT, "aio_max",
SYSCTL_DESCR("Maximum number of asynchronous I/O "
"operations"),
NULL, AIO_MAX, NULL, 0,
sysctl_aio_max, 0, &aio_max, 0,
CTL_KERN, CTL_CREATE, CTL_EOL);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: aio.h,v 1.1 2007/04/30 14:44:31 rmind Exp $ */
/* $NetBSD: aio.h,v 1.2 2007/05/03 22:03:50 rmind Exp $ */
/*
* Copyright (c) 2007, Mindaugas Rasiukevicius <rmind at NetBSD org>
@ -64,8 +64,7 @@ struct aiocb {
/* Internal kernel data */
#ifdef _KERNEL
/* Maximal number of allowed AIO operations */
/* XXX: These will be changeable via sysctl */
/* Default limits of allowed AIO operations */
#define AIO_LISTIO_MAX 512
#define AIO_MAX AIO_LISTIO_MAX * 16