From e5a3d8fd4a1efa48d929dd65b9509cad3cdd2e52 Mon Sep 17 00:00:00 2001
From: Tomohiro Kusumi <tkusumi@netbsd.org>
Date: Sun, 12 Sep 2021 01:57:53 +0900
Subject: [PATCH] sys/kern: Add fdatasync(2)

Based on the following FreeBSD commits in 2016.
295af703a0d7987c6cf4987e7b7f5f07b3ca1221
1c1cc89580f0fbfabaf6f6c7f0f6440eef0c128e

Add the syscall and also add it to pthread's cancellation point.
The default behavior is same as fsync(2), which is fine but inefficient.
---
 include/unistd.h                       |  2 --
 lib/libc/sys/Symbol.map                |  3 +++
 lib/libthread_xu/pthread.map           |  2 ++
 lib/libthread_xu/thread/thr_syscalls.c | 18 +++++++++++++
 sys/kern/init_sysent.c                 |  1 +
 sys/kern/syscalls.c                    |  1 +
 sys/kern/syscalls.master               |  1 +
 sys/kern/vfs_default.c                 |  7 ++++++
 sys/kern/vfs_syscalls.c                | 35 ++++++++++++++++++++------
 sys/kern/vfs_vopops.c                  | 35 ++++++++++++++++++++++++++
 sys/sys/kern_syscall.h                 |  1 +
 sys/sys/param.h                        |  3 ++-
 sys/sys/syscall.h                      |  3 ++-
 sys/sys/syscall.mk                     |  3 ++-
 sys/sys/sysproto.h                     |  4 +++
 sys/sys/sysunion.h                     |  1 +
 sys/sys/vfsops.h                       | 18 +++++++++++++
 sys/sys/vnode.h                        |  1 +
 18 files changed, 126 insertions(+), 13 deletions(-)

diff --git a/include/unistd.h b/include/unistd.h
index 99727075ac..a3569d400d 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -435,9 +435,7 @@ extern int optind, opterr, optopt;
 
 /* ISO/IEC 9945-1: 1996 */
 #if __POSIX_VISIBLE >= 199506 || __XSI_VISIBLE
-#if 0 /* XXX missing */
 int	 fdatasync(int);
-#endif
 int	 fsync(int);
 
 /*
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index cecb07b8a8..60d7af5693 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -336,6 +336,7 @@ DF510.0 {
 
 DF602.0 {
     posix_fallocate;
+    fdatasync;
 };
 
 DFprivate_1.0 {
@@ -408,6 +409,7 @@ DFprivate_1.0 {
     __sys_fchown;
     __sys_fchownat;
     __sys_fcntl;
+    __sys_fdatasync;
     __sys_fexecve;
     __sys_fhopen;
     __sys_fhstat;
@@ -712,6 +714,7 @@ DFprivate_1.0 {
     _fchown;
     _fchownat;
     _fcntl;
+    _fdatasync;
     _fexecve;
     _fhopen;
     _fhstat;
diff --git a/lib/libthread_xu/pthread.map b/lib/libthread_xu/pthread.map
index 396a9dd823..1025002286 100644
--- a/lib/libthread_xu/pthread.map
+++ b/lib/libthread_xu/pthread.map
@@ -414,4 +414,6 @@ global:
 	clock_nanosleep
 	pthread_getname_np;
 	pthread_setname_np;
+	__fdatasync;
+	fdatasync;
 };
diff --git a/lib/libthread_xu/thread/thr_syscalls.c b/lib/libthread_xu/thread/thr_syscalls.c
index 99cbcebf56..2766d34a2d 100644
--- a/lib/libthread_xu/thread/thr_syscalls.c
+++ b/lib/libthread_xu/thread/thr_syscalls.c
@@ -104,6 +104,7 @@ extern int	__sys_aio_suspend(const struct aiocb * const[], int,
 extern int	__sys_accept(int, struct sockaddr *, socklen_t *);
 extern int	__sys_connect(int, const struct sockaddr *, socklen_t);
 extern int	__sys_fsync(int);
+extern int	__sys_fdatasync(int);
 extern int	__sys_msync(void *, size_t, int);
 extern int	__sys_poll(struct pollfd *, unsigned, int);
 extern int	__sys_ppoll(struct pollfd *, unsigned, const struct timespec *,
@@ -127,6 +128,7 @@ int	__close(int);
 int	__connect(int, const struct sockaddr *, socklen_t);
 int	__fcntl(int, int,...);
 int	__fsync(int);
+int	__fdatasync(int);
 int	__msync(void *, size_t, int);
 int	__nanosleep(const struct timespec *, struct timespec *);
 int	__clock_nanosleep(clock_t, int, const struct timespec *,
@@ -294,6 +296,22 @@ __fsync(int fd)
 
 __strong_reference(__fsync, fsync);
 
+int
+__fdatasync(int fd)
+{
+	pthread_t curthread = tls_get_curthread();
+	int	oldcancel;
+	int	ret;
+
+	oldcancel = _thr_cancel_enter(curthread);
+	ret = __sys_fdatasync(fd);
+	_thr_cancel_leave(curthread, oldcancel);
+
+	return (ret);
+}
+
+__strong_reference(__fdatasync, fdatasync);
+
 int
 __msync(void *addr, size_t len, int flags)
 {
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 32e5396149..a9a756e2f6 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -568,4 +568,5 @@ struct sysent sysent[] = {
 	{ AS(__realpath_args), (sy_call_t *)sys___realpath },	/* 551 = __realpath */
 	{ AS(fexecve_args), (sy_call_t *)sys_fexecve },	/* 552 = fexecve */
 	{ AS(posix_fallocate_args), (sy_call_t *)sys_posix_fallocate },	/* 553 = posix_fallocate */
+	{ AS(fdatasync_args), (sy_call_t *)sys_fdatasync },	/* 554 = fdatasync */
 };
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 15519e0e2f..f248edbc94 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -560,4 +560,5 @@ const char *syscallnames[] = {
 	"__realpath",			/* 551 = __realpath */
 	"fexecve",			/* 552 = fexecve */
 	"posix_fallocate"		/* 553 = posix_fallocate */
+	"fdatasync"			/* 554 = fdatasync */
 };
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index f4ea746fcb..c0c5d99c9f 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -737,3 +737,4 @@
 551	STD	{ ssize_t __realpath(const char *path, char *buf, size_t len); }
 552	STD	{ int fexecve(int fd, char **argv, char **envv); }
 553	STD	{ int posix_fallocate(int fd, off_t offset, off_t len); }
+554	STD	{ int fdatasync(int fd); }
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index de40304713..a5a4793c60 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -74,6 +74,7 @@ struct vop_ops default_vnode_vops = {
 	.vop_default		= vop_eopnotsupp,
 	.vop_advlock		= (void *)vop_einval,
 	.vop_fsync		= (void *)vop_null,
+	.vop_fdatasync		= vop_stdfdatasync,
 	.vop_ioctl		= (void *)vop_enotty,
 	.vop_mmap		= (void *)vop_einval,
 	.vop_old_lookup		= vop_nolookup,
@@ -1439,6 +1440,12 @@ vop_stdallocate(struct vop_allocate_args *ap)
 	return (error);
 }
 
+int
+vop_stdfdatasync(struct vop_fdatasync_args *ap)
+{
+	return (VOP_FSYNC_FP(ap->a_vp, ap->a_waitfor, ap->a_flags, ap->a_fp));
+}
+
 int	
 vfs_stdroot(struct mount *mp, struct vnode **vpp)
 {
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index f5fac489a9..acdee8a923 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4050,13 +4050,8 @@ sys_ftruncate(struct sysmsg *sysmsg, const struct ftruncate_args *uap)
 	return (error);
 }
 
-/*
- * fsync(int fd)
- *
- * Sync an open file.
- */
 int
-sys_fsync(struct sysmsg *sysmsg, const struct fsync_args *uap)
+kern_fsync(int fd, bool fullsync)
 {
 	struct thread *td = curthread;
 	struct vnode *vp;
@@ -4064,7 +4059,7 @@ sys_fsync(struct sysmsg *sysmsg, const struct fsync_args *uap)
 	vm_object_t obj;
 	int error;
 
-	if ((error = holdvnode(td, uap->fd, &fp)) != 0)
+	if ((error = holdvnode(td, fd, &fp)) != 0)
 		return (error);
 	vp = (struct vnode *)fp->f_data;
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
@@ -4074,7 +4069,9 @@ sys_fsync(struct sysmsg *sysmsg, const struct fsync_args *uap)
 			vm_object_page_clean(obj, 0, 0, 0);
 		}
 	}
-	error = VOP_FSYNC_FP(vp, MNT_WAIT, VOP_FSYNC_SYSCALL, fp);
+	error = fullsync ?
+		VOP_FSYNC_FP(vp, MNT_WAIT, VOP_FSYNC_SYSCALL, fp) :
+		VOP_FDATASYNC_FP(vp, MNT_WAIT, VOP_FSYNC_SYSCALL, fp);
 	if (error == 0 && vp->v_mount)
 		error = buf_fsync(vp);
 	vn_unlock(vp);
@@ -4083,6 +4080,28 @@ sys_fsync(struct sysmsg *sysmsg, const struct fsync_args *uap)
 	return (error);
 }
 
+/*
+ * fsync(int fd)
+ *
+ * Sync an open file.
+ */
+int
+sys_fsync(struct sysmsg *sysmsg, const struct fsync_args *uap)
+{
+	return (kern_fsync(uap->fd, true));
+}
+
+/*
+ * fdatasync(int fd)
+ *
+ * Data-sync an open file.
+ */
+int
+sys_fdatasync(struct sysmsg *sysmsg, const struct fdatasync_args *uap)
+{
+	return (kern_fsync(uap->fd, false));
+}
+
 /*
  * rename op.
  *
diff --git a/sys/kern/vfs_vopops.c b/sys/kern/vfs_vopops.c
index bce106b9cd..e2fea57c66 100644
--- a/sys/kern/vfs_vopops.c
+++ b/sys/kern/vfs_vopops.c
@@ -106,6 +106,7 @@ VNODEOP_DESC_INIT(poll);
 VNODEOP_DESC_INIT(kqfilter);
 VNODEOP_DESC_INIT(mmap);
 VNODEOP_DESC_INIT(fsync);
+VNODEOP_DESC_INIT(fdatasync);
 VNODEOP_DESC_INIT(old_remove);
 VNODEOP_DESC_INIT(old_link);
 VNODEOP_DESC_INIT(old_rename);
@@ -620,6 +621,31 @@ vop_fsync(struct vop_ops *ops, struct vnode *vp, int waitfor, int flags,
 	return(error);
 }
 
+/*
+ * MPSAFE
+ */
+int
+vop_fdatasync(struct vop_ops *ops, struct vnode *vp, int waitfor, int flags,
+	struct file *fp)
+{
+	struct vop_fdatasync_args ap;
+	VFS_MPLOCK_DECLARE;
+	int error;
+
+	ap.a_head.a_desc = &vop_fdatasync_desc;
+	ap.a_head.a_ops = ops;
+	ap.a_vp = vp;
+	ap.a_waitfor = waitfor;
+	ap.a_flags = flags;
+	ap.a_fp = fp;
+
+	VFS_MPLOCK(vp->v_mount);
+	DO_OPS(ops, error, &ap, vop_fdatasync);
+	VFS_MPUNLOCK();
+
+	return(error);
+}
+
 /*
  * MPSAFE
  */
@@ -1893,6 +1919,15 @@ vop_fsync_ap(struct vop_fsync_args *ap)
 	return(error);
 }
 
+int
+vop_fdatasync_ap(struct vop_fdatasync_args *ap)
+{
+	int error;
+
+	DO_OPS(ap->a_head.a_ops, error, ap, vop_fdatasync);
+	return(error);
+}
+
 int
 vop_readdir_ap(struct vop_readdir_args *ap)
 {
diff --git a/sys/sys/kern_syscall.h b/sys/sys/kern_syscall.h
index e3e3079511..d2eec86120 100644
--- a/sys/sys/kern_syscall.h
+++ b/sys/sys/kern_syscall.h
@@ -170,6 +170,7 @@ int kern_utimensat(struct nlookupdata *nd, const struct timespec *ts, int flag);
 int kern_utimes(struct nlookupdata *nd, struct timeval *tptr);
 struct uuid *kern_uuidgen(struct uuid *store, size_t count);
 int kern_posix_fallocate(int fd, off_t offset, off_t len);
+int kern_fsync(int fd, bool fullsync);
 
 /*
  * Prototypes for syscalls in kern/kern_time.c
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 6401df8295..006292e5f5 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -233,9 +233,10 @@
  * 600102 - add nvmm(4) and libnvmm(3)
  * 600103 - remove the old vmm code
  * 600104 - add posix_fallocate()
+ * 600105 - add fdatasync()
  */
 #undef __DragonFly_version
-#define __DragonFly_version 600104	/* propagated to newvers */
+#define __DragonFly_version 600105	/* propagated to newvers */
 
 #include <sys/_null.h>
 
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 3270836680..c273943a81 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -389,4 +389,5 @@
 #define	SYS___realpath	551
 #define	SYS_fexecve	552
 #define	SYS_posix_fallocate	553
-#define	SYS_MAXSYSCALL	554
+#define	SYS_fdatasync	554
+#define	SYS_MAXSYSCALL	555
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index 7a367ce802..d2e1958daa 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -314,4 +314,5 @@ MIASM =  \
 	getrandom.o \
 	__realpath.o \
 	fexecve.o \
-	posix_fallocate.o
+	posix_fallocate.o \
+	fdatasync.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index 13efaede13..46d50c695f 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1437,6 +1437,9 @@ struct	posix_fallocate_args {
 	off_t	offset;	char offset_[PAD_(off_t)];
 	off_t	len;	char len_[PAD_(off_t)];
 };
+struct	fdatasync_args {
+	int	fd;	char fd_[PAD_(int)];
+};
 
 #undef PAD_
 
@@ -1762,6 +1765,7 @@ int	sys_getrandom (struct sysmsg *sysmsg, const struct getrandom_args *);
 int	sys___realpath (struct sysmsg *sysmsg, const struct __realpath_args *);
 int	sys_fexecve (struct sysmsg *sysmsg, const struct fexecve_args *);
 int	sys_posix_fallocate (struct sysmsg *sysmsg, const struct posix_fallocate_args *);
+int	sys_fdatasync (struct sysmsg *sysmsg, const struct fdatasync_args *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h
index 44aef6b7f3..c9ddb8e245 100644
--- a/sys/sys/sysunion.h
+++ b/sys/sys/sysunion.h
@@ -321,4 +321,5 @@ union sysunion {
 	struct	__realpath_args __realpath;
 	struct	fexecve_args fexecve;
 	struct	posix_fallocate_args posix_fallocate;
+	struct	fdatasync_args fdatasync;
 };
diff --git a/sys/sys/vfsops.h b/sys/sys/vfsops.h
index 865e0b553f..5b4a6cc2b7 100644
--- a/sys/sys/vfsops.h
+++ b/sys/sys/vfsops.h
@@ -224,6 +224,14 @@ struct vop_fsync_args {
 	struct file *a_fp; /* FUSE */
 };
 
+struct vop_fdatasync_args {
+	struct vop_generic_args a_head;
+	struct vnode *a_vp;
+	int a_waitfor;
+	int a_flags;
+	struct file *a_fp; /* FUSE */
+};
+
 struct vop_old_remove_args {
 	struct vop_generic_args a_head;
 	struct vnode *a_dvp;
@@ -622,6 +630,7 @@ struct vop_ops {
 	int	(*vop_unused01)(void *);	/* was vop_revoke */
 	int	(*vop_mmap)(struct vop_mmap_args *);
 	int	(*vop_fsync)(struct vop_fsync_args *);
+	int	(*vop_fdatasync)(struct vop_fdatasync_args *);
 	int	(*vop_old_remove)(struct vop_old_remove_args *);
 	int	(*vop_old_link)(struct vop_old_link_args *);
 	int	(*vop_old_rename)(struct vop_old_rename_args *);
@@ -703,6 +712,7 @@ union vop_args_union {
 	struct vop_kqfilter_args vu_kqfilter;
 	struct vop_mmap_args vu_mmap;
 	struct vop_fsync_args vu_fsync;
+	struct vop_fdatasync_args vu_fdatasync;
 	struct vop_old_remove_args vu_remove;
 	struct vop_old_link_args vu_link;
 	struct vop_old_rename_args vu_rename;
@@ -792,6 +802,8 @@ int vop_mmap(struct vop_ops *ops, struct vnode *vp, int fflags,
 		struct ucred *cred);
 int vop_fsync(struct vop_ops *ops, struct vnode *vp, int waitfor, int flags,
 		struct file *fp);
+int vop_fdatasync(struct vop_ops *ops, struct vnode *vp, int waitfor, int flags,
+		struct file *fp);
 int vop_old_remove(struct vop_ops *ops, struct vnode *dvp,
 		struct vnode *vp, struct componentname *cnp);
 int vop_old_link(struct vop_ops *ops, struct vnode *tdvp,
@@ -907,6 +919,7 @@ int vop_poll_ap(struct vop_poll_args *ap);
 int vop_kqfilter_ap(struct vop_kqfilter_args *ap);
 int vop_mmap_ap(struct vop_mmap_args *ap);
 int vop_fsync_ap(struct vop_fsync_args *ap);
+int vop_fdatasync_ap(struct vop_fdatasync_args *ap);
 int vop_old_remove_ap(struct vop_old_remove_args *ap);
 int vop_old_link_ap(struct vop_old_link_args *ap);
 int vop_old_rename_ap(struct vop_old_rename_args *ap);
@@ -971,6 +984,7 @@ extern struct syslink_desc vop_poll_desc;
 extern struct syslink_desc vop_kqfilter_desc;
 extern struct syslink_desc vop_mmap_desc;
 extern struct syslink_desc vop_fsync_desc;
+extern struct syslink_desc vop_fdatasync_desc;
 extern struct syslink_desc vop_old_remove_desc;
 extern struct syslink_desc vop_old_link_desc;
 extern struct syslink_desc vop_old_rename_desc;
@@ -1059,6 +1073,10 @@ extern struct syslink_desc vop_nrename_desc;
 	vop_fsync(*(vp)->v_ops, vp, waitfor, flags, fp) /* FUSE*/
 #define VOP_FSYNC(vp, waitfor, flags)			\
 	VOP_FSYNC_FP(vp, waitfor, flags, NULL)
+#define VOP_FDATASYNC_FP(vp, waitfor, flags, fp)	\
+	vop_fdatasync(*(vp)->v_ops, vp, waitfor, flags, fp) /* FUSE*/
+#define VOP_FDATASYNC(vp, waitfor, flags, fp)	\
+	VOP_FDATASYNC_FP(*(vp)->v_ops, vp, waitfor, flags, NULL)
 #define VOP_READDIR_FP(vp, uio, cred, eofflag, ncookies, cookies, fp)	\
 	vop_readdir(*(vp)->v_ops, vp, uio, cred, eofflag, ncookies, cookies, fp) /* FUSE */
 #define VOP_READDIR(vp, uio, cred, eofflag, ncookies, cookies)		\
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index d99078d016..63fccb2ad3 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -532,6 +532,7 @@ int	vop_stdallocate(struct vop_allocate_args *ap);
 int	vop_stdnoread(struct vop_read_args *ap);
 int	vop_stdnowrite(struct vop_write_args *ap);
 int	vop_stdpathconf (struct vop_pathconf_args *ap);
+int	vop_stdfdatasync(struct vop_fdatasync_args *ap);
 int	vop_eopnotsupp (struct vop_generic_args *ap);
 int	vop_ebadf (struct vop_generic_args *ap);
 int	vop_einval (struct vop_generic_args *ap);
-- 
2.28.0

