Index: lib/libc/sys/fcntl.2
===================================================================
--- lib/libc/sys/fcntl.2
+++ lib/libc/sys/fcntl.2
@@ -28,7 +28,7 @@
 .\"     @(#)fcntl.2	8.2 (Berkeley) 1/12/94
 .\" $FreeBSD$
 .\"
-.Dd January 17, 2020
+.Dd June 1, 2020
 .Dt FCNTL 2
 .Os
 .Sh NAME
@@ -196,7 +196,7 @@
 .Dv F_GETFL
 and
 .Dv F_SETFL
-flags are as follows:
+commands are as follows:
 .Bl -tag -width O_NONBLOCKX
 .It Dv O_NONBLOCK
 Non-blocking I/O; if no data is available to a
@@ -225,6 +225,21 @@
 signal to be sent to the process group
 when I/O is possible, e.g.,
 upon availability of data to be read.
+.It Dv O_SYNC
+Enable synchronous writes.
+Corresponds to the
+.Dv O_SYNC
+flag of
+.Xr open 2 .
+.Dv O_FSYNC
+is an historical synonym for
+.Dv O_SYNC .
+.It Dv O_DSYNC
+Enable synchronous data writes.
+Corresponds to the
+.Dv O_DSYNC
+flag of
+.Xr open 2 .
 .El
 .Pp
 The seals that may be applied with
Index: lib/libc/sys/open.2
===================================================================
--- lib/libc/sys/open.2
+++ lib/libc/sys/open.2
@@ -28,7 +28,7 @@
 .\"     @(#)open.2	8.2 (Berkeley) 11/16/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd June 1, 2020
 .Dt OPEN 2
 .Os
 .Sh NAME
@@ -175,8 +175,9 @@
 O_SHLOCK	atomically obtain a shared lock
 O_EXLOCK	atomically obtain an exclusive lock
 O_DIRECT	eliminate or reduce cache effects
-O_FSYNC		synchronous writes
+O_FSYNC		synchronous writes (historical synonym for O_SYNC)
 O_SYNC		synchronous writes
+O_DSYNC		synchronous data writes
 O_NOFOLLOW	do not follow symlinks
 O_NOCTTY	ignored
 O_TTY_INIT	ignored
@@ -223,15 +224,18 @@
 The descriptor remains in non-blocking mode for subsequent operations.
 .Pp
 If
-.Dv O_FSYNC
+.Dv O_SYNC
 is used in the mask, all writes will
 immediately and synchronously be written to disk.
-.Pp
-.Dv O_SYNC
-is a synonym for
 .Dv O_FSYNC
-required by
-.Tn POSIX .
+is an historical synonym for
+.Dv O_SYNC .
+.Pp
+If
+.Dv O_DSYNC
+is used in the mask, all data will be synchronously written to disk, but
+changes to meta-data such as file access and modification timestamps may
+be written later.
 .Pp
 If
 .Dv O_NOFOLLOW
@@ -623,6 +627,8 @@
 .Fn openat
 function was introduced in
 .Fx 8.0 .
+.Dv O_DSYNC
+appeared in 13.0.
 .Sh BUGS
 The Open Group Extended API Set 2 specification requires that the test
 for whether
Index: sys/cddl/compat/opensolaris/sys/vnode.h
===================================================================
--- sys/cddl/compat/opensolaris/sys/vnode.h
+++ sys/cddl/compat/opensolaris/sys/vnode.h
@@ -147,7 +147,9 @@
 #define	FCREAT		O_CREAT
 #define	FTRUNC		O_TRUNC
 #define	FEXCL		O_EXCL
+#ifndef FDSYNC
 #define	FDSYNC		FFSYNC
+#endif
 #define	FRSYNC		FFSYNC
 #define	FSYNC		FFSYNC
 #define	FOFFMAX		0x00
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -913,9 +913,16 @@
 		ioflag |= IO_NDELAY;
 	if (fp->f_flag & O_DIRECT)
 		ioflag |= IO_DIRECT;
-	if ((fp->f_flag & O_FSYNC) ||
+	/*
+	 * For O_DSYNC we set both IO_SYNC and IO_DATASYNC, so that VOP_WRITE()
+	 * implementations that don't understand IO_DATASYNC fall back to full
+	 * O_SYNC behavior.
+	 */
+	if ((fp->f_flag & (O_SYNC | O_DSYNC)) ||
 	    (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
 		ioflag |= IO_SYNC;
+	if (fp->f_flag & O_DSYNC)
+		ioflag |= IO_DATASYNC;
 	mp = NULL;
 	if (vp->v_type != VCHR &&
 	    (error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
Index: sys/sys/fcntl.h
===================================================================
--- sys/sys/fcntl.h
+++ sys/sys/fcntl.h
@@ -138,8 +138,10 @@
 #define	O_BENEATH	0x00400000	/* Fail if not under cwd */
 #endif
 
+#define	O_DSYNC		0x00800000	/* POSIX data sync */
+
 /*
- * XXX missing O_DSYNC, O_RSYNC.
+ * XXX missing O_RSYNC.
  */
 
 #ifdef _KERNEL
@@ -155,9 +157,9 @@
 #define	OFLAGS(fflags)	((fflags) & O_EXEC ? (fflags) : (fflags) - 1)
 
 /* bits to save after open */
-#define	FMASK	(FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK|O_DIRECT|FEXEC)
+#define	FMASK	(FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FDSYNC|FNONBLOCK|O_DIRECT|FEXEC)
 /* bits settable by fcntl(F_SETFL, ...) */
-#define	FCNTLFLAGS	(FAPPEND|FASYNC|FFSYNC|FNONBLOCK|FRDAHEAD|O_DIRECT)
+#define	FCNTLFLAGS	(FAPPEND|FASYNC|FFSYNC|FDSYNC|FNONBLOCK|FRDAHEAD|O_DIRECT)
 
 #if defined(COMPAT_FREEBSD7) || defined(COMPAT_FREEBSD6) || \
     defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4)
@@ -182,15 +184,16 @@
 #define	FAPPEND		O_APPEND	/* kernel/compat */
 #define	FASYNC		O_ASYNC		/* kernel/compat */
 #define	FFSYNC		O_FSYNC		/* kernel */
+#define	FDSYNC		O_DSYNC		/* kernel */
 #define	FNONBLOCK	O_NONBLOCK	/* kernel */
 #define	FNDELAY		O_NONBLOCK	/* compat */
 #define	O_NDELAY	O_NONBLOCK	/* compat */
 #endif
 
 /*
- * We are out of bits in f_flag (which is a short).  However,
- * the flag bits not set in FMASK are only meaningful in the
- * initial open syscall.  Those bits can thus be given a
+ * Historically, we ran out of bits in f_flag (which was once a short).
+ * However, the flag bits not set in FMASK are only meaningful in the
+ * initial open syscall.  Those bits were thus given a
  * different meaning for fcntl(2).
  */
 #if __BSD_VISIBLE
Index: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -316,6 +316,7 @@
 #define	IO_NOMACCHECK	0x1000		/* MAC checks unnecessary */
 #define	IO_BUFLOCKED	0x2000		/* ffs flag; indir buf is locked */
 #define	IO_RANGELOCKED	0x4000		/* range locked */
+#define	IO_DATASYNC	0x8000		/* do only data I/O synchronously */
 
 #define IO_SEQMAX	0x7F		/* seq heuristic max value */
 #define IO_SEQSHIFT	16		/* seq heuristic in upper 16 bits */