aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Roberson <jeff@FreeBSD.org>2006-03-31 03:49:51 +0000
committerJeff Roberson <jeff@FreeBSD.org>2006-03-31 03:49:51 +0000
commita218edceb2c1b61bc08673c7ae507f17db6c7090 (patch)
tree09c74a5ac848d059408d1f2e437cc419538c296c
parent9eee260594ce17b91214e914f85fde916ee744e5 (diff)
downloadsrc-a218edceb2c1b61bc08673c7ae507f17db6c7090.tar.gz
src-a218edceb2c1b61bc08673c7ae507f17db6c7090.zip
- Allocate mounts from a uma zone that uses UMA_ZONE_NOFREE to prevent
mount memory from being reclaimed. This resolves a number of race conditions described in vfs_default.c and introduced with the VFS_LOCK_GIANT macros. - Let the mtx and lock remain valid after the mount structure has been freed by using init and fini calls. Technically fini will never be called but is included for completeness. - Consistently use lockmgr directly rather than lockmgr to lock and vfs_unbusy to unlock. Discussed with: tegge Tested by: kris Sponsored by: Isilon Systems, Inc.
Notes
Notes: svn path=/head/; revision=157322
-rw-r--r--sys/kern/vfs_mount.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 61aafb3b8093..117df18617c5 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysent.h>
#include <sys/systm.h>
#include <sys/vnode.h>
+#include <vm/uma.h>
#include <geom/geom.h>
@@ -91,6 +92,7 @@ SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0,
MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
MALLOC_DEFINE(M_VNODE_MARKER, "vnodemarker", "vnode marker");
+static uma_zone_t mount_zone;
/* List of mounted filesystems. */
struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist);
@@ -423,6 +425,27 @@ vfs_rel(struct mount *mp)
MNT_IUNLOCK(mp);
}
+static int
+mount_init(void *mem, int size, int flags)
+{
+ struct mount *mp;
+
+ mp = (struct mount *)mem;
+ mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
+ lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
+ return (0);
+}
+
+static void
+mount_fini(void *mem, int size)
+{
+ struct mount *mp;
+
+ mp = (struct mount *)mem;
+ lockdestroy(&mp->mnt_lock);
+ mtx_destroy(&mp->mnt_mtx);
+}
+
/*
* Allocate and initialize the mount point struct.
*/
@@ -432,13 +455,13 @@ vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp,
{
struct mount *mp;
- mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
+ mp = uma_zalloc(mount_zone, M_WAITOK);
+ bzero(&mp->mnt_startzero,
+ __rangeof(struct mount, mnt_startzero, mnt_endzero));
TAILQ_INIT(&mp->mnt_nvnodelist);
mp->mnt_nvnodelistsize = 0;
- mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
- lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
- (void) vfs_busy(mp, LK_NOWAIT, 0, td);
mp->mnt_ref = 0;
+ (void) vfs_busy(mp, LK_NOWAIT, 0, td);
mp->mnt_op = vfsp->vfc_vfsops;
mp->mnt_vfc = vfsp;
vfsp->vfc_refcount++; /* XXX Unlocked */
@@ -466,7 +489,7 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
{
int i;
- vfs_unbusy(mp, td);
+ lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, td);
MNT_ILOCK(mp);
for (i = 0; mp->mnt_ref && i < 3; i++)
msleep(mp, MNT_MTX(mp), PVFS, "mntref", hz);
@@ -512,7 +535,6 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
mp->mnt_vfc->vfc_refcount--;
if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
panic("unmount: dangling vnode");
- lockdestroy(&mp->mnt_lock);
MNT_ILOCK(mp);
if (mp->mnt_kern_flag & MNTK_MWAIT)
wakeup(mp);
@@ -526,14 +548,13 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
mp->mnt_nvnodelistsize = -1000;
mp->mnt_secondary_writes = -1000;
MNT_IUNLOCK(mp);
- mtx_destroy(&mp->mnt_mtx);
#ifdef MAC
mac_destroy_mount(mp);
#endif
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
crfree(mp->mnt_cred);
- free(mp, M_MOUNT);
+ uma_zfree(mount_zone, mp);
}
static int
@@ -1375,6 +1396,9 @@ vfs_mountroot(void)
root_mount_wait();
+ mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount),
+ NULL, NULL, mount_init, mount_fini,
+ UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
devfs_first();
/*