--- vfs_aio.c.0 Sat Sep 1 13:33:37 2001 +++ vfs_aio.c Sat Sep 8 23:03:58 2001 @@ -97,7 +97,12 @@ static int max_aio_procs = MAX_AIO_PROCS; static int num_aio_procs = 0; static int target_aio_procs = TARGET_AIO_PROCS; +/* VFS_AIO_DISABLE_AT_STARTUP is kernel compiling option */ +#ifdef VFS_AIO_DISABLE_AT_STARTUP +static int max_queue_count = 0; +#else static int max_queue_count = MAX_AIO_QUEUE; +#endif static int num_queue_count = 0; static int num_buf_aio = 0; static int num_aio_resv_start = 0; @@ -108,6 +113,16 @@ static int max_aio_queue_per_proc = MAX_AIO_QUEUE_PER_PROC; static int max_buf_aio = MAX_BUF_AIO; +/* + * aio_group sets group which is allowed to use AIO. + * Two special values: + * -1 - don't check group, allow for all + * -2 - no group is allowed + * Root's process are allowed always to use AIO in this checking. + * But they may fail if any limit above is set to 0. + */ +static long aio_group = 0; /* allow only for group wheel by default */ + SYSCTL_NODE(_vfs, OID_AUTO, aio, CTLFLAG_RW, 0, "AIO mgmt"); SYSCTL_INT(_vfs_aio, OID_AUTO, max_aio_per_proc, @@ -143,6 +158,12 @@ SYSCTL_INT(_vfs_aio, OID_AUTO, aiod_timeout, CTLFLAG_RW, &aiod_timeout, 0, ""); +SYSCTL_LONG(_vfs_aio, OID_AUTO, aio_group, + CTLFLAG_RW, &aio_group, 0, ""); + +SYSCTL_LONG(_vfs_aio, OID_AUTO, jobrefid, + CTLFLAG_RD, &jobrefid, 0, ""); + /* * AIO process info */ @@ -1453,19 +1465,55 @@ } /* + * Check permissions, global and process, to use AIO + * Called from aio_aqueue() and lio_listio() + */ +static int +aio_allowed(struct proc *p) +{ + /* Hard bounce if aio is disabled in sysctl. */ + if (max_queue_count <= 0 || max_aio_procs <= 0 || + max_aio_per_proc <= 0) + return EPROCLIM; + if (num_queue_count >= max_queue_count) + return EAGAIN; + + /* Check permissions. Allow only root or specified group member. */ + /* XXX lock/unlock process? (for FreeBSD5) */ + if (suser_xxx(0, p, PRISON_ROOT) && aio_group != -1) { + int ig; + if (aio_group == -2) + return EPERM; + for (ig = 0; ig < p->p_ucred->cr_ngroups; ig++) { + if (p->p_ucred->cr_groups[ig] == (gid_t)aio_group) + return 0; + } + return EPERM; + } + return 0; +} + +/* * This routine queues an AIO request, checking for quotas. */ static int aio_aqueue(struct proc *p, struct aiocb *job, int type) { struct kaioinfo *ki; + int error; + + /* + * Forward this global check before aio_init_aioinfo(). + * Don't waste resources if it is not allowed. + * max_queue_count is sysctl vfs.aio.max_aio_queue. + */ + error = aio_allowed(p); + if (error) + return error; if (p->p_aioinfo == NULL) aio_init_aioinfo(p); - if (num_queue_count >= max_queue_count) - return EAGAIN; - ki = p->p_aioinfo; if (ki->kaio_queue_count >= ki->kaio_qallowed_count) return EAGAIN; @@ -1921,6 +1978,11 @@ if (nent > AIO_LISTIO_MAX) return EINVAL; + /* Check permissions. */ + error = aio_allowed(p); + if (error) + return error; + if (p->p_aioinfo == NULL) aio_init_aioinfo(p);