Skip to content

Commit d2fa4a8

Browse files
Mikhail EfremovAl Viro
authored andcommitted
vfs: Don't exchange "short" filenames unconditionally.
Only exchange source and destination filenames if flags contain RENAME_EXCHANGE. In case if executable file was running and replaced by other file /proc/PID/exe should still show correct file name, not the old name of the file by which it was replaced. The scenario when this bug manifests itself was like this: * ALT Linux uses rpm and start-stop-daemon; * during a package upgrade rpm creates a temporary file for an executable to rename it upon successful unpacking; * start-stop-daemon is run subsequently and it obtains the (nonexistant) temporary filename via /proc/PID/exe thus failing to identify the running process. Note that "long" filenames (> DNAiME_INLINE_LEN) are still exchanged without RENAME_EXCHANGE and this behaviour exists long enough (should be fixed too apparently). So this patch is just an interim workaround that restores behavior for "short" names as it was before changes introduced by commit da1ce06 ("vfs: add cross-rename"). See https://lkml.org/lkml/2014/9/7/6 for details. AV: the comments about being more careful with ->d_name.hash than with ->d_name.name are from back in 2.3.40s; they became obsolete by 2.3.60s, when we started to unhash the target instead of swapping hash chain positions followed by d_delete() as we used to do when dcache was first introduced. Acked-by: Miklos Szeredi <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Alexander Viro <[email protected]> Cc: [email protected] Cc: [email protected] Fixes: da1ce06 "vfs: add cross-rename" Signed-off-by: Mikhail Efremov <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent a28ddb8 commit d2fa4a8

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

fs/dcache.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,7 +2372,8 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
23722372
}
23732373
EXPORT_SYMBOL(dentry_update_name_case);
23742374

2375-
static void switch_names(struct dentry *dentry, struct dentry *target)
2375+
static void switch_names(struct dentry *dentry, struct dentry *target,
2376+
bool exchange)
23762377
{
23772378
if (dname_external(target)) {
23782379
if (dname_external(dentry)) {
@@ -2406,6 +2407,12 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
24062407
*/
24072408
unsigned int i;
24082409
BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
2410+
if (!exchange) {
2411+
memcpy(dentry->d_iname, target->d_name.name,
2412+
target->d_name.len + 1);
2413+
dentry->d_name.hash_len = target->d_name.hash_len;
2414+
return;
2415+
}
24092416
for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
24102417
swap(((long *) &dentry->d_iname)[i],
24112418
((long *) &target->d_iname)[i]);
@@ -2456,12 +2463,15 @@ static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
24562463
* When switching names, the actual string doesn't strictly have to
24572464
* be preserved in the target - because we're dropping the target
24582465
* anyway. As such, we can just do a simple memcpy() to copy over
2459-
* the new name before we switch.
2460-
*
2461-
* Note that we have to be a lot more careful about getting the hash
2462-
* switched - we have to switch the hash value properly even if it
2463-
* then no longer matches the actual (corrupted) string of the target.
2464-
* The hash value has to match the hash queue that the dentry is on..
2466+
* the new name before we switch, unless we are going to rehash
2467+
* it. Note that if we *do* unhash the target, we are not allowed
2468+
* to rehash it without giving it a new name/hash key - whether
2469+
* we swap or overwrite the names here, resulting name won't match
2470+
* the reality in filesystem; it's only there for d_path() purposes.
2471+
* Note that all of this is happening under rename_lock, so the
2472+
* any hash lookup seeing it in the middle of manipulations will
2473+
* be discarded anyway. So we do not care what happens to the hash
2474+
* key in that case.
24652475
*/
24662476
/*
24672477
* __d_move - move a dentry
@@ -2507,9 +2517,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
25072517
d_hash(dentry->d_parent, dentry->d_name.hash));
25082518
}
25092519

2510-
25112520
/* Switch the names.. */
2512-
switch_names(dentry, target);
2521+
switch_names(dentry, target, exchange);
25132522

25142523
/* ... and switch them in the tree */
25152524
if (IS_ROOT(dentry)) {

0 commit comments

Comments
 (0)