VOP_FSYNC() requires that it's vnode argument be locked, which nfs_link()
wasn't doing. Rather than just lock and unlock the vnode around the call to VOP_FSYNC(), implement rwatson's suggestion to lock the file vnode in kern_link() before calling VOP_LINK(), since the other filesystems also locked the file vnode right away in their link methods. Remove the locking and and unlocking from the leaf filesystem link methods. Reviewed by: rwatson, bde (except for the unionfs_link() changes)
This commit is contained in:
parent
38695c19fd
commit
f280782003
@ -1224,8 +1224,8 @@ union_remove(ap)
|
||||
/*
|
||||
* union_link:
|
||||
*
|
||||
* tdvp will be locked on entry, vp will not be locked on entry.
|
||||
* tdvp should remain locked on return and vp should remain unlocked
|
||||
* tdvp and vp will be locked on entry.
|
||||
* tdvp and vp should remain locked on return.
|
||||
* on return.
|
||||
*/
|
||||
|
||||
@ -1250,7 +1250,6 @@ union_link(ap)
|
||||
struct union_node *tun = VTOUNION(ap->a_vp);
|
||||
|
||||
if (tun->un_uppervp == NULLVP) {
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
#if 0
|
||||
if (dun->un_uppervp == tun->un_dirvp) {
|
||||
if (dun->un_flags & UN_ULOCK) {
|
||||
@ -1267,13 +1266,12 @@ union_link(ap)
|
||||
dun->un_flags |= UN_ULOCK;
|
||||
}
|
||||
#endif
|
||||
VOP_UNLOCK(ap->a_vp, 0, td);
|
||||
}
|
||||
vp = tun->un_uppervp;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
vp = tun->un_uppervp;
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure upper is locked, then unlock the union directory we were
|
||||
@ -1289,11 +1287,20 @@ union_link(ap)
|
||||
error = VOP_LINK(tdvp, vp, cnp); /* call link on upper */
|
||||
|
||||
/*
|
||||
* We have to unlock tdvp prior to relocking our calling node in
|
||||
* order to avoid a deadlock.
|
||||
* Unlock tun->un_uppervp if we locked it above.
|
||||
*/
|
||||
if (ap->a_tdvp->v_op == ap->a_vp->v_op)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
/*
|
||||
* We have to unlock tdvp prior to relocking our calling node in
|
||||
* order to avoid a deadlock. We also have to unlock ap->a_vp
|
||||
* before relocking the directory, but then we have to relock
|
||||
* ap->a_vp as our caller expects.
|
||||
*/
|
||||
VOP_UNLOCK(ap->a_vp, 0, td);
|
||||
union_unlock_upper(tdvp, td);
|
||||
vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -827,7 +827,6 @@ ext2_link(ap)
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vnode *tdvp = ap->a_tdvp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct thread *td = cnp->cn_thread;
|
||||
struct inode *ip;
|
||||
int error;
|
||||
|
||||
@ -837,19 +836,16 @@ ext2_link(ap)
|
||||
#endif
|
||||
if (tdvp->v_mount != vp->v_mount) {
|
||||
error = EXDEV;
|
||||
goto out2;
|
||||
}
|
||||
if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, td))) {
|
||||
goto out2;
|
||||
goto out;
|
||||
}
|
||||
ip = VTOI(vp);
|
||||
if ((nlink_t)ip->i_nlink >= LINK_MAX) {
|
||||
error = EMLINK;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
if (ip->i_flags & (IMMUTABLE | APPEND)) {
|
||||
error = EPERM;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
ip->i_nlink++;
|
||||
ip->i_flag |= IN_CHANGE;
|
||||
@ -860,10 +856,7 @@ ext2_link(ap)
|
||||
ip->i_nlink--;
|
||||
ip->i_flag |= IN_CHANGE;
|
||||
}
|
||||
out1:
|
||||
if (tdvp != vp)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
out2:
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -827,7 +827,6 @@ ext2_link(ap)
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vnode *tdvp = ap->a_tdvp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct thread *td = cnp->cn_thread;
|
||||
struct inode *ip;
|
||||
int error;
|
||||
|
||||
@ -837,19 +836,16 @@ ext2_link(ap)
|
||||
#endif
|
||||
if (tdvp->v_mount != vp->v_mount) {
|
||||
error = EXDEV;
|
||||
goto out2;
|
||||
}
|
||||
if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, td))) {
|
||||
goto out2;
|
||||
goto out;
|
||||
}
|
||||
ip = VTOI(vp);
|
||||
if ((nlink_t)ip->i_nlink >= LINK_MAX) {
|
||||
error = EMLINK;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
if (ip->i_flags & (IMMUTABLE | APPEND)) {
|
||||
error = EPERM;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
ip->i_nlink++;
|
||||
ip->i_flag |= IN_CHANGE;
|
||||
@ -860,10 +856,7 @@ ext2_link(ap)
|
||||
ip->i_nlink--;
|
||||
ip->i_flag |= IN_CHANGE;
|
||||
}
|
||||
out1:
|
||||
if (tdvp != vp)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
out2:
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -1027,10 +1027,12 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
|
||||
if (nd.ni_vp != NULL) {
|
||||
vrele(nd.ni_vp);
|
||||
error = EEXIST;
|
||||
} else {
|
||||
} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
|
||||
== 0) {
|
||||
VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
|
||||
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
|
||||
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
}
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vput(nd.ni_dvp);
|
||||
|
@ -1027,10 +1027,12 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
|
||||
if (nd.ni_vp != NULL) {
|
||||
vrele(nd.ni_vp);
|
||||
error = EEXIST;
|
||||
} else {
|
||||
} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
|
||||
== 0) {
|
||||
VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
|
||||
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
|
||||
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
}
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vput(nd.ni_dvp);
|
||||
|
@ -261,7 +261,7 @@ vop_remove {
|
||||
|
||||
#
|
||||
#% link tdvp L L L
|
||||
#% link vp U U U
|
||||
#% link vp L L L
|
||||
#
|
||||
vop_link {
|
||||
IN struct vnode *tdvp;
|
||||
|
@ -814,7 +814,6 @@ ufs_link(ap)
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vnode *tdvp = ap->a_tdvp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct thread *td = cnp->cn_thread;
|
||||
struct inode *ip;
|
||||
struct direct newdir;
|
||||
int error;
|
||||
@ -825,19 +824,16 @@ ufs_link(ap)
|
||||
#endif
|
||||
if (tdvp->v_mount != vp->v_mount) {
|
||||
error = EXDEV;
|
||||
goto out2;
|
||||
}
|
||||
if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, td))) {
|
||||
goto out2;
|
||||
goto out;
|
||||
}
|
||||
ip = VTOI(vp);
|
||||
if ((nlink_t)ip->i_nlink >= LINK_MAX) {
|
||||
error = EMLINK;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
if (ip->i_flags & (IMMUTABLE | APPEND)) {
|
||||
error = EPERM;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
ip->i_effnlink++;
|
||||
ip->i_nlink++;
|
||||
@ -859,10 +855,7 @@ ufs_link(ap)
|
||||
if (DOINGSOFTDEP(vp))
|
||||
softdep_change_linkcnt(ip);
|
||||
}
|
||||
out1:
|
||||
if (tdvp != vp)
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
out2:
|
||||
out:
|
||||
VN_KNOTE(vp, NOTE_LINK);
|
||||
VN_KNOTE(tdvp, NOTE_WRITE);
|
||||
return (error);
|
||||
|
Loading…
Reference in New Issue
Block a user