summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2003-08-05 00:26:51 +0000
committeriedowse <iedowse@FreeBSD.org>2003-08-05 00:26:51 +0000
commit7bf5fa9caf39cc731d7d0a4284ae21ba234fdd96 (patch)
treeaae1fa32436c87d4f5c656bbc8d3353ec33df6d8 /sys
parentc5cc3acad05c083c81ec2feefaf72a6e6c91eca4 (diff)
downloadFreeBSD-src-7bf5fa9caf39cc731d7d0a4284ae21ba234fdd96.zip
FreeBSD-src-7bf5fa9caf39cc731d7d0a4284ae21ba234fdd96.tar.gz
In the mknod(), mkfifo(), link(), symlink() and undelete() syscalls,
use vrele() instead of vput() on the parent directory vnode returned by namei() in the case where it is equal to the target vnode. This handles namei()'s somewhat strange (but documented) behaviour of not locking either vnode when the two vnodes are equal and LOCKPARENT but not LOCKLEAF is specified. Note that since a vnode double-unlock is not currently fatal, these coding errors were effectively harmless. Spotted by: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de> Reviewed by: mckusick
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_extattr.c28
-rw-r--r--sys/kern/vfs_syscalls.c28
2 files changed, 46 insertions, 10 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 4ac48b3..c578765 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -907,8 +907,13 @@ restart:
return (error);
vp = nd.ni_vp;
if (vp != NULL) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
- error = EEXIST;
+ if (vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ return (EEXIST);
} else {
VATTR_NULL(&vattr);
FILEDESC_LOCK(td->td_proc->p_fd);
@@ -1005,7 +1010,10 @@ restart:
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
@@ -1087,6 +1095,10 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
vrele(nd.ni_vp);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
error = EEXIST;
} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
== 0) {
@@ -1099,9 +1111,9 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
#endif
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
VOP_UNLOCK(vp, 0, td);
+ vput(nd.ni_dvp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
}
vrele(vp);
vn_finished_write(mp);
@@ -1156,7 +1168,10 @@ restart:
if (nd.ni_vp) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
error = EEXIST;
goto out;
}
@@ -1223,7 +1238,10 @@ restart:
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_vp)
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 4ac48b3..c578765 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -907,8 +907,13 @@ restart:
return (error);
vp = nd.ni_vp;
if (vp != NULL) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
- error = EEXIST;
+ if (vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ return (EEXIST);
} else {
VATTR_NULL(&vattr);
FILEDESC_LOCK(td->td_proc->p_fd);
@@ -1005,7 +1010,10 @@ restart:
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
@@ -1087,6 +1095,10 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
vrele(nd.ni_vp);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
error = EEXIST;
} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
== 0) {
@@ -1099,9 +1111,9 @@ kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
#endif
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
VOP_UNLOCK(vp, 0, td);
+ vput(nd.ni_dvp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
}
vrele(vp);
vn_finished_write(mp);
@@ -1156,7 +1168,10 @@ restart:
if (nd.ni_vp) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
error = EEXIST;
goto out;
}
@@ -1223,7 +1238,10 @@ restart:
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_vp)
vrele(nd.ni_vp);
- vput(nd.ni_dvp);
+ if (nd.ni_vp == nd.ni_dvp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
OpenPOWER on IntegriCloud