git: dc433e1530af - main - fusefs: inline fuse_io_dispatch
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 07 Dec 2021 04:42:24 UTC
The branch main has been updated by asomers:
URL: https://cgit.FreeBSD.org/src/commit/?id=dc433e1530af26b0430d66c06c342889e9609590
commit dc433e1530af26b0430d66c06c342889e9609590
Author: Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2021-12-05 21:25:17 +0000
Commit: Alan Somers <asomers@FreeBSD.org>
CommitDate: 2021-12-07 04:41:50 +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.
MFC after: 2 weeks
---
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 2bc592952a4f..be532fa6aa27 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -119,184 +119,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)
{
@@ -402,7 +229,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)
{
@@ -464,7 +291,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)
@@ -627,7 +454,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 a81916b8fbbd..30819b436fee 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