summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2002-09-19 13:32:45 +0000
committertruckman <truckman@FreeBSD.org>2002-09-19 13:32:45 +0000
commitf2807820032fe586ea72f9048accb23a9d17c75f (patch)
treefed75b0fd3d3243127e21c52a13f663281ff50f1 /sys
parent38695c19fde9598c887707063c968842a2395e6c (diff)
downloadFreeBSD-src-f2807820032fe586ea72f9048accb23a9d17c75f.zip
FreeBSD-src-f2807820032fe586ea72f9048accb23a9d17c75f.tar.gz
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)
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/unionfs/union_vnops.c23
-rw-r--r--sys/gnu/ext2fs/ext2_vnops.c15
-rw-r--r--sys/gnu/fs/ext2fs/ext2_vnops.c15
-rw-r--r--sys/kern/vfs_extattr.c4
-rw-r--r--sys/kern/vfs_syscalls.c4
-rw-r--r--sys/kern/vnode_if.src2
-rw-r--r--sys/ufs/ufs/ufs_vnops.c15
7 files changed, 34 insertions, 44 deletions
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 92d92ed..9d0d2a1 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -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,14 +1266,13 @@ union_link(ap)
dun->un_flags |= UN_ULOCK;
}
#endif
- VOP_UNLOCK(ap->a_vp, 0, td);
+ if (error)
+ return (error);
}
vp = tun->un_uppervp;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
}
- if (error)
- return (error);
-
/*
* Make sure upper is locked, then unlock the union directory we were
* called with to avoid a deadlock while we are calling VOP_LINK on
@@ -1289,11 +1287,20 @@ union_link(ap)
error = VOP_LINK(tdvp, vp, cnp); /* call link on upper */
/*
+ * 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.
+ * 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);
}
diff --git a/sys/gnu/ext2fs/ext2_vnops.c b/sys/gnu/ext2fs/ext2_vnops.c
index dd24a9d..c1fba78 100644
--- a/sys/gnu/ext2fs/ext2_vnops.c
+++ b/sys/gnu/ext2fs/ext2_vnops.c
@@ -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);
}
diff --git a/sys/gnu/fs/ext2fs/ext2_vnops.c b/sys/gnu/fs/ext2fs/ext2_vnops.c
index dd24a9d..c1fba78 100644
--- a/sys/gnu/fs/ext2fs/ext2_vnops.c
+++ b/sys/gnu/fs/ext2fs/ext2_vnops.c
@@ -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);
}
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index e1b2d7f..5ad587c 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -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);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index e1b2d7f..5ad587c 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -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);
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index 3202058..28b5d2e 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -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;
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index b7d6425..5ec4b6e 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -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);
OpenPOWER on IntegriCloud