summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/fs/deadfs/dead_vnops.c25
-rw-r--r--sys/kern/vfs_lookup.c21
2 files changed, 41 insertions, 5 deletions
diff --git a/sys/fs/deadfs/dead_vnops.c b/sys/fs/deadfs/dead_vnops.c
index 1bbf453..a5c359f 100644
--- a/sys/fs/deadfs/dead_vnops.c
+++ b/sys/fs/deadfs/dead_vnops.c
@@ -49,6 +49,7 @@ static vop_poll_t dead_poll;
static vop_read_t dead_read;
static vop_write_t dead_write;
static vop_getwritemount_t dead_getwritemount;
+static vop_rename_t dead_rename;
struct vop_vector dead_vnodeops = {
.vop_default = &default_vnodeops,
@@ -73,7 +74,7 @@ struct vop_vector dead_vnodeops = {
.vop_readlink = VOP_EBADF,
.vop_reclaim = VOP_NULL,
.vop_remove = VOP_PANIC,
- .vop_rename = VOP_PANIC,
+ .vop_rename = dead_rename,
.vop_rmdir = VOP_PANIC,
.vop_setattr = VOP_EBADF,
.vop_symlink = VOP_PANIC,
@@ -211,3 +212,25 @@ dead_poll(ap)
{
return (POLLHUP);
}
+
+static int
+dead_rename(ap)
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap;
+{
+ if (ap->a_tvp)
+ vput(ap->a_tvp);
+ if (ap->a_tdvp == ap->a_tvp)
+ vrele(ap->a_tdvp);
+ else
+ vput(ap->a_tdvp);
+ vrele(ap->a_fdvp);
+ vrele(ap->a_fvp);
+ return (EXDEV);
+}
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index a0cbc83..bf624d8 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -69,13 +69,18 @@ __FBSDID("$FreeBSD$");
* Allocation zone for namei
*/
uma_zone_t namei_zone;
+/*
+ * Placeholder vnode for mp traversal
+ */
+static struct vnode *vp_crossmp;
static void
nameiinit(void *dummy __unused)
{
namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
-
+ getnewvnode("crossmp", NULL, &dead_vnodeops, &vp_crossmp);
+ vp_crossmp->v_vnlock->lk_flags &= ~LK_NOSHARE;
}
SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL)
@@ -559,7 +564,8 @@ unionlookup:
* If we have a shared lock we may need to upgrade the lock for the
* last operation.
*/
- if (VOP_ISLOCKED(dp, td) == LK_SHARED &&
+ if (dp != vp_crossmp &&
+ VOP_ISLOCKED(dp, td) == LK_SHARED &&
(cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT))
vn_lock(dp, LK_UPGRADE|LK_RETRY, td);
/*
@@ -658,10 +664,17 @@ unionlookup:
VFS_UNLOCK_GIANT(vfslocked);
vfslocked = VFS_LOCK_GIANT(mp);
if (dp != ndp->ni_dvp)
- VOP_UNLOCK(ndp->ni_dvp, 0, td);
+ vput(ndp->ni_dvp);
+ else
+ vrele(ndp->ni_dvp);
+ VFS_UNLOCK_GIANT(dvfslocked);
+ dvfslocked = 0;
+ vref(vp_crossmp);
+ ndp->ni_dvp = vp_crossmp;
error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags), &tdp, td);
vfs_unbusy(mp, td);
- vn_lock(ndp->ni_dvp, compute_cn_lkflags(mp, cnp->cn_lkflags | LK_RETRY), td);
+ if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT, td))
+ panic("vp_crossmp exclusively locked or reclaimed");
if (error) {
dpunlocked = 1;
goto bad2;
OpenPOWER on IntegriCloud