The branch main has been updated by arrowd:

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

commit f9c9122d5ab9b106ddc6897454350b31de838631
Author:     Gleb Popov <arr...@freebsd.org>
AuthorDate: 2025-06-13 10:38:35 +0000
Commit:     Gleb Popov <arr...@freebsd.org>
CommitDate: 2025-06-17 06:11:34 +0000

    fusefs: First take on exterrorizing
    
    Reviewed by:    kib, asomers
    Approved by:    kib, asomers
    Differential Revision: https://reviews.freebsd.org/D50831
---
 sys/fs/fuse/fuse_device.c | 34 +++++++++++++++++++++-------------
 sys/fs/fuse/fuse_vfsops.c | 33 +++++++++++++++++++++------------
 sys/sys/exterr_cat.h      |  1 +
 3 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c
index 0a5da63c1f54..b0c886d4b120 100644
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -82,6 +82,8 @@
 #include <sys/sysctl.h>
 #include <sys/poll.h>
 #include <sys/selinfo.h>
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#include <sys/exterrvar.h>
 
 #include "fuse.h"
 #include "fuse_internal.h"
@@ -193,7 +195,7 @@ fuse_device_filter(struct cdev *dev, struct knote *kn)
                kn->kn_fop = &fuse_device_wfiltops;
                error = 0;
        } else if (error == 0) {
-               error = EINVAL;
+               error = EXTERROR(EINVAL, "Unsupported kevent filter");
                kn->kn_data = error;
        }
 
@@ -319,7 +321,7 @@ again:
                        "we know early on that reader should be kicked so we "
                        "don't wait for news");
                fuse_lck_mtx_unlock(data->ms_mtx);
-               return (ENODEV);
+               return (EXTERROR(ENODEV, "This FUSE session is about to be 
closed"));
        }
        if (!(tick = fuse_ms_pop(data))) {
                /* check if we may block */
@@ -331,7 +333,10 @@ again:
                        err = msleep(data, &data->ms_mtx, PCATCH, "fu_msg", 0);
                        if (err != 0) {
                                fuse_lck_mtx_unlock(data->ms_mtx);
-                               return (fdata_get_dead(data) ? ENODEV : err);
+                               if (fdata_get_dead(data))
+                                       err = EXTERROR(ENODEV,
+                                               "This FUSE session is about to 
be closed");
+                               return (err);
                        }
                        tick = fuse_ms_pop(data);
                }
@@ -361,8 +366,8 @@ again:
                        FUSE_ASSERT_MS_DONE(tick);
                        fuse_ticket_drop(tick);
                }
-               return (ENODEV);        /* This should make the daemon get off
-                                        * of us */
+               /* This should make the daemon get off of us */
+               return (EXTERROR(ENODEV, "This FUSE session is about to be 
closed"));
        }
        SDT_PROBE2(fusefs, , device, trace, 1,
                "fuse device read message successfully");
@@ -385,7 +390,7 @@ again:
                fdata_set_dead(data);
                SDT_PROBE2(fusefs, , device, trace, 2,
                    "daemon is stupid, kick it off...");
-               err = ENODEV;
+               err = EXTERROR(ENODEV, "Partial read attempted");
        } else {
                err = uiomove(buf, buflen, uio);
        }
@@ -403,12 +408,14 @@ fuse_ohead_audit(struct fuse_out_header *ohead, struct 
uio *uio)
                SDT_PROBE2(fusefs, , device, trace, 1,
                        "Format error: body size "
                        "differs from size claimed by header");
-               return (EINVAL);
+               return (EXTERROR(EINVAL, "Format error: body size "
+                   "differs from size claimed by header"));
        }
        if (uio->uio_resid && ohead->unique != 0 && ohead->error) {
                SDT_PROBE2(fusefs, , device, trace, 1, 
                        "Format error: non zero error but message had a body");
-               return (EINVAL);
+               return (EXTERROR(EINVAL, "Format error: non zero error, "
+                   "but message had a body"));
        }
 
        return (0);
@@ -444,7 +451,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int 
ioflag)
                SDT_PROBE2(fusefs, , device, trace, 1,
                        "fuse_device_write got less than a header!");
                fdata_set_dead(data);
-               return (EINVAL);
+               return (EXTERROR(EINVAL, "fuse_device_write got less than a 
header!"));
        }
        if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
                return (err);
@@ -452,7 +459,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int 
ioflag)
        if (data->linux_errnos != 0 && ohead.error != 0) {
                err = -ohead.error;
                if (err < 0 || err >= nitems(linux_to_bsd_errtbl))
-                       return (EINVAL);
+                       return (EXTERROR(EINVAL, "Unknown Linux errno", err));
 
                /* '-', because it will get flipped again below */
                ohead.error = -linux_to_bsd_errtbl[err];
@@ -520,7 +527,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int 
ioflag)
                                memcpy(&tick->tk_aw_ohead, &ohead,
                                        sizeof(ohead));
                                tick->tk_aw_handler(tick, uio);
-                               err = EINVAL;
+                               err = EXTERROR(EINVAL, "Unknown errno", 
ohead.error);
                        } else {
                                memcpy(&tick->tk_aw_ohead, &ohead,
                                        sizeof(ohead));
@@ -570,7 +577,8 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int 
ioflag)
                        /* Unimplemented.  See comments in fuse_vnops */
                default:
                        /* Not implemented */
-                       err = ENOSYS;
+                       err = EXTERROR(ENOSYS, "Unimplemented FUSE notification 
code",
+                               ohead.error);
                }
                vfs_unbusy(mp);
        } else {
@@ -589,7 +597,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int 
ioflag)
                         */
                        err = 0;
                } else {
-                       err = EINVAL;
+                       err = EXTERROR(ENOSYS, "FUSE ticket is missing");
                }
        }
 
diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c
index 48b84d3c75af..1b858a988289 100644
--- a/sys/fs/fuse/fuse_vfsops.c
+++ b/sys/fs/fuse/fuse_vfsops.c
@@ -81,6 +81,8 @@
 #include <sys/mount.h>
 #include <sys/sysctl.h>
 #include <sys/fcntl.h>
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#include <sys/exterrvar.h>
 
 #include "fuse.h"
 #include "fuse_node.h"
@@ -272,7 +274,7 @@ fuse_vfsop_fhtovp(struct mount *mp, struct fid *fhp, int 
flags,
        int error;
 
        if (!(fuse_get_mpdata(mp)->dataflags & FSESS_EXPORT_SUPPORT))
-               return EOPNOTSUPP;
+               return (EXTERROR(EOPNOTSUPP, "NFS-style lookups are not 
supported"));
 
        error = VFS_VGET(mp, ffhp->nid, LK_EXCLUSIVE, &nvp);
        if (error) {
@@ -321,11 +323,11 @@ fuse_vfsop_mount(struct mount *mp)
        opts = mp->mnt_optnew;
 
        if (!opts)
-               return EINVAL;
+               return (EXTERROR(EINVAL, "Mount options were not supplied"));
 
        /* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */
        if (!vfs_getopts(opts, "fspath", &err))
-               return err;
+               return (EXTERROR(err, "Mount options are missing 'fspath'"));
 
        /*
         * With the help of underscored options the mount program
@@ -358,11 +360,12 @@ fuse_vfsop_mount(struct mount *mp)
        /* `from' contains the device name (eg. /dev/fuse0); REQUIRED */
        fspec = vfs_getopts(opts, "from", &err);
        if (!fspec)
-               return err;
+               return (EXTERROR(err, "Mount options are missing 'from'"));
 
        /* `fd' contains the filedescriptor for this session; REQUIRED */
        if (vfs_scanopt(opts, "fd", "%d", &fd) != 1)
-               return EINVAL;
+               return (EXTERROR(EINVAL, "Mount options contain an invalid 
value "
+                   "for 'fd'"));
 
        err = fuse_getdevice(fspec, td, &fdev);
        if (err != 0)
@@ -398,11 +401,17 @@ fuse_vfsop_mount(struct mount *mp)
        /* Sanity + permission checks */
        if (!data->daemoncred)
                panic("fuse daemon found, but identity unknown");
-       if (mntopts & FSESS_DAEMON_CAN_SPY)
+       if (mntopts & FSESS_DAEMON_CAN_SPY) {
                err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER);
-       if (err == 0 && td->td_ucred->cr_uid != data->daemoncred->cr_uid)
+               EXTERROR(err, "FUSE daemon requires privileges "
+                   "due to 'allow_other' option");
+       }
+       if (err == 0 && td->td_ucred->cr_uid != data->daemoncred->cr_uid) {
                /* are we allowed to do the first mount? */
                err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER);
+               EXTERROR(err, "Mounting as a user that is different from the 
FUSE "
+                   "daemon's requires privileges");
+       }
        if (err) {
                FUSE_UNLOCK();
                goto out;
@@ -549,7 +558,7 @@ fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, 
struct vnode **vpp)
                 * nullfs mount of a fusefs file system.
                 */
                SDT_PROBE1(fusefs, , vfsops, invalidate_without_export, mp);
-               return (EOPNOTSUPP);
+               return (EXTERROR(EOPNOTSUPP, "NFS-style lookups are not 
supported"));
        }
 
        error = fuse_internal_get_cached_vnode(mp, ino, flags, vpp);
@@ -580,10 +589,10 @@ fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, 
struct vnode **vpp)
                 * Something is very wrong with the server if "foo/." has a
                 * different inode number than "foo".
                 */
-               fuse_warn(data, FSESS_WARN_DOT_LOOKUP,
-                   "Inconsistent LOOKUP response: \"FILE/.\" has a different "
-                   "inode number than \"FILE\".");
-               error = EIO;
+               static const char exterr[] = "Inconsistent LOOKUP response: "
+                   "\"FILE/.\" has a different inode number than \"FILE\".";
+               fuse_warn(data, FSESS_WARN_DOT_LOOKUP, exterr);
+               error = EXTERROR(EIO, exterr);
                goto out;
        }
 
diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h
index adb474e84c1b..d770c274d7b7 100644
--- a/sys/sys/exterr_cat.h
+++ b/sys/sys/exterr_cat.h
@@ -15,6 +15,7 @@
 #define        EXTERR_CAT_FILEDESC     2
 #define        EXTERR_KTRACE           3       /* To allow inclusion of this
                                           file into kern_ktrace.c */
+#define        EXTERR_CAT_FUSE         4
 
 #endif
 

Reply via email to