There is a bug when creating a file in fuse-exfat and then deleting it
again without first unmounting the file system. The reason for this is
that fuse-exfat maintains strict reference counts and fuse currently
calls the file system create and open functions when it should only
call create. The additional call to open results in a node having one
extra reference on release.

The Linux version of fuse.h states the following for create.

* Create and open a file
*
* If the file does not exist, first create it with the specified
* mode, and then open it.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the mknod() and open() methods
* will be called instead.
*
* Introduced in version 2.5

The VOP_CREATE(9) function does not behave like this so we either need
to simulate it within fuse or fall back to mknod() and open(). Note
that fuse mknod DOES allow the creation of regular files so doesn't map
completely 1:1 to OpenBSDs mknod(2). Linux has the atomic_open system
call, which maps 1:1 to fuse create.

The following patch is the first pass at changing the behaviour of
fusefs_create so that it maps 1:1 to fuse mknod. If this approach is
accepted, we should consider lowering FUSE_VERSION in fuse.h to 24 so
that file systems can check the supported fuse version at compile time
to determine whether create is available. The only port that currently
does not implement mknod is fuse-zip. It should not be difficult to
patch this.

An alternative and more complicated patch is to modify fusefs_create to
store the file handle returned by the file system in the same way that
fusefs_open does and then not open the file again. The downside of this
is that fusefs_create does not receive the open flags from the vn_open
vfs system call so cannot pass these onto the fuse file system. Let me
know if you would like to see this alternative patch.


Index: sys/miscfs/fuse/fuse_vnops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fuse/fuse_vnops.c,v
retrieving revision 1.33
diff -u -p -r1.33 fuse_vnops.c
--- sys/miscfs/fuse/fuse_vnops.c        7 Sep 2016 17:53:35
-0000   1.33 +++ sys/miscfs/fuse/fuse_vnops.c   8 Nov 2017
13:38:04 -0000 @@ -891,13 +891,13 @@ fusefs_create(void *v)
                goto out;
        }
 
-       if (fmp->undef_op & UNDEF_CREATE) {
+       if (fmp->undef_op & UNDEF_MKNOD) {
                error = ENOSYS;
                goto out;
        }
 
        fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
-           FBT_CREATE, p);
+           FBT_MKNOD, p);
 
        fbuf->fb_io_mode = mode;
        fbuf->fb_io_flags = O_CREAT | O_RDWR;
@@ -908,7 +908,7 @@ fusefs_create(void *v)
        error = fb_queue(fmp->dev, fbuf);
        if (error) {
                if (error == ENOSYS)
-                       fmp->undef_op |= UNDEF_CREATE;
+                       fmp->undef_op |= UNDEF_MKNOD;
 
                fb_delete(fbuf);
                goto out;
Index: lib/libfuse/fuse_ops.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_ops.c,v
retrieving revision 1.26
diff -u -p -r1.26 fuse_ops.c
--- lib/libfuse/fuse_ops.c      7 Sep 2016 17:53:35 -0000       1.26
+++ lib/libfuse/fuse_ops.c      8 Nov 2017 13:38:05 -0000
@@ -598,8 +598,6 @@ ifuse_ops_create(struct fuse *f, struct 
 
        if (f->op.create)
                fbuf->fb_err = f->op.create(realname, mode,  &ffi);
-       else if (f->op.mknod)
-               fbuf->fb_err = f->op.mknod(realname, S_IFREG | mode,
0); else
                fbuf->fb_err = -ENOSYS;
 

Reply via email to