Add new system call - aio_mlock(). The name speaks for itself. It allows
to perform the mlock(2) operation, which can consume a lot of time, under control of aio(4). Reviewed by: kib, jilles Sponsored by: Nginx, Inc.
This commit is contained in:
parent
bf96f17d6f
commit
9a02f3097d
@ -85,6 +85,7 @@ MAN+= abort2.2 \
|
||||
adjtime.2 \
|
||||
aio_cancel.2 \
|
||||
aio_error.2 \
|
||||
aio_mlock.2 \
|
||||
aio_read.2 \
|
||||
aio_return.2 \
|
||||
aio_suspend.2 \
|
||||
|
@ -379,6 +379,7 @@ FBSD_1.2 {
|
||||
|
||||
FBSD_1.3 {
|
||||
accept4;
|
||||
aio_mlock;
|
||||
bindat;
|
||||
cap_fcntls_get;
|
||||
cap_fcntls_limit;
|
||||
|
133
lib/libc/sys/aio_mlock.2
Normal file
133
lib/libc/sys/aio_mlock.2
Normal file
@ -0,0 +1,133 @@
|
||||
.\" Copyright (c) 2013 Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 3, 2013
|
||||
.Dt AIO_MLOCK 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm aio_mlock
|
||||
.Nd asynchronous
|
||||
.Xr mlock 2
|
||||
operation
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In aio.h
|
||||
.Ft int
|
||||
.Fn aio_mlock "struct aiocb *iocb"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn aio_mlock
|
||||
system call allows the calling process to lock into memory the
|
||||
physical pages associated with the virtual address range starting at
|
||||
.Fa iocb->aio_buf
|
||||
for
|
||||
.Fa iocb->aio_nbytes
|
||||
bytes.
|
||||
The call returns immediately after the locking request has
|
||||
been enqueued; the operation may or may not have completed at the time
|
||||
the call returns.
|
||||
.Pp
|
||||
The
|
||||
.Fa iocb
|
||||
pointer may be subsequently used as an argument to
|
||||
.Fn aio_return
|
||||
and
|
||||
.Fn aio_error
|
||||
in order to determine return or error status for the enqueued operation
|
||||
while it is in progress.
|
||||
.Pp
|
||||
If the request could not be enqueued (generally due to
|
||||
.Xr aio 4
|
||||
limits),
|
||||
then the call returns without having enqueued the request.
|
||||
.Sh RESTRICTIONS
|
||||
The Asynchronous I/O Control Block structure pointed to by
|
||||
.Fa iocb
|
||||
and the buffer that the
|
||||
.Fa iocb->aio_buf
|
||||
member of that structure references must remain valid until the
|
||||
operation has completed.
|
||||
For this reason, use of auto (stack) variables
|
||||
for these objects is discouraged.
|
||||
.Pp
|
||||
The asynchronous I/O control buffer
|
||||
.Fa iocb
|
||||
should be zeroed before the
|
||||
.Fn aio_mlock
|
||||
call to avoid passing bogus context information to the kernel.
|
||||
.Pp
|
||||
Modifications of the Asynchronous I/O Control Block structure or the
|
||||
buffer contents after the request has been enqueued, but before the
|
||||
request has completed, are not allowed.
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std aio_mlock
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn aio_read
|
||||
system call will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EAGAIN
|
||||
The request was not queued because of system resource limitations.
|
||||
.It Bq Er ENOSYS
|
||||
The
|
||||
.Fn aio_mlock
|
||||
system call is not supported.
|
||||
.El
|
||||
.Pp
|
||||
If the request is successfully enqueued, but subsequently cancelled
|
||||
or an error occurs, the value returned by the
|
||||
.Fn aio_return
|
||||
system call is per the
|
||||
.Xr mlock 2
|
||||
system call, and the value returned by the
|
||||
.Fn aio_error
|
||||
system call is one of the error returns from the
|
||||
.Xr mlock 2
|
||||
system call, or
|
||||
.Er ECANCELED
|
||||
if the request was explicitly cancelled via a call to
|
||||
.Fn aio_cancel .
|
||||
.Sh SEE ALSO
|
||||
.Xr aio_cancel 2 ,
|
||||
.Xr aio_error 2 ,
|
||||
.Xr aio_return 2 ,
|
||||
.Xr aio 4 ,
|
||||
.Xr mlock 2
|
||||
.Sh PORTABILITY
|
||||
The
|
||||
.Fn aio_mlock
|
||||
system call is a
|
||||
.Fx
|
||||
extension, and should not be used in portable code.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn aio_mlock
|
||||
system call first appeared in
|
||||
.Fx 10.0 .
|
||||
.Sh AUTHORS
|
||||
The system call was introduced by
|
||||
.An Gleb Smirnoff Aq glebius@FreeBSD.org .
|
@ -1044,3 +1044,5 @@
|
||||
__socklen_t * __restrict anamelen, \
|
||||
int flags); }
|
||||
542 AUE_PIPE NOPROTO { int pipe2(int *fildes, int flags); }
|
||||
543 AUE_NULL NOSTD { int freebsd32_aio_mlock( \
|
||||
struct aiocb32 *aiocbp); }
|
||||
|
@ -977,5 +977,6 @@
|
||||
__socklen_t * __restrict anamelen, \
|
||||
int flags); }
|
||||
542 AUE_PIPE STD { int pipe2(int *fildes, int flags); }
|
||||
543 AUE_NULL NOSTD { int aio_mlock(struct aiocb *aiocbp); }
|
||||
; Please copy any additions and changes to the following compatability tables:
|
||||
; sys/compat/freebsd32/syscalls.master
|
||||
|
@ -340,6 +340,7 @@ static int aio_onceonly(void);
|
||||
static int aio_free_entry(struct aiocblist *aiocbe);
|
||||
static void aio_process_rw(struct aiocblist *aiocbe);
|
||||
static void aio_process_sync(struct aiocblist *aiocbe);
|
||||
static void aio_process_mlock(struct aiocblist *aiocbe);
|
||||
static int aio_newproc(int *);
|
||||
int aio_aqueue(struct thread *td, struct aiocb *job,
|
||||
struct aioliojob *lio, int type, struct aiocb_ops *ops);
|
||||
@ -426,6 +427,7 @@ static struct syscall_helper_data aio_syscalls[] = {
|
||||
SYSCALL_INIT_HELPER(aio_cancel),
|
||||
SYSCALL_INIT_HELPER(aio_error),
|
||||
SYSCALL_INIT_HELPER(aio_fsync),
|
||||
SYSCALL_INIT_HELPER(aio_mlock),
|
||||
SYSCALL_INIT_HELPER(aio_read),
|
||||
SYSCALL_INIT_HELPER(aio_return),
|
||||
SYSCALL_INIT_HELPER(aio_suspend),
|
||||
@ -453,6 +455,7 @@ static struct syscall_helper_data aio32_syscalls[] = {
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_cancel),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_error),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_fsync),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_mlock),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_read),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_write),
|
||||
SYSCALL32_INIT_HELPER(freebsd32_aio_waitcomplete),
|
||||
@ -702,7 +705,8 @@ aio_free_entry(struct aiocblist *aiocbe)
|
||||
* at open time, but this is already true of file descriptors in
|
||||
* a multithreaded process.
|
||||
*/
|
||||
fdrop(aiocbe->fd_file, curthread);
|
||||
if (aiocbe->fd_file)
|
||||
fdrop(aiocbe->fd_file, curthread);
|
||||
crfree(aiocbe->cred);
|
||||
uma_zfree(aiocb_zone, aiocbe);
|
||||
AIO_LOCK(ki);
|
||||
@ -967,6 +971,21 @@ aio_process_sync(struct aiocblist *aiocbe)
|
||||
td->td_ucred = td_savedcred;
|
||||
}
|
||||
|
||||
static void
|
||||
aio_process_mlock(struct aiocblist *aiocbe)
|
||||
{
|
||||
struct aiocb *cb = &aiocbe->uaiocb;
|
||||
int error;
|
||||
|
||||
KASSERT(aiocbe->uaiocb.aio_lio_opcode == LIO_MLOCK,
|
||||
("%s: opcode %d", __func__, aiocbe->uaiocb.aio_lio_opcode));
|
||||
|
||||
error = vm_mlock(aiocbe->userproc, aiocbe->cred,
|
||||
__DEVOLATILE(void *, cb->aio_buf), cb->aio_nbytes);
|
||||
cb->_aiocb_private.error = error;
|
||||
cb->_aiocb_private.status = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
aio_bio_done_notify(struct proc *userp, struct aiocblist *aiocbe, int type)
|
||||
{
|
||||
@ -1143,6 +1162,9 @@ aio_daemon(void *_id)
|
||||
case LIO_SYNC:
|
||||
aio_process_sync(aiocbe);
|
||||
break;
|
||||
case LIO_MLOCK:
|
||||
aio_process_mlock(aiocbe);
|
||||
break;
|
||||
}
|
||||
|
||||
mtx_lock(&aio_job_mtx);
|
||||
@ -1283,7 +1305,7 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
|
||||
cb = &aiocbe->uaiocb;
|
||||
fp = aiocbe->fd_file;
|
||||
|
||||
if (fp->f_type != DTYPE_VNODE)
|
||||
if (fp == NULL || fp->f_type != DTYPE_VNODE)
|
||||
return (-1);
|
||||
|
||||
vp = fp->f_vnode;
|
||||
@ -1635,6 +1657,9 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
|
||||
case LIO_SYNC:
|
||||
error = fget(td, fd, CAP_FSYNC, &fp);
|
||||
break;
|
||||
case LIO_MLOCK:
|
||||
fp = NULL;
|
||||
break;
|
||||
case LIO_NOP:
|
||||
error = fget(td, fd, CAP_NONE, &fp);
|
||||
break;
|
||||
@ -1692,7 +1717,8 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
|
||||
error = kqfd_register(kqfd, &kev, td, 1);
|
||||
aqueue_fail:
|
||||
if (error) {
|
||||
fdrop(fp, td);
|
||||
if (fp)
|
||||
fdrop(fp, td);
|
||||
uma_zfree(aiocb_zone, aiocbe);
|
||||
ops->store_error(job, error);
|
||||
goto done;
|
||||
@ -1709,7 +1735,7 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
|
||||
if (opcode == LIO_SYNC)
|
||||
goto queueit;
|
||||
|
||||
if (fp->f_type == DTYPE_SOCKET) {
|
||||
if (fp && fp->f_type == DTYPE_SOCKET) {
|
||||
/*
|
||||
* Alternate queueing for socket ops: Reach down into the
|
||||
* descriptor to get the socket data. Then check to see if the
|
||||
@ -2187,6 +2213,13 @@ sys_aio_write(struct thread *td, struct aio_write_args *uap)
|
||||
return (aio_aqueue(td, uap->aiocbp, NULL, LIO_WRITE, &aiocb_ops));
|
||||
}
|
||||
|
||||
int
|
||||
sys_aio_mlock(struct thread *td, struct aio_mlock_args *uap)
|
||||
{
|
||||
|
||||
return (aio_aqueue(td, uap->aiocbp, NULL, LIO_MLOCK, &aiocb_ops));
|
||||
}
|
||||
|
||||
static int
|
||||
kern_lio_listio(struct thread *td, int mode, struct aiocb * const *uacb_list,
|
||||
struct aiocb **acb_list, int nent, struct sigevent *sig,
|
||||
@ -2928,6 +2961,14 @@ freebsd32_aio_write(struct thread *td, struct freebsd32_aio_write_args *uap)
|
||||
&aiocb32_ops));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_aio_mlock(struct thread *td, struct freebsd32_aio_mlock_args *uap)
|
||||
{
|
||||
|
||||
return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_MLOCK,
|
||||
&aiocb32_ops));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_aio_waitcomplete(struct thread *td,
|
||||
struct freebsd32_aio_waitcomplete_args *uap)
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define LIO_READ 0x2
|
||||
#ifdef _KERNEL
|
||||
#define LIO_SYNC 0x3
|
||||
#define LIO_MLOCK 0x4
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -124,6 +125,11 @@ int aio_cancel(int, struct aiocb *);
|
||||
*/
|
||||
int aio_suspend(const struct aiocb * const[], int, const struct timespec *);
|
||||
|
||||
/*
|
||||
* Asynchronous mlock
|
||||
*/
|
||||
int aio_mlock(struct aiocb *);
|
||||
|
||||
#ifdef __BSD_VISIBLE
|
||||
int aio_waitcomplete(struct aiocb **, struct timespec *);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user