Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F165020941
D52156.id160975.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D52156.id160975.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D52156: pseudofs: defer initialization until first mount
Attached
Detach File
Event Timeline
Log In to Comment