The branch stable/13 has been updated by asomers:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=d056bc6f401a01115b6f5fed532c5ce58c0b0414

commit d056bc6f401a01115b6f5fed532c5ce58c0b0414
Author:     Alan Somers <[email protected]>
AuthorDate: 2021-12-05 21:25:17 +0000
Commit:     Alan Somers <[email protected]>
CommitDate: 2022-01-03 02:54:39 +0000

    fusefs: inline fuse_io_dispatch
    
    This function was always confusing, because it created an H-shaped
    callgraph: two functions called in and left via different paths based on
    which which called.
    
    (cherry picked from commit dc433e1530af26b0430d66c06c342889e9609590)
---
 sys/fs/fuse/fuse_io.c    | 181 ++---------------------------------------------
 sys/fs/fuse/fuse_io.h    |  11 ++-
 sys/fs/fuse/fuse_vnops.c | 167 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 178 insertions(+), 181 deletions(-)

diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
index f85d17517ee0..609d08f9e3d5 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -120,184 +120,11 @@ SDT_PROVIDER_DECLARE(fusefs);
  */
 SDT_PROBE_DEFINE2(fusefs, , io, trace, "int", "char*");
 
-static int
-fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end);
-static int 
-fuse_read_directbackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh);
-static int 
-fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
-    struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
-static int 
-fuse_write_directbackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
-    int ioflag, bool pages);
-static int 
-fuse_write_biobackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
-
-/* Invalidate a range of cached data, whether dirty of not */
-static int
-fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
-{
-       struct buf *bp;
-       daddr_t left_lbn, end_lbn, right_lbn;
-       off_t new_filesize;
-       int iosize, left_on, right_on, right_blksize;
-
-       iosize = fuse_iosize(vp);
-       left_lbn = start / iosize;
-       end_lbn = howmany(end, iosize);
-       left_on = start & (iosize - 1);
-       if (left_on != 0) {
-               bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
-               if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
-                       /* 
-                        * Flush the dirty buffer, because we don't have a
-                        * byte-granular way to record which parts of the
-                        * buffer are valid.
-                        */
-                       bwrite(bp);
-                       if (bp->b_error)
-                               return (bp->b_error);
-               } else {
-                       brelse(bp);
-               }
-       }
-       right_on = end & (iosize - 1);
-       if (right_on != 0) {
-               right_lbn = end / iosize;
-               new_filesize = MAX(filesize, end);
-               right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
-               bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
-               if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
-                       /* 
-                        * Flush the dirty buffer, because we don't have a
-                        * byte-granular way to record which parts of the
-                        * buffer are valid.
-                        */
-                       bwrite(bp);
-                       if (bp->b_error)
-                               return (bp->b_error);
-               } else {
-                       brelse(bp);
-               }
-       }
-
-       v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
-       return (0);
-}
-
-SDT_PROBE_DEFINE5(fusefs, , io, io_dispatch, "struct vnode*", "struct uio*",
-               "int", "struct ucred*", "struct fuse_filehandle*");
-SDT_PROBE_DEFINE4(fusefs, , io, io_dispatch_filehandles_closed, "struct 
vnode*",
-    "struct uio*", "int", "struct ucred*");
-int
-fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
-    struct ucred *cred, pid_t pid)
-{
-       struct fuse_filehandle *fufh;
-       int err, directio;
-       int fflag;
-       bool closefufh = false;
-
-       MPASS(vp->v_type == VREG || vp->v_type == VDIR);
-
-       fflag = (uio->uio_rw == UIO_READ) ? FREAD : FWRITE;
-       err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
-       if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
-               /* 
-                * nfsd will do I/O without first doing VOP_OPEN.  We
-                * must implicitly open the file here
-                */
-               err = fuse_filehandle_open(vp, fflag, &fufh, curthread, cred);
-               closefufh = true;
-       }
-       else if (err) {
-               SDT_PROBE4(fusefs, , io, io_dispatch_filehandles_closed,
-                       vp, uio, ioflag, cred);
-               printf("FUSE: io dispatch: filehandles are closed\n");
-               return err;
-       }
-       if (err)
-               goto out;
-       SDT_PROBE5(fusefs, , io, io_dispatch, vp, uio, ioflag, cred, fufh);
-
-       /*
-         * Ideally, when the daemon asks for direct io at open time, the
-         * standard file flag should be set according to this, so that would
-         * just change the default mode, which later on could be changed via
-         * fcntl(2).
-         * But this doesn't work, the O_DIRECT flag gets cleared at some point
-         * (don't know where). So to make any use of the Fuse direct_io option,
-         * we hardwire it into the file's private data (similarly to Linux,
-         * btw.).
-         */
-       directio = (ioflag & IO_DIRECT) || 
!fsess_opt_datacache(vnode_mount(vp));
-
-       switch (uio->uio_rw) {
-       case UIO_READ:
-               fuse_vnode_update(vp, FN_ATIMECHANGE);
-               if (directio) {
-                       SDT_PROBE2(fusefs, , io, trace, 1,
-                               "direct read of vnode");
-                       err = fuse_read_directbackend(vp, uio, cred, fufh);
-               } else {
-                       SDT_PROBE2(fusefs, , io, trace, 1,
-                               "buffered read of vnode");
-                       err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh,
-                               pid);
-               }
-               break;
-       case UIO_WRITE:
-               fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
-               if (directio) {
-                       off_t start, end, filesize;
-                       bool pages = (ioflag & IO_VMIO) != 0;
-
-                       SDT_PROBE2(fusefs, , io, trace, 1,
-                               "direct write of vnode");
-
-                       err = fuse_vnode_size(vp, &filesize, cred, curthread);
-                       if (err)
-                               goto out;
-
-                       start = uio->uio_offset;
-                       end = start + uio->uio_resid;
-                       if (!pages) {
-                               err = fuse_inval_buf_range(vp, filesize, start,
-                                   end);
-                               if (err)
-                                       return (err);
-                       }
-                       err = fuse_write_directbackend(vp, uio, cred, fufh,
-                               filesize, ioflag, pages);
-               } else {
-                       SDT_PROBE2(fusefs, , io, trace, 1,
-                               "buffered write of vnode");
-                       if (!fsess_opt_writeback(vnode_mount(vp)))
-                               ioflag |= IO_SYNC;
-                       err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag,
-                               pid);
-               }
-               fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
-               break;
-       default:
-               panic("uninterpreted mode passed to fuse_io_dispatch");
-       }
-
-out:
-       if (closefufh)
-               fuse_filehandle_close(vp, fufh, curthread, cred);
-
-       return (err);
-}
-
 SDT_PROBE_DEFINE4(fusefs, , io, read_bio_backend_start, "int", "int", "int", 
"int");
 SDT_PROBE_DEFINE2(fusefs, , io, read_bio_backend_feed, "int", "struct buf*");
 SDT_PROBE_DEFINE4(fusefs, , io, read_bio_backend_end, "int", "ssize_t", "int",
                "struct buf*");
-static int
+int
 fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
     struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid)
 {
@@ -403,7 +230,7 @@ SDT_PROBE_DEFINE1(fusefs, , io, read_directbackend_start,
 SDT_PROBE_DEFINE3(fusefs, , io, read_directbackend_complete,
        "struct fuse_dispatcher*", "struct fuse_read_in*", "struct uio*");
 
-static int
+int
 fuse_read_directbackend(struct vnode *vp, struct uio *uio,
     struct ucred *cred, struct fuse_filehandle *fufh)
 {
@@ -465,7 +292,7 @@ out:
        return (err);
 }
 
-static int
+int
 fuse_write_directbackend(struct vnode *vp, struct uio *uio,
     struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
     int ioflag, bool pages)
@@ -628,7 +455,7 @@ SDT_PROBE_DEFINE6(fusefs, , io, write_biobackend_start, 
"int64_t", "int", "int",
 SDT_PROBE_DEFINE2(fusefs, , io, write_biobackend_append_race, "long", "int");
 SDT_PROBE_DEFINE2(fusefs, , io, write_biobackend_issue, "int", "struct buf*");
 
-static int
+int
 fuse_write_biobackend(struct vnode *vp, struct uio *uio,
     struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid)
 {
diff --git a/sys/fs/fuse/fuse_io.h b/sys/fs/fuse/fuse_io.h
index 6240b6e89775..8305171fc941 100644
--- a/sys/fs/fuse/fuse_io.h
+++ b/sys/fs/fuse/fuse_io.h
@@ -65,10 +65,17 @@
 #ifndef _FUSE_IO_H_
 #define _FUSE_IO_H_
 
-int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
-    struct ucred *cred, pid_t pid);
 int fuse_io_strategy(struct vnode *vp, struct buf *bp);
 int fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td);
 int fuse_io_invalbuf(struct vnode *vp, struct thread *td);
+int fuse_read_directbackend(struct vnode *vp, struct uio *uio,
+    struct ucred *cred, struct fuse_filehandle *fufh);
+int fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
+    struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
+int fuse_write_directbackend(struct vnode *vp, struct uio *uio,
+    struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
+    int ioflag, bool pages);
+int fuse_write_biobackend(struct vnode *vp, struct uio *uio,
+    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
 
 #endif /* _FUSE_IO_H_ */
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index d0f4cae302c1..36507fae4d59 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -318,6 +318,59 @@ fuse_fifo_close(struct vop_close_args *ap)
        return (fifo_specops.vop_close(ap));
 }
 
+/* Invalidate a range of cached data, whether dirty of not */
+static int
+fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
+{
+       struct buf *bp;
+       daddr_t left_lbn, end_lbn, right_lbn;
+       off_t new_filesize;
+       int iosize, left_on, right_on, right_blksize;
+
+       iosize = fuse_iosize(vp);
+       left_lbn = start / iosize;
+       end_lbn = howmany(end, iosize);
+       left_on = start & (iosize - 1);
+       if (left_on != 0) {
+               bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
+               if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
+                       /*
+                        * Flush the dirty buffer, because we don't have a
+                        * byte-granular way to record which parts of the
+                        * buffer are valid.
+                        */
+                       bwrite(bp);
+                       if (bp->b_error)
+                               return (bp->b_error);
+               } else {
+                       brelse(bp);
+               }
+       }
+       right_on = end & (iosize - 1);
+       if (right_on != 0) {
+               right_lbn = end / iosize;
+               new_filesize = MAX(filesize, end);
+               right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
+               bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
+               if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
+                       /*
+                        * Flush the dirty buffer, because we don't have a
+                        * byte-granular way to record which parts of the
+                        * buffer are valid.
+                        */
+                       bwrite(bp);
+                       if (bp->b_error)
+                               return (bp->b_error);
+               } else {
+                       brelse(bp);
+               }
+       }
+
+       v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
+       return (0);
+}
+
+
 /* Send FUSE_LSEEK for this node */
 static int
 fuse_vnop_do_lseek(struct vnode *vp, struct thread *td, struct ucred *cred,
@@ -1587,6 +1640,8 @@ fuse_vnop_pathconf(struct vop_pathconf_args *ap)
        }
 }
 
+SDT_PROBE_DEFINE3(fusefs, , vnops, filehandles_closed, "struct vnode*",
+    "struct uio*", "struct ucred*");
 /*
     struct vnop_read_args {
        struct vnode *a_vp;
@@ -1603,6 +1658,11 @@ fuse_vnop_read(struct vop_read_args *ap)
        int ioflag = ap->a_ioflag;
        struct ucred *cred = ap->a_cred;
        pid_t pid = curthread->td_proc->p_pid;
+       struct fuse_filehandle *fufh;
+       int err;
+       bool closefufh = false, directio;
+
+       MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 
        if (fuse_isdeadfs(vp)) {
                return ENXIO;
@@ -1612,7 +1672,45 @@ fuse_vnop_read(struct vop_read_args *ap)
                ioflag |= IO_DIRECT;
        }
 
-       return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
+       err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
+       if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
+               /*
+                * nfsd will do I/O without first doing VOP_OPEN.  We
+                * must implicitly open the file here
+                */
+               err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
+               closefufh = true;
+       }
+       if (err) {
+               SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
+               return err;
+       }
+
+       /*
+         * Ideally, when the daemon asks for direct io at open time, the
+         * standard file flag should be set according to this, so that would
+         * just change the default mode, which later on could be changed via
+         * fcntl(2).
+         * But this doesn't work, the O_DIRECT flag gets cleared at some point
+         * (don't know where). So to make any use of the Fuse direct_io option,
+         * we hardwire it into the file's private data (similarly to Linux,
+         * btw.).
+         */
+       directio = (ioflag & IO_DIRECT) || 
!fsess_opt_datacache(vnode_mount(vp));
+
+       fuse_vnode_update(vp, FN_ATIMECHANGE);
+       if (directio) {
+               SDT_PROBE2(fusefs, , vnops, trace, 1, "direct read of vnode");
+               err = fuse_read_directbackend(vp, uio, cred, fufh);
+       } else {
+               SDT_PROBE2(fusefs, , vnops, trace, 1, "buffered read of vnode");
+               err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh, pid);
+       }
+
+       if (closefufh)
+               fuse_filehandle_close(vp, fufh, curthread, cred);
+
+       return (err);
 }
 
 /*
@@ -2165,6 +2263,11 @@ fuse_vnop_write(struct vop_write_args *ap)
        int ioflag = ap->a_ioflag;
        struct ucred *cred = ap->a_cred;
        pid_t pid = curthread->td_proc->p_pid;
+       struct fuse_filehandle *fufh;
+       int err;
+       bool closefufh = false, directio;
+
+       MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 
        if (fuse_isdeadfs(vp)) {
                return ENXIO;
@@ -2174,7 +2277,67 @@ fuse_vnop_write(struct vop_write_args *ap)
                ioflag |= IO_DIRECT;
        }
 
-       return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
+       err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
+       if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
+               /*
+                * nfsd will do I/O without first doing VOP_OPEN.  We
+                * must implicitly open the file here
+                */
+               err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
+               closefufh = true;
+       }
+       if (err) {
+               SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
+               return err;
+       }
+
+       /*
+         * Ideally, when the daemon asks for direct io at open time, the
+         * standard file flag should be set according to this, so that would
+         * just change the default mode, which later on could be changed via
+         * fcntl(2).
+         * But this doesn't work, the O_DIRECT flag gets cleared at some point
+         * (don't know where). So to make any use of the Fuse direct_io option,
+         * we hardwire it into the file's private data (similarly to Linux,
+         * btw.).
+         */
+       directio = (ioflag & IO_DIRECT) || 
!fsess_opt_datacache(vnode_mount(vp));
+
+       fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
+       if (directio) {
+               off_t start, end, filesize;
+               bool pages = (ioflag & IO_VMIO) != 0;
+
+               SDT_PROBE2(fusefs, , vnops, trace, 1, "direct write of vnode");
+
+               err = fuse_vnode_size(vp, &filesize, cred, curthread);
+               if (err)
+                       goto out;
+
+               start = uio->uio_offset;
+               end = start + uio->uio_resid;
+               if (!pages) {
+                       err = fuse_inval_buf_range(vp, filesize, start,
+                           end);
+                       if (err)
+                               goto out;
+               }
+               err = fuse_write_directbackend(vp, uio, cred, fufh,
+                       filesize, ioflag, pages);
+       } else {
+               SDT_PROBE2(fusefs, , vnops, trace, 1,
+                       "buffered write of vnode");
+               if (!fsess_opt_writeback(vnode_mount(vp)))
+                       ioflag |= IO_SYNC;
+               err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid);
+       }
+       fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
+
+out:
+       if (closefufh)
+               fuse_filehandle_close(vp, fufh, curthread, cred);
+
+       return (err);
 }
 
 static daddr_t

Reply via email to