aio_fsync(2): Support O_DSYNC.
aio_fsync(O_DSYNC, ...) is the asynchronous version of fdatasync(2). Reviewed by: kib, asomers, jhb Differential Review: https://reviews.freebsd.org/D25071
This commit is contained in:
parent
e7347be9e3
commit
801ac943ea
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd August 19, 2016
|
.Dd January 6, 2021
|
||||||
.Dt AIO_FSYNC 2
|
.Dt AIO_FSYNC 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -49,11 +49,15 @@ completed at the time the call returns.
|
|||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fa op
|
.Fa op
|
||||||
argument can only be set to
|
argument can be set to
|
||||||
.Dv O_SYNC
|
.Dv O_SYNC
|
||||||
to cause all currently queued I/O operations to be completed
|
to cause all currently queued I/O operations to be completed
|
||||||
as if by a call to
|
as if by a call to
|
||||||
.Xr fsync 2 .
|
.Xr fsync 2 ,
|
||||||
|
or
|
||||||
|
.Dv O_DSYNC
|
||||||
|
for the behavior of
|
||||||
|
.Xr fdatasync 2 .
|
||||||
.Pp
|
.Pp
|
||||||
If _POSIX_PRIORITIZED_IO is defined, and the descriptor supports it,
|
If _POSIX_PRIORITIZED_IO is defined, and the descriptor supports it,
|
||||||
then the enqueued operation is submitted at a priority equal to that
|
then the enqueued operation is submitted at a priority equal to that
|
||||||
@ -112,7 +116,9 @@ are unsafe and unsafe asynchronous I/O operations are disabled.
|
|||||||
A value of the
|
A value of the
|
||||||
.Fa op
|
.Fa op
|
||||||
argument is not set to
|
argument is not set to
|
||||||
.Dv O_SYNC .
|
.Dv O_SYNC
|
||||||
|
or
|
||||||
|
.Dv O_DSYNC .
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The following conditions may be synchronously detected when the
|
The following conditions may be synchronously detected when the
|
||||||
@ -176,3 +182,7 @@ The
|
|||||||
.Fn aio_fsync
|
.Fn aio_fsync
|
||||||
system call first appeared in
|
system call first appeared in
|
||||||
.Fx 7.0 .
|
.Fx 7.0 .
|
||||||
|
The
|
||||||
|
.Dv O_DSYNC
|
||||||
|
option appeared in
|
||||||
|
.Fx 13.0 .
|
||||||
|
@ -718,10 +718,10 @@ aio_selectjob(struct aioproc *aiop)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Move all data to a permanent storage device. This code
|
* Move all data to a permanent storage device. This code
|
||||||
* simulates the fsync syscall.
|
* simulates the fsync and fdatasync syscalls.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
aio_fsync_vnode(struct thread *td, struct vnode *vp)
|
aio_fsync_vnode(struct thread *td, struct vnode *vp, int op)
|
||||||
{
|
{
|
||||||
struct mount *mp;
|
struct mount *mp;
|
||||||
int error;
|
int error;
|
||||||
@ -734,7 +734,10 @@ aio_fsync_vnode(struct thread *td, struct vnode *vp)
|
|||||||
vm_object_page_clean(vp->v_object, 0, 0, 0);
|
vm_object_page_clean(vp->v_object, 0, 0, 0);
|
||||||
VM_OBJECT_WUNLOCK(vp->v_object);
|
VM_OBJECT_WUNLOCK(vp->v_object);
|
||||||
}
|
}
|
||||||
error = VOP_FSYNC(vp, MNT_WAIT, td);
|
if (op == LIO_DSYNC)
|
||||||
|
error = VOP_FDATASYNC(vp, td);
|
||||||
|
else
|
||||||
|
error = VOP_FSYNC(vp, MNT_WAIT, td);
|
||||||
|
|
||||||
VOP_UNLOCK(vp);
|
VOP_UNLOCK(vp);
|
||||||
vn_finished_write(mp);
|
vn_finished_write(mp);
|
||||||
@ -838,12 +841,15 @@ aio_process_sync(struct kaiocb *job)
|
|||||||
struct file *fp = job->fd_file;
|
struct file *fp = job->fd_file;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
KASSERT(job->uaiocb.aio_lio_opcode == LIO_SYNC,
|
KASSERT(job->uaiocb.aio_lio_opcode == LIO_SYNC ||
|
||||||
|
job->uaiocb.aio_lio_opcode == LIO_DSYNC,
|
||||||
("%s: opcode %d", __func__, job->uaiocb.aio_lio_opcode));
|
("%s: opcode %d", __func__, job->uaiocb.aio_lio_opcode));
|
||||||
|
|
||||||
td->td_ucred = job->cred;
|
td->td_ucred = job->cred;
|
||||||
if (fp->f_vnode != NULL)
|
if (fp->f_vnode != NULL) {
|
||||||
error = aio_fsync_vnode(td, fp->f_vnode);
|
error = aio_fsync_vnode(td, fp->f_vnode,
|
||||||
|
job->uaiocb.aio_lio_opcode);
|
||||||
|
}
|
||||||
td->td_ucred = td_savedcred;
|
td->td_ucred = td_savedcred;
|
||||||
if (error)
|
if (error)
|
||||||
aio_complete(job, -1, error);
|
aio_complete(job, -1, error);
|
||||||
@ -1579,6 +1585,7 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
|
|||||||
error = fget_read(td, fd, &cap_pread_rights, &fp);
|
error = fget_read(td, fd, &cap_pread_rights, &fp);
|
||||||
break;
|
break;
|
||||||
case LIO_SYNC:
|
case LIO_SYNC:
|
||||||
|
case LIO_DSYNC:
|
||||||
error = fget(td, fd, &cap_fsync_rights, &fp);
|
error = fget(td, fd, &cap_fsync_rights, &fp);
|
||||||
break;
|
break;
|
||||||
case LIO_MLOCK:
|
case LIO_MLOCK:
|
||||||
@ -1592,7 +1599,7 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
|
|||||||
if (error)
|
if (error)
|
||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
if (opcode == LIO_SYNC && fp->f_vnode == NULL) {
|
if ((opcode == LIO_SYNC || opcode == LIO_DSYNC) && fp->f_vnode == NULL) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto err3;
|
goto err3;
|
||||||
}
|
}
|
||||||
@ -1805,10 +1812,12 @@ aio_queue_file(struct file *fp, struct kaiocb *job)
|
|||||||
error = 0;
|
error = 0;
|
||||||
break;
|
break;
|
||||||
case LIO_SYNC:
|
case LIO_SYNC:
|
||||||
|
case LIO_DSYNC:
|
||||||
AIO_LOCK(ki);
|
AIO_LOCK(ki);
|
||||||
TAILQ_FOREACH(job2, &ki->kaio_jobqueue, plist) {
|
TAILQ_FOREACH(job2, &ki->kaio_jobqueue, plist) {
|
||||||
if (job2->fd_file == job->fd_file &&
|
if (job2->fd_file == job->fd_file &&
|
||||||
job2->uaiocb.aio_lio_opcode != LIO_SYNC &&
|
job2->uaiocb.aio_lio_opcode != LIO_SYNC &&
|
||||||
|
job2->uaiocb.aio_lio_opcode != LIO_DSYNC &&
|
||||||
job2->seqno < job->seqno) {
|
job2->seqno < job->seqno) {
|
||||||
job2->jobflags |= KAIOCB_CHECKSYNC;
|
job2->jobflags |= KAIOCB_CHECKSYNC;
|
||||||
job->pending++;
|
job->pending++;
|
||||||
@ -2587,10 +2596,20 @@ static int
|
|||||||
kern_aio_fsync(struct thread *td, int op, struct aiocb *ujob,
|
kern_aio_fsync(struct thread *td, int op, struct aiocb *ujob,
|
||||||
struct aiocb_ops *ops)
|
struct aiocb_ops *ops)
|
||||||
{
|
{
|
||||||
|
int listop;
|
||||||
|
|
||||||
if (op != O_SYNC) /* XXX lack of O_DSYNC */
|
switch (op) {
|
||||||
|
case O_SYNC:
|
||||||
|
listop = LIO_SYNC;
|
||||||
|
break;
|
||||||
|
case O_DSYNC:
|
||||||
|
listop = LIO_DSYNC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
return (aio_aqueue(td, ujob, NULL, LIO_SYNC, ops));
|
}
|
||||||
|
|
||||||
|
return (aio_aqueue(td, ujob, NULL, listop, ops));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#define LIO_MLOCK 0x4
|
#define LIO_MLOCK 0x4
|
||||||
#define LIO_WRITEV 0x5
|
#define LIO_WRITEV 0x5
|
||||||
#define LIO_READV 0x6
|
#define LIO_READV 0x6
|
||||||
|
#define LIO_DSYNC 0x7
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1259,7 +1259,7 @@ ATF_TC_BODY(aio_fsync_errors, tc)
|
|||||||
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
|
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
|
||||||
unlink(FILE_PATHNAME);
|
unlink(FILE_PATHNAME);
|
||||||
|
|
||||||
/* aio_fsync should return EINVAL unless op is O_SYNC */
|
/* aio_fsync should return EINVAL unless op is O_SYNC or O_DSYNC */
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
memset(&iocb, 0, sizeof(iocb));
|
||||||
iocb.aio_fildes = fd;
|
iocb.aio_fildes = fd;
|
||||||
ATF_CHECK_EQ(-1, aio_fsync(666, &iocb));
|
ATF_CHECK_EQ(-1, aio_fsync(666, &iocb));
|
||||||
@ -1282,8 +1282,8 @@ ATF_TC_BODY(aio_fsync_errors, tc)
|
|||||||
/*
|
/*
|
||||||
* This test just performs a basic test of aio_fsync().
|
* This test just performs a basic test of aio_fsync().
|
||||||
*/
|
*/
|
||||||
ATF_TC_WITHOUT_HEAD(aio_fsync_test);
|
static void
|
||||||
ATF_TC_BODY(aio_fsync_test, tc)
|
aio_fsync_test(int op)
|
||||||
{
|
{
|
||||||
struct aiocb synccb, *iocbp;
|
struct aiocb synccb, *iocbp;
|
||||||
struct {
|
struct {
|
||||||
@ -1328,7 +1328,7 @@ ATF_TC_BODY(aio_fsync_test, tc)
|
|||||||
/* Queue the aio_fsync request. */
|
/* Queue the aio_fsync request. */
|
||||||
memset(&synccb, 0, sizeof(synccb));
|
memset(&synccb, 0, sizeof(synccb));
|
||||||
synccb.aio_fildes = fd;
|
synccb.aio_fildes = fd;
|
||||||
ATF_REQUIRE(aio_fsync(O_SYNC, &synccb) == 0);
|
ATF_REQUIRE(aio_fsync(op, &synccb) == 0);
|
||||||
|
|
||||||
/* Wait for requests to complete. */
|
/* Wait for requests to complete. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -1359,6 +1359,18 @@ ATF_TC_BODY(aio_fsync_test, tc)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(aio_fsync_sync_test);
|
||||||
|
ATF_TC_BODY(aio_fsync_sync_test, tc)
|
||||||
|
{
|
||||||
|
aio_fsync_test(O_SYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATF_TC_WITHOUT_HEAD(aio_fsync_dsync_test);
|
||||||
|
ATF_TC_BODY(aio_fsync_dsync_test, tc)
|
||||||
|
{
|
||||||
|
aio_fsync_test(O_DSYNC);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We shouldn't be able to DoS the system by setting iov_len to an insane
|
* We shouldn't be able to DoS the system by setting iov_len to an insane
|
||||||
* value
|
* value
|
||||||
@ -1782,7 +1794,8 @@ ATF_TP_ADD_TCS(tp)
|
|||||||
ATF_TP_ADD_TC(tp, md_thread);
|
ATF_TP_ADD_TC(tp, md_thread);
|
||||||
ATF_TP_ADD_TC(tp, md_waitcomplete);
|
ATF_TP_ADD_TC(tp, md_waitcomplete);
|
||||||
ATF_TP_ADD_TC(tp, aio_fsync_errors);
|
ATF_TP_ADD_TC(tp, aio_fsync_errors);
|
||||||
ATF_TP_ADD_TC(tp, aio_fsync_test);
|
ATF_TP_ADD_TC(tp, aio_fsync_sync_test);
|
||||||
|
ATF_TP_ADD_TC(tp, aio_fsync_dsync_test);
|
||||||
ATF_TP_ADD_TC(tp, aio_large_read_test);
|
ATF_TP_ADD_TC(tp, aio_large_read_test);
|
||||||
ATF_TP_ADD_TC(tp, aio_socket_two_reads);
|
ATF_TP_ADD_TC(tp, aio_socket_two_reads);
|
||||||
ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write);
|
ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write);
|
||||||
|
Loading…
Reference in New Issue
Block a user