diff options
author | jeff <jeff@FreeBSD.org> | 2002-08-21 03:55:35 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2002-08-21 03:55:35 +0000 |
commit | a9972cd35ac1c0c8bbc48e9de134af68e32a14ee (patch) | |
tree | 034467187e2ff6622dd0e3f48ecfafa26e89cd88 /sys/kern/vfs_extattr.c | |
parent | aeba6a13e430ec0e07926ccf816584cb24e0c3c1 (diff) | |
download | FreeBSD-src-a9972cd35ac1c0c8bbc48e9de134af68e32a14ee.zip FreeBSD-src-a9972cd35ac1c0c8bbc48e9de134af68e32a14ee.tar.gz |
- Hold the vnode lock across unlink() so that the v_vflag check is safe.
- Fix the long broken error handling for VV_ROOT and VDIR.
Diffstat (limited to 'sys/kern/vfs_extattr.c')
-rw-r--r-- | sys/kern/vfs_extattr.c | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index c09fbd7..48c0151 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -1142,7 +1142,8 @@ unlink(td, uap) restart: bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td); + NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), td); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; @@ -1154,28 +1155,32 @@ restart: * * XXX: can this only be a VDIR case? */ - mp_fixme("Accessing vflags w/o the vn lock."); if (vp->v_vflag & VV_ROOT) error = EBUSY; } - if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(vp); - vput(nd.ni_dvp); - if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) - return (error); - goto restart; - } - VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - if (!error) { + if (error == 0) { + if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (vp == nd.ni_dvp) + vrele(vp); + else + vput(vp); + vput(nd.ni_dvp); + if ((error = vn_start_write(NULL, &mp, + V_XSLEEP | PCATCH)) != 0) + return (error); + goto restart; + } VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); + vn_finished_write(mp); } NDFREE(&nd, NDF_ONLY_PNBUF); + if (vp == nd.ni_dvp) + vrele(vp); + else + vput(vp); vput(nd.ni_dvp); - vput(vp); - vn_finished_write(mp); ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); return (error); |