Page MenuHomeFreeBSD

D52156.id160975.diff
No OneTemporary

D52156.id160975.diff

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 <sys/_blockcount.h>
#include <sys/jail.h>
/*
@@ -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 to safely manage parallel mounting in conjunction with the
+ * pi_busy count. 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];
@@ -201,6 +203,7 @@
struct pfs_node *pi_root;
struct mtx pi_mutex;
struct unrhdr *pi_unrhdr;
+ blockcount_t pi_busy;
};
/*
@@ -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
@@ -32,6 +32,7 @@
#include "opt_pseudofs.h"
#include <sys/param.h>
+#include <sys/blockcount.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -47,8 +48,14 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/pseudofs/pseudofs_internal.h>
+static int pfs_init(struct pfs_info *pi, struct vfsconf *vfc);
+
static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
+#define PFS_INFO_LOCK(pi) mtx_lock(&(pi)->pi_mutex)
+#define PFS_INFO_UNLOCK(pi) mtx_unlock(&(pi)->pi_mutex)
+#define PFS_INFO_LOCK_ASSERT(pi) mtx_assert(&(pi)->pi_mutex, MA_OWNED)
+
SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"pseudofs");
@@ -375,6 +382,36 @@
return (0);
}
+static void
+pfs_busy(struct pfs_info *pi)
+{
+ PFS_INFO_LOCK_ASSERT(pi);
+
+ blockcount_acquire(&pi->pi_busy, 1);
+}
+
+static bool
+pfs_busied(const struct pfs_info *pi)
+{
+ return (blockcount_read(&pi->pi_busy) != 0);
+}
+
+static void
+pfs_unbusy(struct pfs_info *pi)
+{
+
+ blockcount_release(&pi->pi_busy, 1);
+}
+
+static void
+pfs_busy_wait(struct pfs_info *pi, const char *wmesg)
+{
+ PFS_INFO_LOCK_ASSERT(pi);
+
+ (void)blockcount_sleep(&pi->pi_busy, &pi->pi_mutex.lock_object,
+ wmesg, 0);
+}
+
/*
* Mount a pseudofs instance
*/
@@ -382,10 +419,38 @@
pfs_mount(struct pfs_info *pi, struct mount *mp)
{
struct statfs *sbp;
+ int error;
if (mp->mnt_flag & MNT_UPDATE)
return (EOPNOTSUPP);
+ PFS_INFO_LOCK(pi);
+
+ /*
+ * pfs_init() happens outside of the pfs_info lock because many of our
+ * consumer filesystems currently assume they can sleep, so we must wait
+ * until the busy count drops after they've finished to proceed.
+ *
+ * The acquire fence is intended to synchronize with the fence in
+ * blockcount_release(), since blockcount_read() would not. If we
+ * _are_ busy, then blockcount_sleep() will provide appropriate
+ * barriers.
+ */
+ if (pfs_busied(pi))
+ pfs_busy_wait(pi, "pfsmnt");
+ else
+ atomic_thread_fence_acq();
+ if (pi->pi_root == NULL) {
+ pfs_busy(pi);
+ PFS_INFO_UNLOCK(pi);
+ error = pfs_init(pi, mp->mnt_vfc);
+ pfs_unbusy(pi);
+ if (error != 0)
+ return (error);
+ } else {
+ PFS_INFO_UNLOCK(pi);
+ }
+
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_kern_flag |= MNTK_NOMSYNC;
@@ -454,9 +519,22 @@
}
/*
- * 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)
+{
+
+ mtx_init(&pi->pi_mutex, "pfs_info", NULL, MTX_DEF);
+ blockcount_init(&pi->pi_busy);
+ return (0);
+}
+
+/*
+ * Initialize a pseudofs instance
+ */
+static int
pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
{
struct pfs_node *root;
@@ -490,15 +568,22 @@
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);
+ mtx_destroy(&pi->pi_mutex);
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_fileno.c b/sys/fs/pseudofs/pseudofs_fileno.c
--- a/sys/fs/pseudofs/pseudofs_fileno.c
+++ b/sys/fs/pseudofs/pseudofs_fileno.c
@@ -52,7 +52,6 @@
pfs_fileno_init(struct pfs_info *pi)
{
- mtx_init(&pi->pi_mutex, "pfs_fileno", NULL, MTX_DEF);
pi->pi_unrhdr = new_unrhdr(3, INT_MAX / NO_PID, &pi->pi_mutex);
}
@@ -65,7 +64,6 @@
delete_unrhdr(pi->pi_unrhdr);
pi->pi_unrhdr = NULL;
- mtx_destroy(&pi->pi_mutex);
}
/*
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 \
diff --git a/sys/sys/_blockcount.h b/sys/sys/_blockcount.h
--- a/sys/sys/_blockcount.h
+++ b/sys/sys/_blockcount.h
@@ -42,7 +42,7 @@
#define _BLOCKCOUNT_WAITERS(c) (((c) & _BLOCKCOUNT_WAITERS_FLAG) != 0)
static inline unsigned int
-blockcount_read(blockcount_t *count)
+blockcount_read(const blockcount_t *count)
{
return (_BLOCKCOUNT_COUNT(atomic_load_int(&count->__count)));
}

File Metadata

Mime Type
text/plain
Expires
Thu, Aug 6, 8:51 AM (16 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36106517
Default Alt Text
D52156.id160975.diff (6 KB)

Event Timeline