|
@@ -2372,7 +2372,8 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
|
|
|
}
|
|
|
EXPORT_SYMBOL(dentry_update_name_case);
|
|
|
|
|
|
-static void switch_names(struct dentry *dentry, struct dentry *target)
|
|
|
+static void switch_names(struct dentry *dentry, struct dentry *target,
|
|
|
+ bool exchange)
|
|
|
{
|
|
|
if (dname_external(target)) {
|
|
|
if (dname_external(dentry)) {
|
|
@@ -2406,6 +2407,12 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
|
|
|
*/
|
|
|
unsigned int i;
|
|
|
BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
|
|
|
+ if (!exchange) {
|
|
|
+ memcpy(dentry->d_iname, target->d_name.name,
|
|
|
+ target->d_name.len + 1);
|
|
|
+ dentry->d_name.hash_len = target->d_name.hash_len;
|
|
|
+ return;
|
|
|
+ }
|
|
|
for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
|
|
|
swap(((long *) &dentry->d_iname)[i],
|
|
|
((long *) &target->d_iname)[i]);
|
|
@@ -2456,12 +2463,15 @@ static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
|
|
|
* When switching names, the actual string doesn't strictly have to
|
|
|
* be preserved in the target - because we're dropping the target
|
|
|
* anyway. As such, we can just do a simple memcpy() to copy over
|
|
|
- * the new name before we switch.
|
|
|
- *
|
|
|
- * Note that we have to be a lot more careful about getting the hash
|
|
|
- * switched - we have to switch the hash value properly even if it
|
|
|
- * then no longer matches the actual (corrupted) string of the target.
|
|
|
- * The hash value has to match the hash queue that the dentry is on..
|
|
|
+ * the new name before we switch, unless we are going to rehash
|
|
|
+ * it. Note that if we *do* unhash the target, we are not allowed
|
|
|
+ * to rehash it without giving it a new name/hash key - whether
|
|
|
+ * we swap or overwrite the names here, resulting name won't match
|
|
|
+ * the reality in filesystem; it's only there for d_path() purposes.
|
|
|
+ * Note that all of this is happening under rename_lock, so the
|
|
|
+ * any hash lookup seeing it in the middle of manipulations will
|
|
|
+ * be discarded anyway. So we do not care what happens to the hash
|
|
|
+ * key in that case.
|
|
|
*/
|
|
|
/*
|
|
|
* __d_move - move a dentry
|
|
@@ -2507,9 +2517,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
|
|
d_hash(dentry->d_parent, dentry->d_name.hash));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/* Switch the names.. */
|
|
|
- switch_names(dentry, target);
|
|
|
+ switch_names(dentry, target, exchange);
|
|
|
|
|
|
/* ... and switch them in the tree */
|
|
|
if (IS_ROOT(dentry)) {
|