upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / fs / dcache.c
index a563989..e37d1f0 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/syscalls.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
@@ -395,8 +396,6 @@ static void prune_dcache(int count)
                struct dentry *dentry;
                struct list_head *tmp;
 
-               cond_resched_lock(&dcache_lock);
-
                tmp = dentry_unused.prev;
                if (tmp == &dentry_unused)
                        break;
@@ -732,7 +731,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        dentry->d_extra_attributes = NULL;
        dentry->d_mounted = 0;
        dentry->d_cookie = NULL;
-       dentry->d_bucket = NULL;
        INIT_HLIST_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -754,6 +752,16 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        return dentry;
 }
 
+struct dentry *d_alloc_name(struct dentry *parent, const char *name)
+{
+       struct qstr q;
+
+       q.name = name;
+       q.len = strlen(name);
+       q.hash = full_name_hash(q.name, q.len);
+       return d_alloc(parent, &q);
+}
+
 /**
  * d_instantiate - fill in inode information for a dentry
  * @entry: dentry to complete
@@ -861,12 +869,6 @@ struct dentry * d_alloc_anon(struct inode *inode)
                res->d_sb = inode->i_sb;
                res->d_parent = res;
                res->d_inode = inode;
-
-               /*
-                * Set d_bucket to an "impossible" bucket address so
-                * that d_move() doesn't get a false positive
-                */
-               res->d_bucket = NULL;
                res->d_flags |= DCACHE_DISCONNECTED;
                res->d_flags &= ~DCACHE_UNHASHED;
                list_add(&res->d_alias, &inode->i_dentry);
@@ -989,8 +991,6 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
 
                dentry = hlist_entry(node, struct dentry, d_hash);
 
-               smp_rmb();
-
                if (dentry->d_name.hash != hash)
                        continue;
                if (dentry->d_parent != parent)
@@ -998,13 +998,6 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
 
                spin_lock(&dentry->d_lock);
 
-               /*
-                * If lookup ends up in a different bucket due to concurrent
-                * rename, fail it
-                */
-               if (unlikely(dentry->d_bucket != head))
-                       goto terminate;
-
                /*
                 * Recheck the dentry after taking the lock - d_move may have
                 * changed things.  Don't bother checking the hash because we're
@@ -1013,7 +1006,11 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
                if (dentry->d_parent != parent)
                        goto next;
 
-               qstr = rcu_dereference(&dentry->d_name);
+               /*
+                * It is safe to compare names since d_move() cannot
+                * change the qstr (protected by d_lock).
+                */
+               qstr = &dentry->d_name;
                if (parent->d_op && parent->d_op->d_compare) {
                        if (parent->d_op->d_compare(parent, qstr, name))
                                goto next;
@@ -1028,7 +1025,6 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
                        atomic_inc(&dentry->d_count);
                        found = dentry;
                }
-terminate:
                spin_unlock(&dentry->d_lock);
                break;
 next:
@@ -1120,6 +1116,13 @@ void d_delete(struct dentry * dentry)
        spin_unlock(&dcache_lock);
 }
 
+static void __d_rehash(struct dentry * entry, struct hlist_head *list)
+{
+
+       entry->d_flags &= ~DCACHE_UNHASHED;
+       hlist_add_head_rcu(&entry->d_hash, list);
+}
+
 /**
  * d_rehash    - add an entry back to the hash
  * @entry: dentry to add to the hash
@@ -1133,10 +1136,8 @@ void d_rehash(struct dentry * entry)
 
        spin_lock(&dcache_lock);
        spin_lock(&entry->d_lock);
-       entry->d_flags &= ~DCACHE_UNHASHED;
+       __d_rehash(entry, list);
        spin_unlock(&entry->d_lock);
-       entry->d_bucket = list;
-       hlist_add_head_rcu(&entry->d_hash, list);
        spin_unlock(&dcache_lock);
 }
 
@@ -1214,6 +1215,8 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
 
 void d_move(struct dentry * dentry, struct dentry * target)
 {
+       struct hlist_head *list;
+
        if (!dentry->d_inode)
                printk(KERN_WARNING "VFS: moving negative dcache entry\n");
 
@@ -1233,13 +1236,12 @@ void d_move(struct dentry * dentry, struct dentry * target)
        /* Move the dentry to the target hash queue, if on different bucket */
        if (dentry->d_flags & DCACHE_UNHASHED)
                goto already_unhashed;
-       if (dentry->d_bucket != target->d_bucket) {
-               hlist_del_rcu(&dentry->d_hash);
+
+       hlist_del_rcu(&dentry->d_hash);
+
 already_unhashed:
-               dentry->d_bucket = target->d_bucket;
-               hlist_add_head_rcu(&dentry->d_hash, target->d_bucket);
-               dentry->d_flags &= ~DCACHE_UNHASHED;
-       }
+       list = d_hash(target->d_parent, target->d_name.hash);
+       __d_rehash(dentry, list);
 
        /* Unhash the target: dput() will then get rid of it */
        __d_drop(target);
@@ -1259,7 +1261,6 @@ already_unhashed:
 
        /* Switch the names.. */
        switch_names(dentry, target);
-       smp_wmb();
        do_switch(dentry->d_name.len, target->d_name.len);
        do_switch(dentry->d_name.hash, target->d_name.hash);