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:
truckman 2002-09-19 13:32:45 +00:00
parent 38695c19fd
commit f280782003
7 changed files with 35 additions and 45 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);