summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-08-17 09:07:21 +0000
committerkib <kib@FreeBSD.org>2014-08-17 09:07:21 +0000
commit94d67906ea5fe3906f9ca6700b842d9e4d0ecb60 (patch)
tree4a98692a9f91a0bf1eb66264fa2f665692127fe0 /sys
parent75d88c0d5af7637b80b91ac5ad44544a638d5ea8 (diff)
downloadFreeBSD-src-94d67906ea5fe3906f9ca6700b842d9e4d0ecb60.zip
FreeBSD-src-94d67906ea5fe3906f9ca6700b842d9e4d0ecb60.tar.gz
MFC r269457:
Remove Giant acquisition from the mount and unmount pathes.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_init.c93
-rw-r--r--sys/kern/vfs_mount.c28
-rw-r--r--sys/kern/vfs_subr.c31
-rw-r--r--sys/sys/mount.h6
4 files changed, 93 insertions, 65 deletions
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index eab48fb..dd21743 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/mount.h>
#include <sys/proc.h>
+#include <sys/sx.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
@@ -64,6 +65,8 @@ int maxvfsconf = VFS_GENERIC + 1;
* New entries are added/deleted by vfs_register()/vfs_unregister()
*/
struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf);
+struct sx vfsconf_sx;
+SX_SYSINIT(vfsconf, &vfsconf_sx, "vfsconf");
/*
* Loader.conf variable vfs.typenumhash enables setting vfc_typenum using a hash
@@ -105,20 +108,33 @@ struct vattr va_null;
* Routines having to do with the management of the vnode table.
*/
-struct vfsconf *
-vfs_byname(const char *name)
+static struct vfsconf *
+vfs_byname_locked(const char *name)
{
struct vfsconf *vfsp;
+ sx_assert(&vfsconf_sx, SA_LOCKED);
if (!strcmp(name, "ffs"))
name = "ufs";
- TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
+ TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
if (!strcmp(name, vfsp->vfc_name))
return (vfsp);
+ }
return (NULL);
}
struct vfsconf *
+vfs_byname(const char *name)
+{
+ struct vfsconf *vfsp;
+
+ vfsconf_slock();
+ vfsp = vfs_byname_locked(name);
+ vfsconf_sunlock();
+ return (vfsp);
+}
+
+struct vfsconf *
vfs_byname_kld(const char *fstype, struct thread *td, int *error)
{
struct vfsconf *vfsp;
@@ -169,8 +185,11 @@ vfs_register(struct vfsconf *vfc)
vfc->vfc_name, vfc->vfc_version);
return (EINVAL);
}
- if (vfs_byname(vfc->vfc_name) != NULL)
+ vfsconf_lock();
+ if (vfs_byname_locked(vfc->vfc_name) != NULL) {
+ vfsconf_unlock();
return (EEXIST);
+ }
if (vfs_typenumhash != 0) {
/*
@@ -203,26 +222,6 @@ vfs_register(struct vfsconf *vfc)
TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);
/*
- * If this filesystem has a sysctl node under vfs
- * (i.e. vfs.xxfs), then change the oid number of that node to
- * match the filesystem's type number. This allows user code
- * which uses the type number to read sysctl variables defined
- * by the filesystem to continue working. Since the oids are
- * in a sorted list, we need to make sure the order is
- * preserved by re-registering the oid after modifying its
- * number.
- */
- sysctl_lock();
- SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
- if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
- sysctl_unregister_oid(oidp);
- oidp->oid_number = vfc->vfc_typenum;
- sysctl_register_oid(oidp);
- break;
- }
- sysctl_unlock();
-
- /*
* Initialise unused ``struct vfsops'' fields, to use
* the vfs_std*() functions. Note, we need the mount
* and unmount operations, at the least. The check
@@ -281,8 +280,30 @@ vfs_register(struct vfsconf *vfc)
* Call init function for this VFS...
*/
(*(vfc->vfc_vfsops->vfs_init))(vfc);
+ vfsconf_unlock();
- return 0;
+ /*
+ * If this filesystem has a sysctl node under vfs
+ * (i.e. vfs.xxfs), then change the oid number of that node to
+ * match the filesystem's type number. This allows user code
+ * which uses the type number to read sysctl variables defined
+ * by the filesystem to continue working. Since the oids are
+ * in a sorted list, we need to make sure the order is
+ * preserved by re-registering the oid after modifying its
+ * number.
+ */
+ sysctl_lock();
+ SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) {
+ if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
+ sysctl_unregister_oid(oidp);
+ oidp->oid_number = vfc->vfc_typenum;
+ sysctl_register_oid(oidp);
+ break;
+ }
+ }
+ sysctl_unlock();
+
+ return (0);
}
@@ -295,15 +316,22 @@ vfs_unregister(struct vfsconf *vfc)
i = vfc->vfc_typenum;
- vfsp = vfs_byname(vfc->vfc_name);
- if (vfsp == NULL)
- return EINVAL;
- if (vfsp->vfc_refcount)
- return EBUSY;
+ vfsconf_lock();
+ vfsp = vfs_byname_locked(vfc->vfc_name);
+ if (vfsp == NULL) {
+ vfsconf_unlock();
+ return (EINVAL);
+ }
+ if (vfsp->vfc_refcount != 0) {
+ vfsconf_unlock();
+ return (EBUSY);
+ }
if (vfc->vfc_vfsops->vfs_uninit != NULL) {
error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
- if (error)
+ if (error != 0) {
+ vfsconf_unlock();
return (error);
+ }
}
TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
maxtypenum = VFS_GENERIC;
@@ -311,7 +339,8 @@ vfs_unregister(struct vfsconf *vfc)
if (maxtypenum < vfsp->vfc_typenum)
maxtypenum = vfsp->vfc_typenum;
maxvfsconf = maxtypenum + 1;
- return 0;
+ vfsconf_unlock();
+ return (0);
}
/*
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 8b764f7..674e526 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -463,9 +463,9 @@ vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, const char *fspath,
mp->mnt_activevnodelistsize = 0;
mp->mnt_ref = 0;
(void) vfs_busy(mp, MBF_NOWAIT);
+ atomic_add_acq_int(&vfsp->vfc_refcount, 1);
mp->mnt_op = vfsp->vfc_vfsops;
mp->mnt_vfc = vfsp;
- vfsp->vfc_refcount++; /* XXX Unlocked */
mp->mnt_stat.f_type = vfsp->vfc_typenum;
mp->mnt_gen++;
strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
@@ -505,7 +505,7 @@ vfs_mount_destroy(struct mount *mp)
panic("vfs_mount_destroy: nonzero writeopcount");
if (mp->mnt_secondary_writes != 0)
panic("vfs_mount_destroy: nonzero secondary_writes");
- mp->mnt_vfc->vfc_refcount--;
+ atomic_subtract_rel_int(&mp->mnt_vfc->vfc_refcount, 1);
if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) {
struct vnode *vp;
@@ -736,17 +736,12 @@ sys_mount(td, uap)
}
AUDIT_ARG_TEXT(fstype);
- mtx_lock(&Giant);
vfsp = vfs_byname_kld(fstype, td, &error);
free(fstype, M_TEMP);
- if (vfsp == NULL) {
- mtx_unlock(&Giant);
+ if (vfsp == NULL)
return (ENOENT);
- }
- if (vfsp->vfc_vfsops->vfs_cmount == NULL) {
- mtx_unlock(&Giant);
+ if (vfsp->vfc_vfsops->vfs_cmount == NULL)
return (EOPNOTSUPP);
- }
ma = mount_argsu(ma, "fstype", uap->type, MFSNAMELEN);
ma = mount_argsu(ma, "fspath", uap->path, MNAMELEN);
@@ -755,7 +750,6 @@ sys_mount(td, uap)
ma = mount_argb(ma, !(flags & MNT_NOEXEC), "noexec");
error = vfsp->vfc_vfsops->vfs_cmount(ma, uap->data, flags);
- mtx_unlock(&Giant);
return (error);
}
@@ -777,7 +771,6 @@ vfs_domount_first(
struct vnode *newdp;
int error;
- mtx_assert(&Giant, MA_OWNED);
ASSERT_VOP_ELOCKED(vp, __func__);
KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
@@ -889,7 +882,6 @@ vfs_domount_update(
int error, export_error;
uint64_t flag;
- mtx_assert(&Giant, MA_OWNED);
ASSERT_VOP_ELOCKED(vp, __func__);
KASSERT((fsflags & MNT_UPDATE) != 0, ("MNT_UPDATE should be here"));
@@ -1091,7 +1083,6 @@ vfs_domount(
error = namei(&nd);
if (error != 0)
return (error);
- mtx_lock(&Giant);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if ((fsflags & MNT_UPDATE) == 0) {
@@ -1106,7 +1097,6 @@ vfs_domount(
free(pathbuf, M_TEMP);
} else
error = vfs_domount_update(td, vp, fsflags, optlist);
- mtx_unlock(&Giant);
ASSERT_VI_UNLOCKED(vp, __func__);
ASSERT_VOP_UNLOCKED(vp, __func__);
@@ -1153,12 +1143,10 @@ sys_unmount(td, uap)
free(pathbuf, M_TEMP);
return (error);
}
- mtx_lock(&Giant);
if (uap->flags & MNT_BYFSID) {
AUDIT_ARG_TEXT(pathbuf);
/* Decode the filesystem ID. */
if (sscanf(pathbuf, "FSID:%d:%d", &id0, &id1) != 2) {
- mtx_unlock(&Giant);
free(pathbuf, M_TEMP);
return (EINVAL);
}
@@ -1198,19 +1186,15 @@ sys_unmount(td, uap)
* now, so in the !MNT_BYFSID case return the more likely
* EINVAL for compatibility.
*/
- mtx_unlock(&Giant);
return ((uap->flags & MNT_BYFSID) ? ENOENT : EINVAL);
}
/*
* Don't allow unmounting the root filesystem.
*/
- if (mp->mnt_flag & MNT_ROOTFS) {
- mtx_unlock(&Giant);
+ if (mp->mnt_flag & MNT_ROOTFS)
return (EINVAL);
- }
error = dounmount(mp, uap->flags, td);
- mtx_unlock(&Giant);
return (error);
}
@@ -1228,8 +1212,6 @@ dounmount(mp, flags, td)
uint64_t async_flag;
int mnt_gen_r;
- mtx_assert(&Giant, MA_OWNED);
-
if ((coveredvp = mp->mnt_vnodecovered) != NULL) {
mnt_gen_r = mp->mnt_gen;
VI_LOCK(coveredvp);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9f34eda..9c90fe5 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3231,6 +3231,7 @@ sysctl_vfs_conflist(SYSCTL_HANDLER_ARGS)
int error;
error = 0;
+ vfsconf_slock();
TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
#ifdef COMPAT_FREEBSD32
if (req->flags & SCTL_MASK32)
@@ -3241,11 +3242,12 @@ sysctl_vfs_conflist(SYSCTL_HANDLER_ARGS)
if (error)
break;
}
+ vfsconf_sunlock();
return (error);
}
-SYSCTL_PROC(_vfs, OID_AUTO, conflist, CTLTYPE_OPAQUE | CTLFLAG_RD,
- NULL, 0, sysctl_vfs_conflist,
+SYSCTL_PROC(_vfs, OID_AUTO, conflist, CTLTYPE_OPAQUE | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, NULL, 0, sysctl_vfs_conflist,
"S,xvfsconf", "List of all configured filesystems");
#ifndef BURN_BRIDGES
@@ -3275,9 +3277,12 @@ vfs_sysctl(SYSCTL_HANDLER_ARGS)
case VFS_CONF:
if (namelen != 3)
return (ENOTDIR); /* overloaded */
- TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
+ vfsconf_slock();
+ TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
if (vfsp->vfc_typenum == name[2])
break;
+ }
+ vfsconf_sunlock();
if (vfsp == NULL)
return (EOPNOTSUPP);
#ifdef COMPAT_FREEBSD32
@@ -3290,8 +3295,9 @@ vfs_sysctl(SYSCTL_HANDLER_ARGS)
return (EOPNOTSUPP);
}
-static SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD | CTLFLAG_SKIP,
- vfs_sysctl, "Generic filesystem");
+static SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD | CTLFLAG_SKIP |
+ CTLFLAG_MPSAFE, vfs_sysctl,
+ "Generic filesystem");
#if 1 || defined(COMPAT_PRELITE2)
@@ -3302,6 +3308,7 @@ sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS)
struct vfsconf *vfsp;
struct ovfsconf ovfs;
+ vfsconf_slock();
TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
bzero(&ovfs, sizeof(ovfs));
ovfs.vfc_vfsops = vfsp->vfc_vfsops; /* XXX used as flag */
@@ -3310,10 +3317,13 @@ sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS)
ovfs.vfc_refcount = vfsp->vfc_refcount;
ovfs.vfc_flags = vfsp->vfc_flags;
error = SYSCTL_OUT(req, &ovfs, sizeof ovfs);
- if (error)
- return error;
+ if (error != 0) {
+ vfsconf_sunlock();
+ return (error);
+ }
}
- return 0;
+ vfsconf_sunlock();
+ return (0);
}
#endif /* 1 || COMPAT_PRELITE2 */
@@ -3411,8 +3421,9 @@ sysctl_vnode(SYSCTL_HANDLER_ARGS)
return (error);
}
-SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD,
- 0, 0, sysctl_vnode, "S,xvnode", "");
+SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, 0, 0, sysctl_vnode, "S,xvnode",
+ "");
#endif
/*
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index b9e9336..e0c2696 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -39,6 +39,7 @@
#include <sys/lock.h>
#include <sys/lockmgr.h>
#include <sys/_mutex.h>
+#include <sys/_sx.h>
#endif
/*
@@ -891,6 +892,11 @@ void vfs_unmountall(void);
extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */
extern struct mtx mountlist_mtx;
extern struct nfs_public nfs_pub;
+extern struct sx vfsconf_sx;
+#define vfsconf_lock() sx_xlock(&vfsconf_sx)
+#define vfsconf_unlock() sx_xunlock(&vfsconf_sx)
+#define vfsconf_slock() sx_slock(&vfsconf_sx)
+#define vfsconf_sunlock() sx_sunlock(&vfsconf_sx)
/*
* Declarations for these vfs default operations are located in
OpenPOWER on IntegriCloud