diff --git a/lib/libc/sys/aio_fsync.2 b/lib/libc/sys/aio_fsync.2 --- a/lib/libc/sys/aio_fsync.2 +++ b/lib/libc/sys/aio_fsync.2 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 19, 2016 +.Dd January 6, 2021 .Dt AIO_FSYNC 2 .Os .Sh NAME @@ -49,11 +49,15 @@ .Pp The .Fa op -argument can only be set to +argument can be set to .Dv O_SYNC to cause all currently queued I/O operations to be completed as if by a call to -.Xr fsync 2 . +.Xr fsync 2 , +or +.Dv O_DSYNC +for +.Xr fdatasync 2 . .Pp If _POSIX_PRIORITIZED_IO is defined, and the descriptor supports it, then the enqueued operation is submitted at a priority equal to that @@ -112,7 +116,9 @@ A value of the .Fa op argument is not set to -.Dv O_SYNC . +.Dv O_SYNC +or +.Dv O_DSYNC . .El .Pp The following conditions may be synchronously detected when the @@ -176,3 +182,7 @@ .Fn aio_fsync system call first appeared in .Fx 7.0 . +The +.Dv O_DSYNC +option appeared in +.Fx 13.0 . diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -718,10 +718,10 @@ /* * Move all data to a permanent storage device. This code - * simulates the fsync syscall. + * simulates the fsync and fdatasync syscalls. */ 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; int error; @@ -734,7 +734,10 @@ vm_object_page_clean(vp->v_object, 0, 0, 0); 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); vn_finished_write(mp); @@ -838,12 +841,15 @@ struct file *fp = job->fd_file; 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)); td->td_ucred = job->cred; - if (fp->f_vnode != NULL) - error = aio_fsync_vnode(td, fp->f_vnode); + if (fp->f_vnode != NULL) { + error = aio_fsync_vnode(td, fp->f_vnode, + job->uaiocb.aio_lio_opcode); + } td->td_ucred = td_savedcred; if (error) aio_complete(job, -1, error); @@ -1579,6 +1585,7 @@ error = fget_read(td, fd, &cap_pread_rights, &fp); break; case LIO_SYNC: + case LIO_DSYNC: error = fget(td, fd, &cap_fsync_rights, &fp); break; case LIO_MLOCK: @@ -1592,7 +1599,7 @@ if (error) goto err3; - if (opcode == LIO_SYNC && fp->f_vnode == NULL) { + if ((opcode == LIO_SYNC || opcode == LIO_DSYNC) && fp->f_vnode == NULL) { error = EINVAL; goto err3; } @@ -1805,10 +1812,12 @@ error = 0; break; case LIO_SYNC: + case LIO_DSYNC: AIO_LOCK(ki); TAILQ_FOREACH(job2, &ki->kaio_jobqueue, plist) { if (job2->fd_file == job->fd_file && job2->uaiocb.aio_lio_opcode != LIO_SYNC && + job2->uaiocb.aio_lio_opcode != LIO_DSYNC && job2->seqno < job->seqno) { job2->jobflags |= KAIOCB_CHECKSYNC; job->pending++; @@ -2587,10 +2596,20 @@ kern_aio_fsync(struct thread *td, int op, struct aiocb *ujob, 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 (aio_aqueue(td, ujob, NULL, LIO_SYNC, ops)); + } + + return (aio_aqueue(td, ujob, NULL, listop, ops)); } int diff --git a/sys/sys/aio.h b/sys/sys/aio.h --- a/sys/sys/aio.h +++ b/sys/sys/aio.h @@ -48,6 +48,7 @@ #define LIO_MLOCK 0x4 #define LIO_WRITEV 0x5 #define LIO_READV 0x6 +#define LIO_DSYNC 0x7 #endif /* diff --git a/tests/sys/aio/aio_test.c b/tests/sys/aio/aio_test.c --- a/tests/sys/aio/aio_test.c +++ b/tests/sys/aio/aio_test.c @@ -1259,7 +1259,7 @@ ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 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)); iocb.aio_fildes = fd; ATF_CHECK_EQ(-1, aio_fsync(666, &iocb)); @@ -1282,8 +1282,8 @@ /* * This test just performs a basic test of aio_fsync(). */ -ATF_TC_WITHOUT_HEAD(aio_fsync_test); -ATF_TC_BODY(aio_fsync_test, tc) +static void +aio_fsync_test(int op) { struct aiocb synccb, *iocbp; struct { @@ -1328,7 +1328,7 @@ /* Queue the aio_fsync request. */ memset(&synccb, 0, sizeof(synccb)); synccb.aio_fildes = fd; - ATF_REQUIRE(aio_fsync(O_SYNC, &synccb) == 0); + ATF_REQUIRE(aio_fsync(op, &synccb) == 0); /* Wait for requests to complete. */ for (;;) { @@ -1359,6 +1359,18 @@ 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 * value @@ -1782,7 +1794,8 @@ ATF_TP_ADD_TC(tp, md_thread); ATF_TP_ADD_TC(tp, md_waitcomplete); 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_socket_two_reads); ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write);