diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h --- 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 #include /* @@ -189,8 +190,9 @@ * 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. + * for unrhdr, and the pi_mountlock is used to coordinate initialization of the + * consumer filesystem on first ount. The rest of struct pfs_info is only + * modified during pi_init() and pi_uninit() of the consumer filesystem. */ struct pfs_info { char pi_name[PFS_FSNAMELEN]; @@ -198,6 +200,7 @@ 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; @@ -249,7 +252,7 @@ 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_vfsinit (struct pfs_info *pi, struct vfsconf *vfc); int pfs_uninit (struct pfs_info *pi, struct vfsconf *vfc); /* @@ -276,9 +279,9 @@ #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,8 +290,8 @@ } \ \ 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 \ @@ -298,7 +301,7 @@ \ 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, \ diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c --- a/sys/fs/pseudofs/pseudofs.c +++ b/sys/fs/pseudofs/pseudofs.c @@ -41,12 +41,15 @@ #include #include #include +#include #include #include #include #include +static int pfs_init(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 +385,18 @@ 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_init(pi, mp->mnt_vfc); + sx_xunlock(&pi->pi_mountlock); + if (error != 0) + return (error); + MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_NOMSYNC; @@ -454,9 +465,21 @@ } /* - * 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_vfsinit(struct pfs_info *pi, struct vfsconf *vfc) +{ + + sx_init(&pi->pi_mountlock, "pfs mountlock"); + return (0); +} + +/* + * Initialize a pseudofs instance + */ +static int pfs_init(struct pfs_info *pi, struct vfsconf *vfc) { struct pfs_node *root; @@ -490,15 +513,21 @@ int pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc) { - int error; + if (pi->pi_root != NULL) { + int error; + + error = (pi->pi_uninit)(pi, vfc); + if (error != 0) + return (error); + + pfs_destroy(pi->pi_root); + pi->pi_root = NULL; + pfs_fileno_uninit(pi); + } - 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/modules/pseudofs/Makefile b/sys/modules/pseudofs/Makefile --- a/sys/modules/pseudofs/Makefile +++ b/sys/modules/pseudofs/Makefile @@ -13,7 +13,7 @@ pfs_unmount \ pfs_root \ pfs_statfs \ - pfs_init \ + pfs_vfsinit \ pfs_uninit \ pfs_create_dir \ pfs_create_file \