svn commit: r272541 - stable/10/sys/kern
Konstantin Belousov
kib at FreeBSD.org
Sat Oct 4 19:37:45 UTC 2014
Author: kib
Date: Sat Oct 4 19:37:44 2014
New Revision: 272541
URL: https://svnweb.freebsd.org/changeset/base/272541
Log:
MFC r272130:
In kern_linkat() and kern_renameat(), do not call namei(9) while
holding a write reference on the filesystem. Try to get write
reference in unblocked way after all vnodes are resolved; if failed,
drop all locks and retry after waiting for suspension end.
Modified:
stable/10/sys/kern/vfs_syscalls.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/kern/vfs_syscalls.c
==============================================================================
--- stable/10/sys/kern/vfs_syscalls.c Sat Oct 4 19:33:58 2014 (r272540)
+++ stable/10/sys/kern/vfs_syscalls.c Sat Oct 4 19:37:44 2014 (r272541)
@@ -1552,10 +1552,10 @@ kern_linkat(struct thread *td, int fd1,
cap_rights_t rights;
int error;
+again:
bwillwrite();
NDINIT_AT(&nd, LOOKUP, follow | AUDITVNODE1, segflg, path1, fd1, td);
-again:
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -1564,50 +1564,65 @@ again:
vrele(vp);
return (EPERM); /* POSIX */
}
- if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
- vrele(vp);
- return (error);
- }
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2,
segflg, path2, fd2, cap_rights_init(&rights, CAP_LINKAT), td);
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
- error = EEXIST;
- } else if ((error = vn_lock(vp, LK_EXCLUSIVE)) == 0) {
+ vrele(vp);
+ return (EEXIST);
+ } else if (nd.ni_dvp->v_mount != vp->v_mount) {
/*
- * Check for cross-device links. No need to
- * recheck vp->v_type, since it cannot change
- * for non-doomed vnode.
+ * Cross-device link. No need to recheck
+ * vp->v_type, since it cannot change, except
+ * to VBAD.
*/
- if (nd.ni_dvp->v_mount != vp->v_mount)
- error = EXDEV;
- else
- error = can_hardlink(vp, td->td_ucred);
- if (error == 0)
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_dvp);
+ vrele(vp);
+ return (EXDEV);
+ } else if ((error = vn_lock(vp, LK_EXCLUSIVE)) == 0) {
+ error = can_hardlink(vp, td->td_ucred);
#ifdef MAC
+ if (error == 0)
error = mac_vnode_check_link(td->td_ucred,
nd.ni_dvp, vp, &nd.ni_cnd);
- if (error == 0)
#endif
- error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+ if (error != 0) {
+ vput(vp);
+ vput(nd.ni_dvp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ return (error);
+ }
+ error = vn_start_write(vp, &mp, V_NOWAIT);
+ if (error != 0) {
+ vput(vp);
+ vput(nd.ni_dvp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ error = vn_start_write(NULL, &mp,
+ V_XSLEEP | PCATCH);
+ if (error != 0)
+ return (error);
+ goto again;
+ }
+ error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
VOP_UNLOCK(vp, 0);
vput(nd.ni_dvp);
+ vn_finished_write(mp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
} else {
vput(nd.ni_dvp);
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
- vn_finished_write(mp);
goto again;
}
- NDFREE(&nd, NDF_ONLY_PNBUF);
}
vrele(vp);
- vn_finished_write(mp);
return (error);
}
@@ -3517,6 +3532,7 @@ kern_renameat(struct thread *td, int old
cap_rights_t rights;
int error;
+again:
bwillwrite();
#ifdef MAC
NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART |
@@ -3537,14 +3553,6 @@ kern_renameat(struct thread *td, int old
VOP_UNLOCK(fromnd.ni_vp, 0);
#endif
fvp = fromnd.ni_vp;
- if (error == 0)
- error = vn_start_write(fvp, &mp, V_WAIT | PCATCH);
- if (error != 0) {
- NDFREE(&fromnd, NDF_ONLY_PNBUF);
- vrele(fromnd.ni_dvp);
- vrele(fvp);
- goto out1;
- }
NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE |
SAVESTART | AUDITVNODE2, pathseg, new, newfd,
cap_rights_init(&rights, CAP_LINKAT), td);
@@ -3557,11 +3565,30 @@ kern_renameat(struct thread *td, int old
NDFREE(&fromnd, NDF_ONLY_PNBUF);
vrele(fromnd.ni_dvp);
vrele(fvp);
- vn_finished_write(mp);
goto out1;
}
tdvp = tond.ni_dvp;
tvp = tond.ni_vp;
+ error = vn_start_write(fvp, &mp, V_NOWAIT);
+ if (error != 0) {
+ NDFREE(&fromnd, NDF_ONLY_PNBUF);
+ NDFREE(&tond, NDF_ONLY_PNBUF);
+ if (tvp != NULL)
+ vput(tvp);
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ vrele(tond.ni_startdir);
+ if (fromnd.ni_startdir != NULL)
+ vrele(fromnd.ni_startdir);
+ error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
+ if (error != 0)
+ return (error);
+ goto again;
+ }
if (tvp != NULL) {
if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
error = ENOTDIR;
More information about the svn-src-stable-10
mailing list