diff options
-rw-r--r-- | fs/dcache.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 7599d35b4ae5..cb25a1a5e307 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2372,7 +2372,8 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name) | |||
2372 | } | 2372 | } |
2373 | EXPORT_SYMBOL(dentry_update_name_case); | 2373 | EXPORT_SYMBOL(dentry_update_name_case); |
2374 | 2374 | ||
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) | ||
2376 | { | 2377 | { |
2377 | if (dname_external(target)) { | 2378 | if (dname_external(target)) { |
2378 | if (dname_external(dentry)) { | 2379 | if (dname_external(dentry)) { |
@@ -2406,6 +2407,12 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
2406 | */ | 2407 | */ |
2407 | unsigned int i; | 2408 | unsigned int i; |
2408 | BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long))); | 2409 | 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 | } | ||
2409 | for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) { | 2416 | for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) { |
2410 | swap(((long *) &dentry->d_iname)[i], | 2417 | swap(((long *) &dentry->d_iname)[i], |
2411 | ((long *) &target->d_iname)[i]); | 2418 | ((long *) &target->d_iname)[i]); |
@@ -2456,12 +2463,15 @@ static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target) | |||
2456 | * When switching names, the actual string doesn't strictly have to | 2463 | * When switching names, the actual string doesn't strictly have to |
2457 | * be preserved in the target - because we're dropping the target | 2464 | * be preserved in the target - because we're dropping the target |
2458 | * anyway. As such, we can just do a simple memcpy() to copy over | 2465 | * anyway. As such, we can just do a simple memcpy() to copy over |
2459 | * the new name before we switch. | 2466 | * the new name before we switch, unless we are going to rehash |
2460 | * | 2467 | * it. Note that if we *do* unhash the target, we are not allowed |
2461 | * Note that we have to be a lot more careful about getting the hash | 2468 | * to rehash it without giving it a new name/hash key - whether |
2462 | * switched - we have to switch the hash value properly even if it | 2469 | * we swap or overwrite the names here, resulting name won't match |
2463 | * then no longer matches the actual (corrupted) string of the target. | 2470 | * the reality in filesystem; it's only there for d_path() purposes. |
2464 | * The hash value has to match the hash queue that the dentry is on.. | 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. | ||
2465 | */ | 2475 | */ |
2466 | /* | 2476 | /* |
2467 | * __d_move - move a dentry | 2477 | * __d_move - move a dentry |
@@ -2507,9 +2517,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target, | |||
2507 | d_hash(dentry->d_parent, dentry->d_name.hash)); | 2517 | d_hash(dentry->d_parent, dentry->d_name.hash)); |
2508 | } | 2518 | } |
2509 | 2519 | ||
2510 | |||
2511 | /* Switch the names.. */ | 2520 | /* Switch the names.. */ |
2512 | switch_names(dentry, target); | 2521 | switch_names(dentry, target, exchange); |
2513 | 2522 | ||
2514 | /* ... and switch them in the tree */ | 2523 | /* ... and switch them in the tree */ |
2515 | if (IS_ROOT(dentry)) { | 2524 | if (IS_ROOT(dentry)) { |