diff options
author | jeff <jeff@FreeBSD.org> | 2006-02-06 10:19:50 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2006-02-06 10:19:50 +0000 |
commit | 4c912bf42a10c895b13ee13c4eb058800b35f9c4 (patch) | |
tree | 30f6eae36feb6e956e739224d6eb90e611ac8989 /sys/kern/vfs_subr.c | |
parent | 05c6b40c0d429243e6e525bbfe4fd2e75fc84a69 (diff) | |
download | FreeBSD-src-4c912bf42a10c895b13ee13c4eb058800b35f9c4.zip FreeBSD-src-4c912bf42a10c895b13ee13c4eb058800b35f9c4.tar.gz |
- Add a ref count to the mount structure. Sleep for up to 3 seconds in
vfs_mount_destroy waiting for this ref to hit 0. We don't print an
error if we are rebooting as the root mount always retains some refernces
by init proc.
- Acquire a mnt ref for every vnode allocated to a mount point. Drop this
ref only once vdestroy() has been called and the mount has been freed.
- No longer NULL the v_mount pointer in delmntque() so that we may release
the ref after vgone() has been called. This allows us to guarantee
that the mount point structure will be valid until the last vnode has
lost its last ref.
- Fix a few places that rely on checking v_mount to detect recycling.
Sponsored by: Isilon Systems, Inc.
MFC After: 1 week
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index ca85214..5017c72 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -785,6 +785,8 @@ vdestroy(struct vnode *vp) mtx_destroy(&vp->v_pollinfo->vpi_lock); uma_zfree(vnodepoll_zone, vp->v_pollinfo); } + if (vp->v_mount) + vfs_rel(vp->v_mount); #ifdef INVARIANTS /* XXX Elsewhere we can detect an already freed vnode via NULL v_op. */ vp->v_op = NULL; @@ -918,7 +920,6 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, else if (mp == NULL) printf("NULL mp in getnewvnode()\n"); #endif - delmntque(vp); if (mp != NULL) { insmntque(vp, mp); bo->bo_bsize = mp->mnt_stat.f_iosize; @@ -939,15 +940,15 @@ delmntque(struct vnode *vp) { struct mount *mp; - if (vp->v_mount == NULL) - return; mp = vp->v_mount; + if (mp == NULL) + return; MNT_ILOCK(mp); - vp->v_mount = NULL; VNASSERT(mp->mnt_nvnodelistsize > 0, vp, ("bad mount point vnode list size")); TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); mp->mnt_nvnodelistsize--; + /* mnt ref is released in vdestroy. */ MNT_IUNLOCK(mp); } @@ -960,12 +961,13 @@ insmntque(struct vnode *vp, struct mount *mp) vp->v_mount = mp; VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)")); - MNT_ILOCK(vp->v_mount); + MNT_ILOCK(mp); + MNT_REF(mp); TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes); VNASSERT(mp->mnt_nvnodelistsize >= 0, vp, ("neg mount point vnode list size")); mp->mnt_nvnodelistsize++; - MNT_IUNLOCK(vp->v_mount); + MNT_IUNLOCK(mp); } /* |