On Mon, Nov 27, 2017 at 10:48:04AM +0100, Martin Pieuchot wrote:
> On 23/11/17(Thu) 21:45, Helg wrote:
> > On Thu, Nov 23, 2017 at 12:09:34PM +0000, Helg Bredow wrote:
> > > ----- Forwarded message from Martin Pieuchot <m...@openbsd.org> -----
> > > 
> > > Date: Sat, 18 Nov 2017 11:03:49 +0100
> > > From: Martin Pieuchot <m...@openbsd.org>
> > > To: Helg Bredow <xx...@msn.com>
> > > CC: "tech@openbsd.org" <tech@openbsd.org>
> > > Subject: Re: fuse: vfs create does not map 1:1 to fuse create
> > > User-Agent: Mutt/1.9.1 (2017-09-22)
> > > 
> > > On 18/11/17(Sat) 02:22, Helg Bredow wrote:
> > > > On Fri, 10 Nov 2017 09:09:32 +0100
> > > > Martin Pieuchot <m...@openbsd.org> wrote:
> > > > 
> > > > > On 09/11/17(Thu) 01:20, Helg Bredow wrote:
> > > > > > > On 08/11/17(Wed) 14:12, Helg Bredow wrote:
> > > > > > > > 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. 
> > > > > > > > [...]
> > > > > > > 
> > > > [...]
> > > > > 
> > [...]
> > > > 
> > > > I now this caused some confusion but I believe the patch below is the
> > > > correct solution.
> > > 
> > > When you use the work "believing" you're asking us to trust you without
> > > argumenting.
> > > 
> > > >                   Here's the mapping of file system calls so it's clear.
> > > > [...]
> > > 
> > > That's irrelevant.
> > > 
> > > There's no such thing as "atomic_open" from the userland point of view.
> > > So what you're discussing here is an "implementation details" of Linux
> > > VFS.
> > > 
> > > What matters is which syscall the application do.  I believe it is
> > > open(2).  So how its arguments are translated to the userland FS?  If
> > > I understand your diff correctly, OpenBSD will now do something like
> > > below (please correct the graph):
> > > 
> > > 
> > >   USER PROCESS            fuse-zip
> > >       |                       ^
> > >    open(2)                    | 
> > >       |           FBT_MKNOD + FBT_OPEN 
> > >      \/                     |
> > >   ---------------------------------
> > >       
> > >                 KERNEL
> > > 
> > > The only thing I understand is that you're changing the kernel behavior
> > > for all open(2) syscall operating on FUSE filesystem.  Before the kernel
> > > was generating a FBT_CREATE and FBT_OPEN messages, with some arguments.
> > > Now you want to generate FTB_MKNOD and FBT_OPEN with other arguments.
> > > 
> > > To me it sounds that you're working around a problem you don't
> > > understand.  If FUSE FSs want a FUSE 'create' operation then let's
> > > give them that!  What argument do they expect?
> > > 
> > > So let's start from the beginning:
> > > 
> > > - Which syscall is causing problem with which arguments?
> > > - Which FUSE operation(s) FUSE FSs are expecting for this exact syscall
> > >   with these arguments? 
> > > - Which FUSE operation(s) OpenBSD FUSE is currently generating with which
> > >   arguments?
> >  
> > The syscall that is causing the problem is open(2) with the O_CREAT flag.
> > With my change, this is the call graph.
> >  
> >  open(2)
> >    |
> >  vn_open()
> >    |
> >    +--VOP_CREATE(9) when O_CREAT
> >    |       |
> >    |       +-->fusefs_create()-->FBT_MKNOD-->ifuse_ops_mknod()
> >    |                                               |
> >    |                                               +--> fs mknod()
> >    |
> >    +--VOP_SETATTR(9) when O_TRUNC
> >    |       |
> >    |       +-->fusefs_setattr()-->FBT_SETATTR-->ifuse_ops_setattr()
> >    |                                               |
> >    |                                               +--> fs truncate()
> >    |
> >    +--VOP_OPEN(9)   always
> >            |
> >            +--fusefs_open()-->FBT_OPEN-->ifuse_ops_open()
> >                                                    |
> >                                                    +--> fs open()
> >  
> >  
> > The file systems are expecting the following arguments.
> > 
> > mknod(path, mode, dev)
> >    mode is that passed to open(2)
> >    dev will be 0 for regular files. FUSE mknod can create regular files.
> > open(path, fuse_file_info)
> >    fuse_file_info has (almost all) flags passed to open(2) plus other
> >    things that are not set by ifuse_ops_open. The FS will also return
> >    a handle to the file that was opened which it expects to receive
> >    again for functions that operate on the same file.
> > create(path, mode, fuse_file_info)
> >    mode is that passed to open(2)
> >    fuse_file_info has (almost all) flags passed to open(2) plus other
> >    things that are not set by ifuse_ops_open. The FS will also return
> >    a handle to the file that was opened which it expects to receive
> >    again for functions that operate on the same file.
> >    
> > OpenBSD FUSE is currently generating the following sequence of FUSE
> > calls when creating a file with open(2).
> > 
> >   FBT_CREATE + FBT_OPEN
> >   create arguments are hard-coded to O_CREAT | O_RDWR
> >   open arguments are either O_RDONLY, O_RDWR, O_WRONLY depending on
> >   mode
> > 
> > The problem is in vn_open(9). It does not pass the flags to VOP_CREATE
> > so we don't have them in fusefs_create(). We could defer calling create
> > when fusefs_open() is called but then we don't have the mode. We could
> > store the mode in fusefs_create() but create operates on a directory
> > vnode and this is not locked when fusefs_open() is called so we would
> > have to lock it ourselves. I don't fancy messing with vnode locks
> > right now.
> > 
> > FUSE's FS create() needs open(2)'s `flags' and `mode_t'.
> > 
> > These are the options we have.
> > 
> > 1. Pass more arguments to VOP_CREATE(9)
> > 
> > 2. Delay sending FBT_CREATE from kernel to userland and send it instead
> >    of FBT_OPEN if O_CREAT flag is passed to open(2)
> > 
> > 3. Don't support FBT_CREATE in the OpenBSD FUSE implementation
> > 
> > I've chosen option 3. because this has the least risk and sends a valid
> > sequence of messages (FBT_MKNOD + FBT_OPEN) from the kernel to userland.
> > This will get us by until FUSE is more stable and I can revisit it 
> > later.
> > 
> > This patch is the same as I previously sent but with more comments.
> 
> I agree option 3 is the best for the moment.  We should try to
> consolidate our FUSE implementation without extending the VFS
> first.
> 
> Some comments below.

Thanks for all your patience so far mpi@, I really appreciate your help.
I've replaced the patch with an updated version so I'll address your
comments directly here.

> Can't you write that on a single line?
> 
>       flags = OFLAGS(ap->a_mode) & ~(O_CREAT|O_EXCL|O_TRUNC);

Done.

> > -   fbuf->fb_io_flags = O_CREAT | O_RDWR;
> 
> Why are you hardcoding RDWR?

I'm not. I deleted this line because FBT_MKNOD doesn't accept flags.

> Just remove the function, if people need this they can look at the
> history.

Done. I've also removed FBT_CREATE from sys/sys/fusebuf.h and
share/man/man9/fb_setup.9


Index: lib/libfuse/fuse_ops.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_ops.c,v
retrieving revision 1.27
diff -u -p -u -p -r1.27 fuse_ops.c
--- lib/libfuse/fuse_ops.c      17 Nov 2017 15:45:17 -0000      1.27
+++ lib/libfuse/fuse_ops.c      28 Nov 2017 14:43:48 -0000
@@ -580,53 +580,6 @@ ifuse_ops_write(struct fuse *f, struct f
 }
 
 static int
-ifuse_ops_create(struct fuse *f, struct fusebuf *fbuf)
-{
-       struct fuse_file_info ffi;
-       struct fuse_vnode *vn;
-       uint32_t mode;
-
-       char *realname;
-
-       DPRINTF("Opcode:\tcreate\n");
-       DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
-
-       bzero(&ffi, sizeof(ffi));
-       ffi.flags = fbuf->fb_io_flags;
-       mode = fbuf->fb_io_mode;
-
-       vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
-       if (vn == NULL) {
-               fbuf->fb_err = -errno;
-               free(fbuf->fb_dat);
-               return (0);
-       }
-
-       free(fbuf->fb_dat);
-       realname = build_realname(f, vn->ino);
-       if (realname == NULL) {
-               fbuf->fb_err = -errno;
-               return (0);
-       }
-
-       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;
-
-       if (!fbuf->fb_err) {
-               fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
-               fbuf->fb_ino = fbuf->fb_attr.st_ino;
-               fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
-       }
-       free(realname);
-
-       return (0);
-}
-
-static int
 ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
 {
        struct fuse_vnode *vn;
@@ -1124,9 +1077,6 @@ ifuse_exec_opcode(struct fuse *f, struct
                break;
        case FBT_ACCESS:
                ret = ifuse_ops_access(f, fbuf);
-               break;
-       case FBT_CREATE:
-               ret = ifuse_ops_create(f, fbuf);
                break;
        case FBT_SYMLINK:
                ret = ifuse_ops_symlink(f, fbuf);
Index: sys/miscfs/fuse/fuse_vnops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fuse/fuse_vnops.c,v
retrieving revision 1.36
diff -u -p -u -p -r1.36 fuse_vnops.c
--- sys/miscfs/fuse/fuse_vnops.c        27 Nov 2017 22:55:17 -0000      1.36
+++ sys/miscfs/fuse/fuse_vnops.c        28 Nov 2017 14:43:49 -0000
@@ -211,7 +211,7 @@ fusefs_open(void *v)
        struct fusefs_node *ip;
        struct fusefs_mnt *fmp;
        enum fufh_type fufh_type = FUFH_RDONLY;
-       int flags = O_RDONLY;
+       int flags;
        int error;
        int isdir;
 
@@ -226,24 +226,27 @@ fusefs_open(void *v)
        if (ap->a_vp->v_type == VDIR)
                isdir = 1;
        else {
-               if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) {
+               if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE))
                        fufh_type = FUFH_RDWR;
-                       flags = O_RDWR;
-               } else if (ap->a_mode  & (FWRITE)) {
+               else if (ap->a_mode  & (FWRITE))
                        fufh_type = FUFH_WRONLY;
-                       flags = O_WRONLY;
-               }
        }
 
        /* already open i think all is ok */
        if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
                return (0);
 
+       /*
+        * The file has already been created and/or truncated so FUSE dictates
+        * that no creation and truncation flags are passed to open.
+        */
+       flags = OFLAGS(ap->a_mode) & ~(O_CREAT|O_EXCL|O_TRUNC);
+
        error = fusefs_file_open(fmp, ip, fufh_type, flags, isdir, ap->a_p);
        if (error)
                return (error);
 
-       return (error);
+       return (0);
 }
 
 int
@@ -904,16 +907,15 @@ 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;
 
        memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
        fbuf->fb_dat[cnp->cn_namelen] = '\0';
@@ -921,7 +923,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: sys/sys/fusebuf.h
===================================================================
RCS file: /cvs/src/sys/sys/fusebuf.h,v
retrieving revision 1.11
diff -u -p -u -p -r1.11 fusebuf.h
--- sys/sys/fusebuf.h   30 Aug 2016 16:45:54 -0000      1.11
+++ sys/sys/fusebuf.h   28 Nov 2017 14:43:49 -0000
@@ -126,7 +126,6 @@ struct fusebuf {
 #define FBT_RELEASEDIR 22
 #define FBT_FSYNCDIR   23
 #define FBT_ACCESS     24
-#define FBT_CREATE     25
 #define FBT_DESTROY    26
 #define FBT_RECLAIM    27
 
Index: share/man/man9/fb_setup.9
===================================================================
RCS file: /cvs/src/share/man/man9/fb_setup.9,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 fb_setup.9
--- share/man/man9/fb_setup.9   30 Aug 2016 16:45:54 -0000      1.6
+++ share/man/man9/fb_setup.9   28 Nov 2017 14:43:49 -0000
@@ -184,8 +184,6 @@ The fusebuf is a close dir operation.
 The fusebuf is a dir sync operation.
 .It Dv FBT_ACCESS
 The fusebuf is an access operation.
-.It Dv FBT_CREATE
-The fusebuf is a create file operation.
 .It Dv FBT_DESTROY
 The fusebuf closes the FUSE connection.
 .El

Reply via email to