Implement FBT_FSYNC, which is called on fsync(2) and fdatasync(2).
authorhelg <helg@openbsd.org>
Mon, 16 Jul 2018 13:10:53 +0000 (13:10 +0000)
committerhelg <helg@openbsd.org>
Mon, 16 Jul 2018 13:10:53 +0000 (13:10 +0000)
Currently ignores the a_waitfor argument and always invokes the file
system's fsync implementation synchronously.

ok mpi@

lib/libfuse/fuse_new.3
lib/libfuse/fuse_ops.c
sys/miscfs/fuse/fuse_vnops.c
sys/miscfs/fuse/fusefs.h

index d640805..3c5887c 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: fuse_new.3,v 1.2 2018/07/08 06:17:10 jmc Exp $
+.\" $OpenBSD: fuse_new.3,v 1.3 2018/07/16 13:10:53 helg Exp $
 .\"
 .\" Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
 .\" Copyright (c) 2018 Helg Bredow <helg@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 8 2018 $
+.Dd $Mdocdate: July 16 2018 $
 .Dt FUSE_NEW 3
 .Os
 .Sh NAME
@@ -38,6 +38,13 @@ a negated errno value (-errno) on failure.
 .Pp
 All operations are optional but a functional file system will want to
 implement at least statfs, readdir, open, read and getattr.
+FUSE will return ENOSYS if any operation other than flush, fsync or
+fsyncdir is not implemented.
+.Pp
+The first parameter to each of these operations (except for init and
+terminate) is a NULL terminated string representing the full path to
+the file or directory, relative to the root of this file system, that
+is being operated on.
 .Bd -literal
 struct fuse_operations {
     int    (*getattr)(const char *, struct stat *);
@@ -123,6 +130,24 @@ creates and opens the file.
 There is no equivalent in the
 .Ox
 VFS.
+.It flush
+Called when the file is closed by the
+.Xr close 2
+system call.
+This is the only way for a file system to return an error on close.
+.It fsync
+Optional function that implements
+.Xr fsync 2
+and
+.Xr fdatasync 2 .
+The datasync parameter specifies whether the operation is as a result
+of a call to
+.Xr fdatasync 2
+and is currently always 0 (false).
+ffi.fh_id will contain the file handle returned by the file system when
+the file was opened.
+.It fsyncdir
+Not implemented.
 .It getattr
 Corresponds to the
 .Xr stat 2
@@ -131,19 +156,9 @@ Flags and extended attributes are ignored.
 This operation is mandatory.
 .It getxattr
 Not implemented.
-.It flush
-Called when the file is closed by the
-.Xr close 2
-system call.
-This is the only way for a file system to return an error on close.
 .It getdir
 Deprecated.
 File system should implement readdir instead.
-.It flush
-Called when the file is closed by the
-.Xr close 2
-system call.
-This is the only way for a file system to return an error on close.
 .It mknod
 Called on
 .Xr open 2
@@ -195,7 +210,9 @@ This is always set on
 Similar to use_ino but the file system's inode number is only reported
 for readdir.
 This is always set on
-.Ox .
+.Ox
+because it's required by
+.Xr getcwd 3 .
 .It uid=%u
 The UID that will be reported as the owner for all files by getattr.
 .It umask=%o
index 2a3b0b0..5e9ea7b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_ops.c,v 1.34 2018/06/08 23:43:40 helg Exp $ */
+/* $OpenBSD: fuse_ops.c,v 1.35 2018/07/16 13:10:53 helg Exp $ */
 /*
  * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -434,6 +434,42 @@ ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
        return (0);
 }
 
+static int
+ifuse_ops_fsync(struct fuse *f, struct fusebuf *fbuf)
+{
+       struct fuse_file_info ffi;
+       struct fuse_vnode *vn;
+       char *realname;
+       int datasync;
+
+       CHECK_OPT(fsync);
+
+       memset(&ffi, 0, sizeof(ffi));
+       ffi.fh = fbuf->fb_io_fd;
+
+       /*
+        * fdatasync(2) is just a wrapper around fsync(2) so datasync
+        * is always false.
+        */
+       datasync = 0;
+
+       vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+       if (vn == NULL) {
+               fbuf->fb_err = -errno;
+               return (0);
+       }
+
+       realname = build_realname(f, vn->ino);
+       if (realname == NULL) {
+               fbuf->fb_err = -errno;
+               return (0);
+       }
+       fbuf->fb_err = f->op.fsync(realname, datasync, &ffi);
+       free(realname);
+
+       return (0);
+}
+
 static int
 ifuse_ops_flush(struct fuse *f, struct fusebuf *fbuf)
 {
@@ -1095,6 +1131,9 @@ ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
        case FBT_RELEASE:
                ret = ifuse_ops_release(f, fbuf);
                break;
+       case FBT_FSYNC:
+               ret = ifuse_ops_fsync(f, fbuf);
+               break;
        case FBT_FLUSH:
                ret = ifuse_ops_flush(f, fbuf);
                break;
index 051c633..b20f532 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_vnops.c,v 1.49 2018/06/21 14:17:23 visa Exp $ */
+/* $OpenBSD: fuse_vnops.c,v 1.50 2018/07/16 13:10:53 helg Exp $ */
 /*
  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -66,6 +66,7 @@ int   fusefs_lock(void *);
 int    fusefs_unlock(void *);
 int    fusefs_islocked(void *);
 int    fusefs_advlock(void *);
+int    fusefs_fsync(void *);
 
 /* Prototypes for fusefs kqfilter */
 int    filt_fusefsread(struct knote *, long);
@@ -87,7 +88,7 @@ struct vops fusefs_vops = {
        .vop_ioctl      = fusefs_ioctl,
        .vop_poll       = fusefs_poll,
        .vop_kqfilter   = fusefs_kqfilter,
-       .vop_fsync      = nullop,
+       .vop_fsync      = fusefs_fsync,
        .vop_remove     = fusefs_remove,
        .vop_link       = fusefs_link,
        .vop_rename     = fusefs_rename,
@@ -1526,3 +1527,59 @@ fusefs_advlock(void *v)
        return (lf_advlock(&ip->ufs_ino.i_lockf, ip->filesize, ap->a_id,
            ap->a_op, ap->a_fl, ap->a_flags));
 }
+
+int
+fusefs_fsync(void *v)
+{
+       struct vop_fsync_args *ap = v;
+       struct vnode *vp = ap->a_vp;
+       struct proc *p = ap->a_p;
+       struct fusefs_node *ip;
+       struct fusefs_mnt *fmp;
+       struct fusefs_filehandle *fufh;
+       struct fusebuf *fbuf;
+       int type, error = 0;
+
+       /*
+        * Can't write to directory file handles so no need to fsync.
+        * FUSE has fsyncdir but it doesn't make sense on OpenBSD.
+        */
+       if (vp->v_type == VDIR)
+               return (0);
+
+       ip = VTOI(vp);
+       fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
+
+       if (!fmp->sess_init)
+               return (ENXIO);
+
+       /* Implementing fsync is optional so don't error. */
+       if (fmp->undef_op & UNDEF_FSYNC)
+               return (0);
+
+       /* Sync all writeable file descriptors. */
+       for (type = 0; type < FUFH_MAXTYPE; type++) {
+               fufh = &(ip->fufh[type]);
+               if (fufh->fh_type == FUFH_WRONLY ||
+                   fufh->fh_type == FUFH_RDWR) {
+
+                       fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_FSYNC, p);
+                       fbuf->fb_io_fd = fufh->fh_id;
+
+                       /* Always behave as if ap->a_waitfor = MNT_WAIT. */
+                       error = fb_queue(fmp->dev, fbuf);
+                       fb_delete(fbuf);
+                       if (error)
+                               break;
+               }
+       }
+
+       if (error == ENOSYS) {
+               fmp->undef_op |= UNDEF_FSYNC;
+
+               /* Implementing fsync is optional so don't error. */
+               return (0);
+       }
+
+       return (error);
+}
index c0b3fb8..237ef05 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fusefs.h,v 1.12 2018/06/25 12:03:53 helg Exp $ */
+/* $OpenBSD: fusefs.h,v 1.13 2018/07/16 13:10:53 helg Exp $ */
 /*
  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -68,6 +68,7 @@ struct fusefs_mnt {
 #define UNDEF_SYMLINK  1<<9
 #define UNDEF_MKNOD    1<<10
 #define UNDEF_FLUSH    1<<11
+#define UNDEF_FSYNC    1<<12
 
 extern struct vops fusefs_vops;
 extern struct pool fusefs_fbuf_pool;