diff options
author | iedowse <iedowse@FreeBSD.org> | 2003-08-05 00:26:51 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2003-08-05 00:26:51 +0000 |
commit | 7bf5fa9caf39cc731d7d0a4284ae21ba234fdd96 (patch) | |
tree | aae1fa32436c87d4f5c656bbc8d3353ec33df6d8 /sys | |
parent | c5cc3acad05c083c81ec2feefaf72a6e6c91eca4 (diff) | |
download | FreeBSD-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.c | 28 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 28 |
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) { |