]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/dcache.c
mm/vmalloc.c: use seq_open_private() instead of seq_open()
[karo-tx-linux.git] / fs / dcache.c
index 6e543173a5d80ad08838d18f250a5cef8a8f04fb..cb25a1a5e3073748cbef154b6d3575da3f55982d 100644 (file)
@@ -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,13 +2407,19 @@ 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]);
                        }
                }
        }
-       swap(dentry->d_name.len, target->d_name.len);
+       swap(dentry->d_name.hash_len, target->d_name.hash_len);
 }
 
 static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target)
@@ -2442,25 +2449,29 @@ static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target)
        }
 }
 
-static void dentry_unlock_parents_for_move(struct dentry *dentry,
-                                       struct dentry *target)
+static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
 {
        if (target->d_parent != dentry->d_parent)
                spin_unlock(&dentry->d_parent->d_lock);
        if (target->d_parent != target)
                spin_unlock(&target->d_parent->d_lock);
+       spin_unlock(&target->d_lock);
+       spin_unlock(&dentry->d_lock);
 }
 
 /*
  * 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
@@ -2506,10 +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);
-       swap(dentry->d_name.hash, target->d_name.hash);
+       switch_names(dentry, target, exchange);
 
        /* ... and switch them in the tree */
        if (IS_ROOT(dentry)) {
@@ -2531,9 +2540,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
        write_seqcount_end(&target->d_seq);
        write_seqcount_end(&dentry->d_seq);
 
-       dentry_unlock_parents_for_move(dentry, target);
-       spin_unlock(&target->d_lock);
-       spin_unlock(&dentry->d_lock);
+       dentry_unlock_for_move(dentry, target);
 }
 
 /*