aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Egge <tegge@FreeBSD.org>2007-03-13 01:50:27 +0000
committerTor Egge <tegge@FreeBSD.org>2007-03-13 01:50:27 +0000
commit61b9d89ff0a7d4c7bcea7fd083db918e16de41a5 (patch)
tree6dca3f2c99e6dcb6402e1486118e56eb8d5e871b
parent06e83c7e86824a2bf64e797dca3cf56e60ac3e85 (diff)
downloadsrc-61b9d89ff0a7d4c7bcea7fd083db918e16de41a5.tar.gz
src-61b9d89ff0a7d4c7bcea7fd083db918e16de41a5.zip
Make insmntque() externally visibile and allow it to fail (e.g. during
late stages of unmount). On failure, the vnode is recycled. Add insmntque1(), to allow for file system specific cleanup when recycling vnode on failure. Change getnewvnode() to no longer call insmntque(). Previously, embryonic vnodes were put onto the list of vnode belonging to a file system, which is unsafe for a file system marked MPSAFE. Change vfs_hash_insert() to no longer lock the vnode. The caller now has that responsibility. Change most file systems to lock the vnode and call insmntque() or insmntque1() after a new vnode has been sufficiently setup. Handle failed insmntque*() calls by propagating errors to callers, possibly after some file system specific cleanup. Approved by: re (kensmith) Reviewed by: kib In collaboration with: kib
Notes
Notes: svn path=/head/; revision=167497
-rw-r--r--sys/coda/coda_vnops.c3
-rw-r--r--sys/fs/cd9660/cd9660_vfsops.c13
-rw-r--r--sys/fs/coda/coda_vnops.c3
-rw-r--r--sys/fs/devfs/devfs_vnops.c23
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c7
-rw-r--r--sys/fs/hpfs/hpfs_vfsops.c12
-rw-r--r--sys/fs/msdosfs/msdosfs_denode.c11
-rw-r--r--sys/fs/ntfs/ntfs_vfsops.c7
-rw-r--r--sys/fs/nullfs/null_subr.c15
-rw-r--r--sys/fs/nwfs/nwfs_node.c6
-rw-r--r--sys/fs/portalfs/portal_vfsops.c7
-rw-r--r--sys/fs/portalfs/portal_vnops.c5
-rw-r--r--sys/fs/pseudofs/pseudofs_vncache.c10
-rw-r--r--sys/fs/smbfs/smbfs_node.c5
-rw-r--r--sys/fs/udf/udf_vfsops.c8
-rw-r--r--sys/fs/umapfs/umap_subr.c6
-rw-r--r--sys/fs/unionfs/union_subr.c5
-rw-r--r--sys/gnu/fs/ext2fs/ext2_vfsops.c13
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_inode.c8
-rw-r--r--sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c5
-rw-r--r--sys/kern/uipc_mqueue.c7
-rw-r--r--sys/kern/vfs_hash.c1
-rw-r--r--sys/kern/vfs_subr.c45
-rw-r--r--sys/nfsclient/nfs_node.c11
-rw-r--r--sys/sys/vnode.h3
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c11
26 files changed, 229 insertions, 21 deletions
diff --git a/sys/coda/coda_vnops.c b/sys/coda/coda_vnops.c
index c35dda8bb07d..f5b246bfd061 100644
--- a/sys/coda/coda_vnops.c
+++ b/sys/coda/coda_vnops.c
@@ -1797,6 +1797,9 @@ make_coda_node(CodaFid *fid, struct mount *vfsp, short type)
if (err) {
panic("coda: getnewvnode returned error %d\n", err);
}
+ err = insmntque1(vp, vfsp, NULL, NULL); /* XXX: Too early for mpsafe fs */
+ if (err != 0)
+ panic("coda: insmntque failed: error %d", err);
vp->v_data = cp;
vp->v_type = type;
cp->c_vnode = vp;
diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c
index 319b192e4673..2b557a063fda 100644
--- a/sys/fs/cd9660/cd9660_vfsops.c
+++ b/sys/fs/cd9660/cd9660_vfsops.c
@@ -663,8 +663,10 @@ cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir)
struct vnode *vp;
struct cdev *dev;
int error;
+ struct thread *td;
- error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
+ td = curthread;
+ error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
@@ -682,7 +684,14 @@ cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir)
ip->i_vnode = vp;
ip->i_number = ino;
- error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ free(ip, M_ISOFSNODE);
+ *vpp = NULLVP;
+ return (error);
+ }
+ error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
diff --git a/sys/fs/coda/coda_vnops.c b/sys/fs/coda/coda_vnops.c
index c35dda8bb07d..f5b246bfd061 100644
--- a/sys/fs/coda/coda_vnops.c
+++ b/sys/fs/coda/coda_vnops.c
@@ -1797,6 +1797,9 @@ make_coda_node(CodaFid *fid, struct mount *vfsp, short type)
if (err) {
panic("coda: getnewvnode returned error %d\n", err);
}
+ err = insmntque1(vp, vfsp, NULL, NULL); /* XXX: Too early for mpsafe fs */
+ if (err != 0)
+ panic("coda: insmntque failed: error %d", err);
vp->v_data = cp;
vp->v_type = type;
cp->c_vnode = vp;
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 47cc01cfbbe7..dc39e6703ca7 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -154,6 +154,20 @@ devfs_allocv_drop_refs(int drop_dm_lock, struct devfs_mount *dmp,
return (not_found);
}
+static void
+devfs_insmntque_dtr(struct vnode *vp, void *arg)
+{
+ struct devfs_dirent *de;
+
+ de = (struct devfs_dirent *)arg;
+ mtx_lock(&devfs_de_interlock);
+ vp->v_data = NULL;
+ de->de_vnode = NULL;
+ mtx_unlock(&devfs_de_interlock);
+ vgone(vp);
+ vput(vp);
+}
+
/*
* devfs_allocv shall be entered with dmp->dm_lock held, and it drops
* it on return.
@@ -230,13 +244,16 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, stru
} else {
vp->v_type = VBAD;
}
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
mtx_lock(&devfs_de_interlock);
vp->v_data = de;
de->de_vnode = vp;
mtx_unlock(&devfs_de_interlock);
- sx_xunlock(&dmp->dm_lock);
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
- sx_xlock(&dmp->dm_lock);
+ error = insmntque1(vp, mp, devfs_insmntque_dtr, de);
+ if (error != 0) {
+ (void) devfs_allocv_drop_refs(1, dmp, de);
+ return (error);
+ }
if (devfs_allocv_drop_refs(0, dmp, de)) {
vput(vp);
return (ENOENT);
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index 90c4be0f38d2..c16c0a274584 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -151,6 +151,13 @@ loop:
fd->fd_type = ftype;
fd->fd_fd = -1;
fd->fd_ix = ix;
+ /* XXX: vnode should be locked here */
+ error = insmntque(*vpp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ free(fd, M_TEMP);
+ *vpp = NULLVP;
+ goto out;
+ }
LIST_INSERT_HEAD(fc, fd, fd_hash);
out:
diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c
index b0a303a01485..bb29a838bc80 100644
--- a/sys/fs/hpfs/hpfs_vfsops.c
+++ b/sys/fs/hpfs/hpfs_vfsops.c
@@ -445,6 +445,7 @@ hpfs_vget(
struct hpfsnode *hp;
struct buf *bp;
int error;
+ struct thread *td;
dprintf(("hpfs_vget(0x%x): ",ino));
@@ -471,7 +472,7 @@ hpfs_vget(
MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode),
M_HPFSNO, M_WAITOK);
- error = getnewvnode("hpfs", hpmp->hpm_mp, &hpfs_vnodeops, &vp);
+ error = getnewvnode("hpfs", mp, &hpfs_vnodeops, &vp);
if (error) {
printf("hpfs_vget: can't get new vnode\n");
FREE(hp, M_HPFSNO);
@@ -498,7 +499,14 @@ hpfs_vget(
hp->h_mode = hpmp->hpm_mode;
hp->h_devvp = hpmp->hpm_devvp;
- error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
+ td = curthread;
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ free(hp, M_HPFSNO);
+ return (error);
+ }
+ error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
index 726f7a0630cf..3c8970d9b8ab 100644
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -107,6 +107,7 @@ deget(pmp, dirclust, diroffset, depp)
struct denode *ldep;
struct vnode *nvp, *xvp;
struct buf *bp;
+ struct thread *td;
#ifdef MSDOSFS_DEBUG
printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
@@ -172,7 +173,15 @@ deget(pmp, dirclust, diroffset, depp)
ldep->de_inode = inode;
fc_purge(ldep, 0); /* init the fat cache for this denode */
- error = vfs_hash_insert(nvp, inode, LK_EXCLUSIVE, curthread, &xvp,
+ td = curthread;
+ lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(nvp, mntp);
+ if (error != 0) {
+ FREE(ldep, M_MSDOSFSNODE);
+ *depp = NULL;
+ return (error);
+ }
+ error = vfs_hash_insert(nvp, inode, LK_EXCLUSIVE, td, &xvp,
de_vncmpf, &inode);
if (error) {
*depp = NULL;
diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c
index e63fc8a82a57..26ab396e6e38 100644
--- a/sys/fs/ntfs/ntfs_vfsops.c
+++ b/sys/fs/ntfs/ntfs_vfsops.c
@@ -706,6 +706,13 @@ ntfs_vgetex(
ntfs_ntput(ip);
return (error);
}
+ /* XXX: Too early for mpsafe fs, lacks vnode lock */
+ error = insmntque(vp, ntmp->ntm_mountp);
+ if (error) {
+ ntfs_frele(fp);
+ ntfs_ntput(ip);
+ return (error);
+ }
dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
fp->f_vp = vp;
diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c
index 5dc7c634ca76..66144c055913 100644
--- a/sys/fs/nullfs/null_subr.c
+++ b/sys/fs/nullfs/null_subr.c
@@ -185,6 +185,18 @@ null_hashins(mp, xp)
return (NULLVP);
}
+static void
+null_insmntque_dtr(struct vnode *vp, void *xp)
+{
+ vp->v_data = NULL;
+ vp->v_vnlock = &vp->v_lock;
+ FREE(xp, M_NULLFSNODE);
+ vp->v_op = &dead_vnodeops;
+ (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+ vgone(vp);
+ vput(vp);
+}
+
/*
* Make a new or get existing nullfs node.
* Vp is the alias vnode, lowervp is the lower vnode.
@@ -239,6 +251,9 @@ null_nodeget(mp, lowervp, vpp)
vp->v_vnlock = lowervp->v_vnlock;
if (vp->v_vnlock == NULL)
panic("null_nodeget: Passed a NULL vnlock.\n");
+ error = insmntque1(vp, mp, null_insmntque_dtr, xp);
+ if (error != 0)
+ return (error);
/*
* Atomically insert our new node into the hash or vget existing
* if someone else has beaten us to it.
diff --git a/sys/fs/nwfs/nwfs_node.c b/sys/fs/nwfs/nwfs_node.c
index dc906efbf230..92b7f863cb75 100644
--- a/sys/fs/nwfs/nwfs_node.c
+++ b/sys/fs/nwfs/nwfs_node.c
@@ -174,6 +174,12 @@ rescan:
FREE(np, M_NWNODE);
return (error);
}
+ error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ FREE(np, M_NWNODE);
+ *vpp = NULL;
+ return (error);
+ }
vp->v_data = np;
np->n_vnode = vp;
np->n_mount = nmp;
diff --git a/sys/fs/portalfs/portal_vfsops.c b/sys/fs/portalfs/portal_vfsops.c
index db73ef0f3639..412e81acacfa 100644
--- a/sys/fs/portalfs/portal_vfsops.c
+++ b/sys/fs/portalfs/portal_vfsops.c
@@ -136,6 +136,13 @@ portal_mount(struct mount *mp, struct thread *td)
return (error);
}
+ error = insmntque(rvp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ FREE(fmp, M_PORTALFSMNT);
+ FREE(pn, M_TEMP);
+ fdrop(fp, td);
+ return (error);
+ }
rvp->v_data = pn;
rvp->v_type = VDIR;
rvp->v_vflag |= VV_ROOT;
diff --git a/sys/fs/portalfs/portal_vnops.c b/sys/fs/portalfs/portal_vnops.c
index 143d6340f887..d6c4bc58640a 100644
--- a/sys/fs/portalfs/portal_vnops.c
+++ b/sys/fs/portalfs/portal_vnops.c
@@ -154,6 +154,11 @@ portal_lookup(ap)
*vpp = fvp;
vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, td);
+ error = insmntque(fvp, dvp->v_mount);
+ if (error != 0) {
+ *vpp = NULLVP;
+ return (error);
+ }
return (0);
bad:;
diff --git a/sys/fs/pseudofs/pseudofs_vncache.c b/sys/fs/pseudofs/pseudofs_vncache.c
index e6961bdb46cd..2412e3231f21 100644
--- a/sys/fs/pseudofs/pseudofs_vncache.c
+++ b/sys/fs/pseudofs/pseudofs_vncache.c
@@ -180,6 +180,14 @@ retry:
if ((pn->pn_flags & PFS_PROCDEP) != 0)
(*vpp)->v_vflag |= VV_PROCDEP;
pvd->pvd_vnode = *vpp;
+ (*vpp)->v_vnlock->lk_flags |= LK_CANRECURSE;
+ vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread);
+ error = insmntque(*vpp, mp);
+ if (error != 0) {
+ FREE(pvd, M_PFSVNCACHE);
+ *vpp = NULLVP;
+ return (error);
+ }
mtx_lock(&pfs_vncache_mutex);
pvd->pvd_prev = NULL;
pvd->pvd_next = pfs_vncache;
@@ -187,8 +195,6 @@ retry:
pvd->pvd_next->pvd_prev = pvd;
pfs_vncache = pvd;
mtx_unlock(&pfs_vncache_mutex);
- (*vpp)->v_vnlock->lk_flags |= LK_CANRECURSE;
- vn_lock(*vpp, LK_RETRY | LK_EXCLUSIVE, curthread);
return (0);
}
diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c
index 52e35654f6fa..bd3af4addc92 100644
--- a/sys/fs/smbfs/smbfs_node.c
+++ b/sys/fs/smbfs/smbfs_node.c
@@ -242,6 +242,11 @@ loop:
FREE(np, M_SMBNODE);
return error;
}
+ error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ FREE(np, M_SMBNODE);
+ return (error);
+ }
vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
bzero(np, sizeof(*np));
vp->v_data = np;
diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c
index ee58725c45d7..262e605a3ac7 100644
--- a/sys/fs/udf/udf_vfsops.c
+++ b/sys/fs/udf/udf_vfsops.c
@@ -613,7 +613,13 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
unode->udfmp = udfmp;
vp->v_data = unode;
- error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ uma_zfree(udf_zone_node, unode);
+ return (error);
+ }
+ error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
diff --git a/sys/fs/umapfs/umap_subr.c b/sys/fs/umapfs/umap_subr.c
index 90f19d975911..40756c3f7144 100644
--- a/sys/fs/umapfs/umap_subr.c
+++ b/sys/fs/umapfs/umap_subr.c
@@ -214,6 +214,12 @@ umap_node_alloc(mp, lowervp, vpp)
return (error);
}
vp = *vpp;
+ error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ FREE(xp, M_TEMP);
+ *vpp = NULLVP;
+ return (error);
+ }
vp->v_type = lowervp->v_type;
xp->umap_vnode = vp;
diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c
index 09e2f6d8c8ac..9af99397566f 100644
--- a/sys/fs/unionfs/union_subr.c
+++ b/sys/fs/unionfs/union_subr.c
@@ -243,6 +243,11 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
FREE(unp, M_UNIONFSNODE);
return (error);
}
+ error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
+ if (error != 0) {
+ FREE(unp, M_UNIONFSNODE);
+ return (error);
+ }
if (dvp != NULLVP)
vref(dvp);
if (uppervp != NULLVP)
diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c
index 7abcb7e62d00..3a362a49ddb8 100644
--- a/sys/gnu/fs/ext2fs/ext2_vfsops.c
+++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c
@@ -954,8 +954,10 @@ ext2_vget(mp, ino, flags, vpp)
struct cdev *dev;
int i, error;
int used_blocks;
+ struct thread *td;
- error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
+ td = curthread;
+ error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
@@ -982,7 +984,14 @@ ext2_vget(mp, ino, flags, vpp)
ip->i_e2fs = fs = ump->um_e2fs;
ip->i_number = ino;
- error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ free(ip, M_EXT2NODE);
+ *vpp = NULL;
+ return (error);
+ }
+ error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);
diff --git a/sys/gnu/fs/reiserfs/reiserfs_inode.c b/sys/gnu/fs/reiserfs/reiserfs_inode.c
index ece4a75d3251..3eddd840c024 100644
--- a/sys/gnu/fs/reiserfs/reiserfs_inode.c
+++ b/sys/gnu/fs/reiserfs/reiserfs_inode.c
@@ -815,6 +815,14 @@ reiserfs_iget(
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td);
#endif
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ free(ip, M_REISERFSNODE);
+ *vpp = NULL;
+ reiserfs_log(LOG_DEBUG, "insmntque FAILED\n");
+ return (error);
+ }
error = vfs_hash_insert(vp, key->on_disk_key.k_objectid, flags,
td, vpp, NULL, NULL);
if (error || *vpp != NULL)
diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c
index de5284c5747f..7145b9497a4b 100644
--- a/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c
+++ b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c
@@ -391,6 +391,11 @@ xfs_vn_allocate(xfs_mount_t *mp, xfs_inode_t *ip, struct xfs_vnode **vpp)
vp->v_vnlock->lk_flags |= LK_CANRECURSE;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+ error = insmntque(vp, XVFSTOMNT(XFS_MTOVFS(mp)));
+ if (error != 0) {
+ kmem_free(vdata, sizeof(*vdata));
+ return (error);
+ }
vp->v_data = (void *)vdata;
vdata->v_number= 0;
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index 3439dbc571fa..45162129647e 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -717,6 +717,12 @@ mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn)
error = getnewvnode("mqueue", mp, &mqfs_vnodeops, vpp);
if (error)
return (error);
+ vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread);
+ error = insmntque(*vpp, mp);
+ if (error != 0) {
+ *vpp = NULLVP;
+ return (error);
+ }
vd = uma_zalloc(mvdata_zone, M_WAITOK);
(*vpp)->v_data = vd;
vd->mv_vnode = *vpp;
@@ -744,7 +750,6 @@ mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn)
default:
panic("%s has unexpected type: %d", pn->mn_name, pn->mn_type);
}
- vn_lock(*vpp, LK_RETRY | LK_EXCLUSIVE, curthread);
return (0);
}
diff --git a/sys/kern/vfs_hash.c b/sys/kern/vfs_hash.c
index 80c2dc5938ef..cfdab1b9595e 100644
--- a/sys/kern/vfs_hash.c
+++ b/sys/kern/vfs_hash.c
@@ -109,7 +109,6 @@ vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, stru
struct vnode *vp2;
int error;
- lockmgr(vp->v_vnlock, flags & LK_TYPE_MASK, NULL, td);
*vpp = NULL;
while (1) {
mtx_lock(&vfs_hash_mtx);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index e860b1b0a6f8..cf78d0429d69 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -90,7 +90,6 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_NETADDR, "subr_export_host", "Export host address structure");
static void delmntque(struct vnode *vp);
-static void insmntque(struct vnode *vp, struct mount *mp);
static int flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo,
int slpflag, int slptimeo);
static void syncer_shutdown(void *arg, int howto);
@@ -943,7 +942,6 @@ alloc:
printf("NULL mp in getnewvnode()\n");
#endif
if (mp != NULL) {
- insmntque(vp, mp);
bo->bo_bsize = mp->mnt_stat.f_iosize;
if ((mp->mnt_kern_flag & MNTK_NOKNOTE) != 0)
vp->v_vflag |= VV_NOKNOTE;
@@ -975,22 +973,56 @@ delmntque(struct vnode *vp)
MNT_IUNLOCK(mp);
}
+static void
+insmntque_stddtr(struct vnode *vp, void *dtr_arg)
+{
+ struct thread *td;
+
+ td = curthread; /* XXX ? */
+ vp->v_data = NULL;
+ vp->v_op = &dead_vnodeops;
+ /* XXX non mp-safe fs may still call insmntque with vnode
+ unlocked */
+ if (!VOP_ISLOCKED(vp, td))
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ vgone(vp);
+ vput(vp);
+}
+
/*
* Insert into list of vnodes for the new mount point, if available.
*/
-static void
-insmntque(struct vnode *vp, struct mount *mp)
+int
+insmntque1(struct vnode *vp, struct mount *mp,
+ void (*dtr)(struct vnode *, void *), void *dtr_arg)
{
- vp->v_mount = mp;
+ KASSERT(vp->v_mount == NULL,
+ ("insmntque: vnode already on per mount vnode list"));
VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)"));
MNT_ILOCK(mp);
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 &&
+ mp->mnt_nvnodelistsize == 0) {
+ MNT_IUNLOCK(mp);
+ if (dtr != NULL)
+ dtr(vp, dtr_arg);
+ return (EBUSY);
+ }
+ vp->v_mount = 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(mp);
+ return (0);
+}
+
+int
+insmntque(struct vnode *vp, struct mount *mp)
+{
+
+ return (insmntque1(vp, mp, insmntque_stddtr, NULL));
}
/*
@@ -3015,6 +3047,9 @@ vfs_allocate_syncvnode(struct mount *mp)
return (error);
}
vp->v_type = VNON;
+ error = insmntque(vp, mp);
+ if (error != 0)
+ panic("vfs_allocate_syncvnode: insmntque failed");
/*
* Place the vnode onto the syncer worklist. We attempt to
* scatter them about on the list so that they will go off
diff --git a/sys/nfsclient/nfs_node.c b/sys/nfsclient/nfs_node.c
index b6b92630f073..e97e3589f1f4 100644
--- a/sys/nfsclient/nfs_node.c
+++ b/sys/nfsclient/nfs_node.c
@@ -166,6 +166,17 @@ nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int
np->n_fhp = &np->n_fh;
bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
np->n_fhsize = fhsize;
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mntp);
+ if (error != 0) {
+ *npp = NULL;
+ if (np->n_fhsize > NFS_SMALLFH) {
+ FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
+ }
+ mtx_destroy(&np->n_mtx);
+ uma_zfree(nfsnode_zone, np);
+ return (error);
+ }
error = vfs_hash_insert(vp, hash, flags,
td, &nvp, nfs_vncmpf, &ncmp);
if (error)
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 15bfe6bb1771..da47a50b2412 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -572,6 +572,9 @@ void cvtstat(struct stat *st, struct ostat *ost);
void cvtnstat(struct stat *sb, struct nstat *nsb);
int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
struct vnode **vpp);
+int insmntque1(struct vnode *vp, struct mount *mp,
+ void (*dtr)(struct vnode *, void *), void *dtr_arg);
+int insmntque(struct vnode *vp, struct mount *mp);
u_quad_t init_va_filerev(void);
int lease_check(struct vop_lease_args *ap);
int speedup_syncer(void);
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 788eb2f68d51..7af15dd2b254 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1327,6 +1327,7 @@ ffs_vget(mp, ino, flags, vpp)
struct vnode *vp;
struct cdev *dev;
int error;
+ struct thread *td;
error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
if (error || *vpp != NULL)
@@ -1391,7 +1392,15 @@ ffs_vget(mp, ino, flags, vpp)
}
#endif
- error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
+ td = curthread;
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
+ error = insmntque(vp, mp);
+ if (error != 0) {
+ uma_zfree(uma_inode, ip);
+ *vpp = NULL;
+ return (error);
+ }
+ error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
if (error || *vpp != NULL)
return (error);