Merge branch 'work.dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / fs / dcache.c
index aac41adf474336ba11488cc025e1e8d46afd0e32..982d97bbb72cad7f8416d1814f42254c5cd0919d 100644 (file)
@@ -284,25 +284,23 @@ static inline int dname_external(const struct dentry *dentry)
 void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
 {
        spin_lock(&dentry->d_lock);
+       name->name = dentry->d_name;
        if (unlikely(dname_external(dentry))) {
-               struct external_name *p = external_name(dentry);
-               atomic_inc(&p->u.count);
-               spin_unlock(&dentry->d_lock);
-               name->name = p->name;
+               atomic_inc(&external_name(dentry)->u.count);
        } else {
                memcpy(name->inline_name, dentry->d_iname,
                       dentry->d_name.len + 1);
-               spin_unlock(&dentry->d_lock);
-               name->name = name->inline_name;
+               name->name.name = name->inline_name;
        }
+       spin_unlock(&dentry->d_lock);
 }
 EXPORT_SYMBOL(take_dentry_name_snapshot);
 
 void release_dentry_name_snapshot(struct name_snapshot *name)
 {
-       if (unlikely(name->name != name->inline_name)) {
+       if (unlikely(name->name.name != name->inline_name)) {
                struct external_name *p;
-               p = container_of(name->name, struct external_name, name[0]);
+               p = container_of(name->name.name, struct external_name, name[0]);
                if (unlikely(atomic_dec_and_test(&p->u.count)))
                        kfree_rcu(p, u.head);
        }
@@ -344,7 +342,7 @@ static void dentry_free(struct dentry *dentry)
                }
        }
        /* if dentry was never visible to RCU, immediate free is OK */
-       if (!(dentry->d_flags & DCACHE_RCUACCESS))
+       if (dentry->d_flags & DCACHE_NORCU)
                __d_free(&dentry->d_u.d_rcu);
        else
                call_rcu(&dentry->d_u.d_rcu, __d_free);
@@ -1701,7 +1699,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        struct dentry *dentry = __d_alloc(parent->d_sb, name);
        if (!dentry)
                return NULL;
-       dentry->d_flags |= DCACHE_RCUACCESS;
        spin_lock(&parent->d_lock);
        /*
         * don't need child lock because it is not subject
@@ -1726,7 +1723,7 @@ struct dentry *d_alloc_cursor(struct dentry * parent)
 {
        struct dentry *dentry = d_alloc_anon(parent->d_sb);
        if (dentry) {
-               dentry->d_flags |= DCACHE_RCUACCESS | DCACHE_DENTRY_CURSOR;
+               dentry->d_flags |= DCACHE_DENTRY_CURSOR;
                dentry->d_parent = dget(parent);
        }
        return dentry;
@@ -1739,12 +1736,21 @@ struct dentry *d_alloc_cursor(struct dentry * parent)
  *
  * For a filesystem that just pins its dentries in memory and never
  * performs lookups at all, return an unhashed IS_ROOT dentry.
+ * This is used for pipes, sockets et.al. - the stuff that should
+ * never be anyone's children or parents.  Unlike all other
+ * dentries, these will not have RCU delay between dropping the
+ * last reference and freeing them.
+ *
+ * The only user is alloc_file_pseudo() and that's what should
+ * be considered a public interface.  Don't use directly.
  */
 struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
 {
-       return __d_alloc(sb, name);
+       struct dentry *dentry = __d_alloc(sb, name);
+       if (likely(dentry))
+               dentry->d_flags |= DCACHE_NORCU;
+       return dentry;
 }
-EXPORT_SYMBOL(d_alloc_pseudo);
 
 struct dentry *d_alloc_name(struct dentry *parent, const char *name)
 {
@@ -1911,12 +1917,10 @@ struct dentry *d_make_root(struct inode *root_inode)
 
        if (root_inode) {
                res = d_alloc_anon(root_inode->i_sb);
-               if (res) {
-                       res->d_flags |= DCACHE_RCUACCESS;
+               if (res)
                        d_instantiate(res, root_inode);
-               } else {
+               else
                        iput(root_inode);
-               }
        }
        return res;
 }
@@ -2781,9 +2785,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
                copy_name(dentry, target);
                target->d_hash.pprev = NULL;
                dentry->d_parent->d_lockref.count++;
-               if (dentry == old_parent)
-                       dentry->d_flags |= DCACHE_RCUACCESS;
-               else
+               if (dentry != old_parent) /* wasn't IS_ROOT */
                        WARN_ON(!--old_parent->d_lockref.count);
        } else {
                target->d_parent = old_parent;