vfs_syscalls.c:

Changed rename(2) to follow the letter of the POSIX spec.  POSIX
requires rename() to have no effect if its args "resolve to the same
existing file".  I think "file" can only reasonably be read as referring
to the inode, although the rationale and "resolve" seem to say that
sameness is at the level of (resolved) directory entries.

ext2fs_vnops.c, ufs_vnops.c:
Replaced code that gave the historical BSD behaviour of removing one
link name by checks that this code is now unreachable.  This fixes
some races.  All vnodes needed to be unlocked for the removal, and
locking at another level using something like IN_RENAME was not even
attempted, so it was possible for rename(x, y) to return with both x
and y removed even without any unlink(2) syscalls (one process can
remove x using rename(x, y) and another process can remove y using
rename(y, x)).

Prodded by:	alfred
MFC after:	8 weeks
PR:		42617
This commit is contained in:
Bruce Evans 2002-09-10 11:09:13 +00:00
parent 3e30ca7b1c
commit d3a7b5e70e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=103180
5 changed files with 24 additions and 168 deletions

View File

@ -925,60 +925,15 @@ ext2_rename(ap)
}
/*
* Check if just deleting a link name or if we've lost a race.
* If another process completes the same rename after we've looked
* up the source and have blocked looking up the target, then the
* source and target inodes may be identical now although the
* names were never linked.
* Renaming a file to itself has no effect. The upper layers should
* not call us in that case. Temporarily just warn if they do.
*/
if (fvp == tvp) {
if (fvp->v_type == VDIR) {
/*
* Linked directories are impossible, so we must
* have lost the race. Pretend that the rename
* completed before the lookup.
*/
#ifdef UFS_RENAME_DEBUG
printf("ext2_rename: fvp == tvp for directories\n");
#endif
error = ENOENT;
goto abortit;
}
/* Release destination completely. */
vput(tdvp);
vput(tvp);
/*
* Delete source. There is another race now that everything
* is unlocked, but this doesn't cause any new complications.
* Relookup() may find a file that is unrelated to the
* original one, or it may fail. Too bad.
*/
vrele(fdvp);
vrele(fvp);
fcnp->cn_flags &= ~MODMASK;
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
fcnp->cn_nameiop = DELETE;
VREF(fdvp);
error = relookup(fdvp, &fvp, fcnp);
if (error == 0)
vrele(fdvp);
if (fvp == NULL) {
#ifdef UFS_RENAME_DEBUG
printf("ext2_rename: from name disappeared\n");
#endif
return (ENOENT);
}
error = VOP_REMOVE(fdvp, fvp, fcnp);
if (fdvp == fvp)
vrele(fdvp);
else
vput(fdvp);
if (fvp != NULLVP)
vput(fvp);
return (error);
printf("ext2_rename: fvp == tvp (can't happen)\n");
error = 0;
goto abortit;
}
if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
goto abortit;
dp = VTOI(fdvp);

View File

@ -925,60 +925,15 @@ ext2_rename(ap)
}
/*
* Check if just deleting a link name or if we've lost a race.
* If another process completes the same rename after we've looked
* up the source and have blocked looking up the target, then the
* source and target inodes may be identical now although the
* names were never linked.
* Renaming a file to itself has no effect. The upper layers should
* not call us in that case. Temporarily just warn if they do.
*/
if (fvp == tvp) {
if (fvp->v_type == VDIR) {
/*
* Linked directories are impossible, so we must
* have lost the race. Pretend that the rename
* completed before the lookup.
*/
#ifdef UFS_RENAME_DEBUG
printf("ext2_rename: fvp == tvp for directories\n");
#endif
error = ENOENT;
goto abortit;
}
/* Release destination completely. */
vput(tdvp);
vput(tvp);
/*
* Delete source. There is another race now that everything
* is unlocked, but this doesn't cause any new complications.
* Relookup() may find a file that is unrelated to the
* original one, or it may fail. Too bad.
*/
vrele(fdvp);
vrele(fvp);
fcnp->cn_flags &= ~MODMASK;
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
fcnp->cn_nameiop = DELETE;
VREF(fdvp);
error = relookup(fdvp, &fvp, fcnp);
if (error == 0)
vrele(fdvp);
if (fvp == NULL) {
#ifdef UFS_RENAME_DEBUG
printf("ext2_rename: from name disappeared\n");
#endif
return (ENOENT);
}
error = VOP_REMOVE(fdvp, fvp, fcnp);
if (fdvp == fvp)
vrele(fdvp);
else
vput(fdvp);
if (fvp != NULLVP)
vput(fvp);
return (error);
printf("ext2_rename: fvp == tvp (can't happen)\n");
error = 0;
goto abortit;
}
if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
goto abortit;
dp = VTOI(fdvp);

View File

@ -2744,14 +2744,10 @@ kern_rename(struct thread *td, char *from, char *to, enum uio_seg pathseg)
if (fvp == tdvp)
error = EINVAL;
/*
* If source is the same as the destination (that is the
* same inode number with the same name in the same directory),
* then there is nothing to do.
* If the source is the same as the destination (that is, if they
* are links to the same vnode), then there is nothing to do.
*/
if (fvp == tvp && fromnd.ni_dvp == tdvp &&
fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
!bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
fromnd.ni_cnd.cn_namelen))
if (fvp == tvp)
error = -1;
out:
if (!error) {

View File

@ -2744,14 +2744,10 @@ kern_rename(struct thread *td, char *from, char *to, enum uio_seg pathseg)
if (fvp == tdvp)
error = EINVAL;
/*
* If source is the same as the destination (that is the
* same inode number with the same name in the same directory),
* then there is nothing to do.
* If the source is the same as the destination (that is, if they
* are links to the same vnode), then there is nothing to do.
*/
if (fvp == tvp && fromnd.ni_dvp == tdvp &&
fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
!bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
fromnd.ni_cnd.cn_namelen))
if (fvp == tvp)
error = -1;
out:
if (!error) {

View File

@ -1000,61 +1000,15 @@ ufs_rename(ap)
}
/*
* Check if just deleting a link name or if we've lost a race.
* If another process completes the same rename after we've looked
* up the source and have blocked looking up the target, then the
* source and target inodes may be identical now although the
* names were never linked.
* Renaming a file to itself has no effect. The upper layers should
* not call us in that case. Temporarily just warn if they do.
*/
if (fvp == tvp) {
if (fvp->v_type == VDIR) {
/*
* Linked directories are impossible, so we must
* have lost the race. Pretend that the rename
* completed before the lookup.
*/
#ifdef UFS_RENAME_DEBUG
printf("ufs_rename: fvp == tvp for directories\n");
#endif
error = ENOENT;
goto abortit;
}
/* Release destination completely. */
vput(tdvp);
vput(tvp);
/*
* Delete source. There is another race now that everything
* is unlocked, but this doesn't cause any new complications.
* Relookup() may find a file that is unrelated to the
* original one, or it may fail. Too bad.
*/
vrele(fdvp);
vrele(fvp);
fcnp->cn_flags &= ~MODMASK;
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
if ((fcnp->cn_flags & SAVESTART) == 0)
panic("ufs_rename: lost from startdir");
fcnp->cn_nameiop = DELETE;
VREF(fdvp);
error = relookup(fdvp, &fvp, fcnp);
if (error == 0)
vrele(fdvp);
if (fvp == NULL) {
#ifdef UFS_RENAME_DEBUG
printf("ufs_rename: from name disappeared\n");
#endif
return (ENOENT);
}
error = VOP_REMOVE(fdvp, fvp, fcnp);
if (fdvp == fvp)
vrele(fdvp);
else
vput(fdvp);
vput(fvp);
return (error);
printf("ufs_rename: fvp == tvp (can't happen)\n");
error = 0;
goto abortit;
}
if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
goto abortit;
dp = VTOI(fdvp);