diff options
author | kib <kib@FreeBSD.org> | 2014-08-17 09:07:21 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2014-08-17 09:07:21 +0000 |
commit | 94d67906ea5fe3906f9ca6700b842d9e4d0ecb60 (patch) | |
tree | 4a98692a9f91a0bf1eb66264fa2f665692127fe0 /sys | |
parent | 75d88c0d5af7637b80b91ac5ad44544a638d5ea8 (diff) | |
download | FreeBSD-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.c | 93 | ||||
-rw-r--r-- | sys/kern/vfs_mount.c | 28 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 31 | ||||
-rw-r--r-- | sys/sys/mount.h | 6 |
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 |