The branch main has been updated by kevans:

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

commit 65059dd2b6f94e570acc645be82b8ea056316459
Author:     Kyle Evans <kev...@freebsd.org>
AuthorDate: 2025-09-04 02:08:52 +0000
Commit:     Kyle Evans <kev...@freebsd.org>
CommitDate: 2025-09-04 02:08:52 +0000

    pseudofs: defer initialization until first mount
    
    Currently, pseudofs all get fully constructed when the module is loaded
    and vfs registered, but this is pretty unnecessary.  Just loading the
    fs doesn't mean that it will be used so we're adding overhead and
    risk[0] by fully initializing these at the start, along with committing
    resources that may not be used.
    
    Deferring pfs_init() allows us to reduce the risk of simply loading the
    module causing problems that are harder to avoid, and existing pseudo
    filesystems don't really care: configuration that is context-sensitive
    is generally deferred to access-time with PFS_PROCDEP.
    
    To preserve symmetry, we'll also teardown our pseudofs on last unmount,
    which leaves us with a vfs_uninit() implementation that simply destroys
    our lock and prints a message.
    
    [0] Example of such being recent bugs in linsysfs, which caused a panic
    as soon as the module was loaded because we're eager to set it up.
    
    Reviewed by:    des (previous version), kib
    Differential Revision:  https://reviews.freebsd.org/D52156
---
 sys/fs/pseudofs/pseudofs.c    | 71 ++++++++++++++++++++++++++++++++++++++-----
 sys/fs/pseudofs/pseudofs.h    | 33 +++++++++++---------
 sys/modules/pseudofs/Makefile |  4 +--
 3 files changed, 84 insertions(+), 24 deletions(-)

diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c
index efeeb57e6448..20cb87c6c6d5 100644
--- a/sys/fs/pseudofs/pseudofs.c
+++ b/sys/fs/pseudofs/pseudofs.c
@@ -40,13 +40,18 @@
 #include <sys/mount.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
+#include <sys/refcount.h>
 #include <sys/sbuf.h>
+#include <sys/sx.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 
 #include <fs/pseudofs/pseudofs.h>
 #include <fs/pseudofs/pseudofs_internal.h>
 
+static int pfs_setup(struct pfs_info *pi, struct vfsconf *vfc);
+static int pfs_teardown(struct pfs_info *pi, struct vfsconf *vfc);
+
 static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
 
 SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
@@ -382,10 +387,20 @@ int
 pfs_mount(struct pfs_info *pi, struct mount *mp)
 {
        struct statfs *sbp;
+       int error = 0;
 
        if (mp->mnt_flag & MNT_UPDATE)
                return (EOPNOTSUPP);
 
+       sx_xlock(&pi->pi_mountlock);
+       if (pi->pi_root == NULL)
+               error = pfs_setup(pi, mp->mnt_vfc);
+       if (error == 0)
+               refcount_acquire(&pi->pi_mounts);
+       sx_xunlock(&pi->pi_mountlock);
+       if (error != 0)
+               return (error);
+
        MNT_ILOCK(mp);
        mp->mnt_flag |= MNT_LOCAL;
        mp->mnt_kern_flag |= MNTK_NOMSYNC;
@@ -424,10 +439,23 @@ pfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
 int
 pfs_unmount(struct mount *mp, int mntflags)
 {
+       struct pfs_info *pi;
        int error;
 
        error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0,
            curthread);
+       if (error != 0)
+               return (error);
+
+       pi = (struct pfs_info *)mp->mnt_data;
+       sx_xlock(&pi->pi_mountlock);
+       if (!refcount_release_if_not_last(&pi->pi_mounts)) {
+               error = pfs_teardown(pi, mp->mnt_vfc);
+               if (error == 0)
+                       refcount_release(&pi->pi_mounts);
+       }
+       sx_xunlock(&pi->pi_mountlock);
+
        return (error);
 }
 
@@ -454,10 +482,35 @@ pfs_statfs(struct mount *mp, struct statfs *sbp)
 }
 
 /*
- * Initialize a pseudofs instance
+ * Initialize pseudofs synchronization bits.  These will generally be needed
+ * in order to avoid problems with parallel mounting of pseudofs consumers.
  */
 int
-pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
+pfs_vfsinit(struct pfs_info *pi, struct vfsconf *vfc)
+{
+
+       sx_init(&pi->pi_mountlock, "pfs mountlock");
+       refcount_init(&pi->pi_mounts, 0);
+       return (0);
+}
+
+int
+pfs_vfsuninit(struct pfs_info *pi, struct vfsconf *vfc)
+{
+
+       MPASS(pi->pi_root == NULL);
+       sx_destroy(&pi->pi_mountlock);
+
+       if (bootverbose)
+               printf("%s unregistered\n", pi->pi_name);
+       return (0);
+}
+
+/*
+ * Initialize a pseudofs instance
+ */
+static int
+pfs_setup(struct pfs_info *pi, struct vfsconf *vfc)
 {
        struct pfs_node *root;
        int error;
@@ -487,18 +540,20 @@ pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
 /*
  * Destroy a pseudofs instance
  */
-int
-pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
+static int
+pfs_teardown(struct pfs_info *pi, struct vfsconf *vfc)
 {
        int error;
 
+       MPASS(pi->pi_root != NULL);
+       error = (pi->pi_uninit)(pi, vfc);
+       if (error != 0)
+               return (error);
+
        pfs_destroy(pi->pi_root);
        pi->pi_root = NULL;
        pfs_fileno_uninit(pi);
-       if (bootverbose)
-               printf("%s unregistered\n", pi->pi_name);
-       error = (pi->pi_uninit)(pi, vfc);
-       return (error);
+       return (0);
 }
 
 /*
diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h
index c60dd7b339d1..461a1d2402e4 100644
--- a/sys/fs/pseudofs/pseudofs.h
+++ b/sys/fs/pseudofs/pseudofs.h
@@ -31,6 +31,7 @@
 #ifndef _PSEUDOFS_H_INCLUDED
 #define _PSEUDOFS_H_INCLUDED
 
+#include <sys/_sx.h>
 #include <sys/jail.h>
 
 /*
@@ -188,9 +189,11 @@ typedef int (*pfs_destroy_t)(PFS_DESTROY_ARGS);
 /*
  * pfs_info: describes a pseudofs instance
  *
- * The pi_mutex is only used to avoid using the global subr_unit lock
- * for unrhdr.  The rest of struct pfs_info is only modified during
- * vfs_init() and vfs_uninit() of the consumer filesystem.
+ * The pi_mutex is used to avoid using the global subr_unit lock for unrhdr, 
and
+ * the pi_mountlock is used to coordinate initialization of the consumer
+ * filesystem on first mount.  The rest of struct pfs_info is only modified
+ * during pi_init() and pi_uninit() of the consumer filesystem, which are fully
+ * serialized.
  */
 struct pfs_info {
        char                     pi_name[PFS_FSNAMELEN];
@@ -198,9 +201,11 @@ struct pfs_info {
        pfs_init_t               pi_uninit;
 
        /* members below this line are initialized at run time */
+       struct sx                pi_mountlock;
        struct pfs_node         *pi_root;
        struct mtx               pi_mutex;
        struct unrhdr           *pi_unrhdr;
+       u_int                    pi_mounts;
 };
 
 /*
@@ -249,8 +254,8 @@ int          pfs_unmount    (struct mount *mp, int 
mntflags);
 int             pfs_root       (struct mount *mp, int flags,
                                 struct vnode **vpp);
 int             pfs_statfs     (struct mount *mp, struct statfs *sbp);
-int             pfs_init       (struct pfs_info *pi, struct vfsconf *vfc);
-int             pfs_uninit     (struct pfs_info *pi, struct vfsconf *vfc);
+int             pfs_vfsinit    (struct pfs_info *pi, struct vfsconf *vfc);
+int             pfs_vfsuninit  (struct pfs_info *pi, struct vfsconf *vfc);
 
 /*
  * Directory structure construction and manipulation
@@ -276,9 +281,9 @@ int          pfs_destroy    (struct pfs_node *pn);
 #define PSEUDOFS(name, version, flags)                                 \
                                                                        \
 static struct pfs_info name##_info = {                                 \
-       #name,                                                          \
-       name##_init,                                                    \
-       name##_uninit,                                                  \
+       .pi_name = #name,                                               \
+       .pi_init = name##_init,                                         \
+       .pi_uninit = name##_uninit,                                     \
 };                                                                     \
                                                                        \
 static int                                                             \
@@ -287,22 +292,22 @@ _##name##_mount(struct mount *mp) {                       
                \
 }                                                                      \
                                                                        \
 static int                                                             \
-_##name##_init(struct vfsconf *vfc) {                                  \
-       return (pfs_init(&name##_info, vfc));                           \
+_##name##_vfsinit(struct vfsconf *vfc) {                               \
+       return (pfs_vfsinit(&name##_info, vfc));                        \
 }                                                                      \
                                                                        \
 static int                                                             \
-_##name##_uninit(struct vfsconf *vfc) {                                        
\
-       return (pfs_uninit(&name##_info, vfc));                         \
+_##name##_vfsuninit(struct vfsconf *vfc) {                             \
+       return (pfs_vfsuninit(&name##_info, vfc));                      \
 }                                                                      \
                                                                        \
 static struct vfsops name##_vfsops = {                                 \
        .vfs_cmount =           pfs_cmount,                             \
-       .vfs_init =             _##name##_init,                         \
+       .vfs_init =             _##name##_vfsinit,                      \
        .vfs_mount =            _##name##_mount,                        \
        .vfs_root =             pfs_root,                               \
        .vfs_statfs =           pfs_statfs,                             \
-       .vfs_uninit =           _##name##_uninit,                       \
+       .vfs_uninit =           _##name##_vfsuninit,                    \
        .vfs_unmount =          pfs_unmount,                            \
 };                                                                     \
 VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC | flags);                  \
diff --git a/sys/modules/pseudofs/Makefile b/sys/modules/pseudofs/Makefile
index cb92b8912c86..3928c950ab70 100644
--- a/sys/modules/pseudofs/Makefile
+++ b/sys/modules/pseudofs/Makefile
@@ -13,8 +13,8 @@ EXPORT_SYMS=  pfs_cmount      \
                pfs_unmount     \
                pfs_root        \
                pfs_statfs      \
-               pfs_init        \
-               pfs_uninit      \
+               pfs_vfsinit     \
+               pfs_vfsuninit   \
                pfs_create_dir  \
                pfs_create_file \
                pfs_create_link \

Reply via email to