VFS: Put a small type field into struct dentry::d_flags
[firefly-linux-kernel-4.4.55.git] / fs / dcache.c
index 99d4d7226203536aaeb2956c6436d7bbc4f69f5c..525770e576db0db8085f5c3c2220095008cb2629 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/rculist_bl.h>
 #include <linux/prefetch.h>
 #include <linux/ratelimit.h>
+#include <linux/list_lru.h>
 #include "internal.h"
 #include "mount.h"
 
@@ -48,7 +49,7 @@
  *   - the dcache hash table
  * s_anon bl list spinlock protects:
  *   - the s_anon list (see __d_drop)
- * dcache_lru_lock protects:
+ * dentry->d_sb->s_dentry_lru_lock protects:
  *   - the dcache lru lists and counters
  * d_lock protects:
  *   - d_flags
@@ -63,7 +64,7 @@
  * Ordering:
  * dentry->d_inode->i_lock
  *   dentry->d_lock
- *     dcache_lru_lock
+ *     dentry->d_sb->s_dentry_lru_lock
  *     dcache_hash_bucket lock
  *     s_anon lock
  *
@@ -81,7 +82,6 @@
 int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock);
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
 
 EXPORT_SYMBOL(rename_lock);
@@ -146,23 +146,47 @@ struct dentry_stat_t dentry_stat = {
        .age_limit = 45,
 };
 
-static DEFINE_PER_CPU(unsigned int, nr_dentry);
+static DEFINE_PER_CPU(long, nr_dentry);
+static DEFINE_PER_CPU(long, nr_dentry_unused);
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
-static int get_nr_dentry(void)
+
+/*
+ * Here we resort to our own counters instead of using generic per-cpu counters
+ * for consistency with what the vfs inode code does. We are expected to harvest
+ * better code and performance by having our own specialized counters.
+ *
+ * Please note that the loop is done over all possible CPUs, not over all online
+ * CPUs. The reason for this is that we don't want to play games with CPUs going
+ * on and off. If one of them goes off, we will just keep their counters.
+ *
+ * glommer: See cffbc8a for details, and if you ever intend to change this,
+ * please update all vfs counters to match.
+ */
+static long get_nr_dentry(void)
 {
        int i;
-       int sum = 0;
+       long sum = 0;
        for_each_possible_cpu(i)
                sum += per_cpu(nr_dentry, i);
        return sum < 0 ? 0 : sum;
 }
 
+static long get_nr_dentry_unused(void)
+{
+       int i;
+       long sum = 0;
+       for_each_possible_cpu(i)
+               sum += per_cpu(nr_dentry_unused, i);
+       return sum < 0 ? 0 : sum;
+}
+
 int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
                   size_t *lenp, loff_t *ppos)
 {
        dentry_stat.nr_dentry = get_nr_dentry();
-       return proc_dointvec(table, write, buffer, lenp, ppos);
+       dentry_stat.nr_unused = get_nr_dentry_unused();
+       return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 #endif
 
@@ -319,6 +343,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
        __releases(dentry->d_inode->i_lock)
 {
        struct inode *inode = dentry->d_inode;
+       __d_clear_type(dentry);
        dentry->d_inode = NULL;
        hlist_del_init(&dentry->d_alias);
        dentry_rcuwalk_barrier(dentry);
@@ -333,52 +358,96 @@ static void dentry_unlink_inode(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
+ * The DCACHE_LRU_LIST bit is set whenever the 'd_lru' entry
+ * is in use - which includes both the "real" per-superblock
+ * LRU list _and_ the DCACHE_SHRINK_LIST use.
+ *
+ * The DCACHE_SHRINK_LIST bit is set whenever the dentry is
+ * on the shrink list (ie not on the superblock LRU list).
+ *
+ * The per-cpu "nr_dentry_unused" counters are updated with
+ * the DCACHE_LRU_LIST bit.
+ *
+ * These helper functions make sure we always follow the
+ * rules. d_lock must be held by the caller.
  */
-static void dentry_lru_add(struct dentry *dentry)
+#define D_FLAG_VERIFY(dentry,x) WARN_ON_ONCE(((dentry)->d_flags & (DCACHE_LRU_LIST | DCACHE_SHRINK_LIST)) != (x))
+static void d_lru_add(struct dentry *dentry)
 {
-       if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) {
-               spin_lock(&dcache_lru_lock);
-               dentry->d_flags |= DCACHE_LRU_LIST;
-               list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
-               dentry->d_sb->s_nr_dentry_unused++;
-               dentry_stat.nr_unused++;
-               spin_unlock(&dcache_lru_lock);
-       }
+       D_FLAG_VERIFY(dentry, 0);
+       dentry->d_flags |= DCACHE_LRU_LIST;
+       this_cpu_inc(nr_dentry_unused);
+       WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
+}
+
+static void d_lru_del(struct dentry *dentry)
+{
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags &= ~DCACHE_LRU_LIST;
+       this_cpu_dec(nr_dentry_unused);
+       WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 }
 
-static void __dentry_lru_del(struct dentry *dentry)
+static void d_shrink_del(struct dentry *dentry)
 {
+       D_FLAG_VERIFY(dentry, DCACHE_SHRINK_LIST | DCACHE_LRU_LIST);
        list_del_init(&dentry->d_lru);
        dentry->d_flags &= ~(DCACHE_SHRINK_LIST | DCACHE_LRU_LIST);
-       dentry->d_sb->s_nr_dentry_unused--;
-       dentry_stat.nr_unused--;
+       this_cpu_dec(nr_dentry_unused);
+}
+
+static void d_shrink_add(struct dentry *dentry, struct list_head *list)
+{
+       D_FLAG_VERIFY(dentry, 0);
+       list_add(&dentry->d_lru, list);
+       dentry->d_flags |= DCACHE_SHRINK_LIST | DCACHE_LRU_LIST;
+       this_cpu_inc(nr_dentry_unused);
 }
 
 /*
- * Remove a dentry with references from the LRU.
+ * These can only be called under the global LRU lock, ie during the
+ * callback for freeing the LRU list. "isolate" removes it from the
+ * LRU lists entirely, while shrink_move moves it to the indicated
+ * private list.
  */
-static void dentry_lru_del(struct dentry *dentry)
+static void d_lru_isolate(struct dentry *dentry)
 {
-       if (!list_empty(&dentry->d_lru)) {
-               spin_lock(&dcache_lru_lock);
-               __dentry_lru_del(dentry);
-               spin_unlock(&dcache_lru_lock);
-       }
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags &= ~DCACHE_LRU_LIST;
+       this_cpu_dec(nr_dentry_unused);
+       list_del_init(&dentry->d_lru);
 }
 
-static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
+static void d_lru_shrink_move(struct dentry *dentry, struct list_head *list)
 {
-       spin_lock(&dcache_lru_lock);
-       if (list_empty(&dentry->d_lru)) {
-               dentry->d_flags |= DCACHE_LRU_LIST;
-               list_add_tail(&dentry->d_lru, list);
-               dentry->d_sb->s_nr_dentry_unused++;
-               dentry_stat.nr_unused++;
-       } else {
-               list_move_tail(&dentry->d_lru, list);
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags |= DCACHE_SHRINK_LIST;
+       list_move_tail(&dentry->d_lru, list);
+}
+
+/*
+ * dentry_lru_(add|del)_list) must be called with d_lock held.
+ */
+static void dentry_lru_add(struct dentry *dentry)
+{
+       if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
+               d_lru_add(dentry);
+}
+
+/*
+ * Remove a dentry with references from the LRU.
+ *
+ * If we are on the shrink list, then we can get to try_prune_one_dentry() and
+ * lose our last reference through the parent walk. In this case, we need to
+ * remove ourselves from the shrink list, not the LRU.
+ */
+static void dentry_lru_del(struct dentry *dentry)
+{
+       if (dentry->d_flags & DCACHE_LRU_LIST) {
+               if (dentry->d_flags & DCACHE_SHRINK_LIST)
+                       return d_shrink_del(dentry);
+               d_lru_del(dentry);
        }
-       spin_unlock(&dcache_lru_lock);
 }
 
 /**
@@ -415,27 +484,6 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
        return parent;
 }
 
-/*
- * Unhash a dentry without inserting an RCU walk barrier or checking that
- * dentry->d_lock is locked.  The caller must take care of that, if
- * appropriate.
- */
-static void __d_shrink(struct dentry *dentry)
-{
-       if (!d_unhashed(dentry)) {
-               struct hlist_bl_head *b;
-               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
-                       b = &dentry->d_sb->s_anon;
-               else
-                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
-
-               hlist_bl_lock(b);
-               __hlist_bl_del(&dentry->d_hash);
-               dentry->d_hash.pprev = NULL;
-               hlist_bl_unlock(b);
-       }
-}
-
 /**
  * d_drop - drop a dentry
  * @dentry: dentry to drop
@@ -454,7 +502,16 @@ static void __d_shrink(struct dentry *dentry)
 void __d_drop(struct dentry *dentry)
 {
        if (!d_unhashed(dentry)) {
-               __d_shrink(dentry);
+               struct hlist_bl_head *b;
+               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+                       b = &dentry->d_sb->s_anon;
+               else
+                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
+
+               hlist_bl_lock(b);
+               __hlist_bl_del(&dentry->d_hash);
+               dentry->d_hash.pprev = NULL;
+               hlist_bl_unlock(b);
                dentry_rcuwalk_barrier(dentry);
        }
 }
@@ -474,7 +531,8 @@ EXPORT_SYMBOL(d_drop);
  * If ref is non-zero, then decrement the refcount too.
  * Returns dentry requiring refcount drop, or NULL if we're done.
  */
-static inline struct dentry *dentry_kill(struct dentry *dentry)
+static inline struct dentry *
+dentry_kill(struct dentry *dentry, int unlock_on_failure)
        __releases(dentry->d_lock)
 {
        struct inode *inode;
@@ -483,8 +541,10 @@ static inline struct dentry *dentry_kill(struct dentry *dentry)
        inode = dentry->d_inode;
        if (inode && !spin_trylock(&inode->i_lock)) {
 relock:
-               spin_unlock(&dentry->d_lock);
-               cpu_relax();
+               if (unlock_on_failure) {
+                       spin_unlock(&dentry->d_lock);
+                       cpu_relax();
+               }
                return dentry; /* try again with same dentry */
        }
        if (IS_ROOT(dentry))
@@ -567,7 +627,7 @@ repeat:
        return;
 
 kill_it:
-       dentry = dentry_kill(dentry);
+       dentry = dentry_kill(dentry, 1);
        if (dentry)
                goto repeat;
 }
@@ -787,12 +847,12 @@ EXPORT_SYMBOL(d_prune_aliases);
  *
  * This may fail if locks cannot be acquired no problem, just try again.
  */
-static void try_prune_one_dentry(struct dentry *dentry)
+static struct dentry * try_prune_one_dentry(struct dentry *dentry)
        __releases(dentry->d_lock)
 {
        struct dentry *parent;
 
-       parent = dentry_kill(dentry);
+       parent = dentry_kill(dentry, 0);
        /*
         * If dentry_kill returns NULL, we have nothing more to do.
         * if it returns the same dentry, trylocks failed. In either
@@ -804,17 +864,18 @@ static void try_prune_one_dentry(struct dentry *dentry)
         * fragmentation.
         */
        if (!parent)
-               return;
+               return NULL;
        if (parent == dentry)
-               return;
+               return dentry;
 
        /* Prune ancestors. */
        dentry = parent;
        while (dentry) {
                if (lockref_put_or_lock(&dentry->d_lockref))
-                       return;
-               dentry = dentry_kill(dentry);
+                       return NULL;
+               dentry = dentry_kill(dentry, 1);
        }
+       return NULL;
 }
 
 static void shrink_dentry_list(struct list_head *list)
@@ -826,83 +887,159 @@ static void shrink_dentry_list(struct list_head *list)
                dentry = list_entry_rcu(list->prev, struct dentry, d_lru);
                if (&dentry->d_lru == list)
                        break; /* empty */
+
+               /*
+                * Get the dentry lock, and re-verify that the dentry is
+                * this on the shrinking list. If it is, we know that
+                * DCACHE_SHRINK_LIST and DCACHE_LRU_LIST are set.
+                */
                spin_lock(&dentry->d_lock);
                if (dentry != list_entry(list->prev, struct dentry, d_lru)) {
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
 
+               /*
+                * The dispose list is isolated and dentries are not accounted
+                * to the LRU here, so we can simply remove it from the list
+                * here regardless of whether it is referenced or not.
+                */
+               d_shrink_del(dentry);
+
                /*
                 * We found an inuse dentry which was not removed from
-                * the LRU because of laziness during lookup.  Do not free
-                * it - just keep it off the LRU list.
+                * the LRU because of laziness during lookup. Do not free it.
                 */
                if (dentry->d_lockref.count) {
-                       dentry_lru_del(dentry);
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
-
                rcu_read_unlock();
 
-               try_prune_one_dentry(dentry);
+               /*
+                * If 'try_to_prune()' returns a dentry, it will
+                * be the same one we passed in, and d_lock will
+                * have been held the whole time, so it will not
+                * have been added to any other lists. We failed
+                * to get the inode lock.
+                *
+                * We just add it back to the shrink list.
+                */
+               dentry = try_prune_one_dentry(dentry);
 
                rcu_read_lock();
+               if (dentry) {
+                       d_shrink_add(dentry, list);
+                       spin_unlock(&dentry->d_lock);
+               }
        }
        rcu_read_unlock();
 }
 
+static enum lru_status
+dentry_lru_isolate(struct list_head *item, spinlock_t *lru_lock, void *arg)
+{
+       struct list_head *freeable = arg;
+       struct dentry   *dentry = container_of(item, struct dentry, d_lru);
+
+
+       /*
+        * we are inverting the lru lock/dentry->d_lock here,
+        * so use a trylock. If we fail to get the lock, just skip
+        * it
+        */
+       if (!spin_trylock(&dentry->d_lock))
+               return LRU_SKIP;
+
+       /*
+        * Referenced dentries are still in use. If they have active
+        * counts, just remove them from the LRU. Otherwise give them
+        * another pass through the LRU.
+        */
+       if (dentry->d_lockref.count) {
+               d_lru_isolate(dentry);
+               spin_unlock(&dentry->d_lock);
+               return LRU_REMOVED;
+       }
+
+       if (dentry->d_flags & DCACHE_REFERENCED) {
+               dentry->d_flags &= ~DCACHE_REFERENCED;
+               spin_unlock(&dentry->d_lock);
+
+               /*
+                * The list move itself will be made by the common LRU code. At
+                * this point, we've dropped the dentry->d_lock but keep the
+                * lru lock. This is safe to do, since every list movement is
+                * protected by the lru lock even if both locks are held.
+                *
+                * This is guaranteed by the fact that all LRU management
+                * functions are intermediated by the LRU API calls like
+                * list_lru_add and list_lru_del. List movement in this file
+                * only ever occur through this functions or through callbacks
+                * like this one, that are called from the LRU API.
+                *
+                * The only exceptions to this are functions like
+                * shrink_dentry_list, and code that first checks for the
+                * DCACHE_SHRINK_LIST flag.  Those are guaranteed to be
+                * operating only with stack provided lists after they are
+                * properly isolated from the main list.  It is thus, always a
+                * local access.
+                */
+               return LRU_ROTATE;
+       }
+
+       d_lru_shrink_move(dentry, freeable);
+       spin_unlock(&dentry->d_lock);
+
+       return LRU_REMOVED;
+}
+
 /**
  * prune_dcache_sb - shrink the dcache
  * @sb: superblock
- * @count: number of entries to try to free
+ * @nr_to_scan : number of entries to try to free
+ * @nid: which node to scan for freeable entities
  *
- * Attempt to shrink the superblock dcache LRU by @count entries. This is
+ * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
  * done when we need more memory an called from the superblock shrinker
  * function.
  *
  * This function may fail to free any resources if all the dentries are in
  * use.
  */
-void prune_dcache_sb(struct super_block *sb, int count)
+long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan,
+                    int nid)
 {
-       struct dentry *dentry;
-       LIST_HEAD(referenced);
-       LIST_HEAD(tmp);
+       LIST_HEAD(dispose);
+       long freed;
 
-relock:
-       spin_lock(&dcache_lru_lock);
-       while (!list_empty(&sb->s_dentry_lru)) {
-               dentry = list_entry(sb->s_dentry_lru.prev,
-                               struct dentry, d_lru);
-               BUG_ON(dentry->d_sb != sb);
-
-               if (!spin_trylock(&dentry->d_lock)) {
-                       spin_unlock(&dcache_lru_lock);
-                       cpu_relax();
-                       goto relock;
-               }
+       freed = list_lru_walk_node(&sb->s_dentry_lru, nid, dentry_lru_isolate,
+                                      &dispose, &nr_to_scan);
+       shrink_dentry_list(&dispose);
+       return freed;
+}
 
-               if (dentry->d_flags & DCACHE_REFERENCED) {
-                       dentry->d_flags &= ~DCACHE_REFERENCED;
-                       list_move(&dentry->d_lru, &referenced);
-                       spin_unlock(&dentry->d_lock);
-               } else {
-                       list_move_tail(&dentry->d_lru, &tmp);
-                       dentry->d_flags |= DCACHE_SHRINK_LIST;
-                       spin_unlock(&dentry->d_lock);
-                       if (!--count)
-                               break;
-               }
-               cond_resched_lock(&dcache_lru_lock);
-       }
-       if (!list_empty(&referenced))
-               list_splice(&referenced, &sb->s_dentry_lru);
-       spin_unlock(&dcache_lru_lock);
+static enum lru_status dentry_lru_isolate_shrink(struct list_head *item,
+                                               spinlock_t *lru_lock, void *arg)
+{
+       struct list_head *freeable = arg;
+       struct dentry   *dentry = container_of(item, struct dentry, d_lru);
+
+       /*
+        * we are inverting the lru lock/dentry->d_lock here,
+        * so use a trylock. If we fail to get the lock, just skip
+        * it
+        */
+       if (!spin_trylock(&dentry->d_lock))
+               return LRU_SKIP;
 
-       shrink_dentry_list(&tmp);
+       d_lru_shrink_move(dentry, freeable);
+       spin_unlock(&dentry->d_lock);
+
+       return LRU_REMOVED;
 }
 
+
 /**
  * shrink_dcache_sb - shrink dcache for a superblock
  * @sb: superblock
@@ -912,128 +1049,19 @@ relock:
  */
 void shrink_dcache_sb(struct super_block *sb)
 {
-       LIST_HEAD(tmp);
-
-       spin_lock(&dcache_lru_lock);
-       while (!list_empty(&sb->s_dentry_lru)) {
-               list_splice_init(&sb->s_dentry_lru, &tmp);
-               spin_unlock(&dcache_lru_lock);
-               shrink_dentry_list(&tmp);
-               spin_lock(&dcache_lru_lock);
-       }
-       spin_unlock(&dcache_lru_lock);
-}
-EXPORT_SYMBOL(shrink_dcache_sb);
-
-/*
- * destroy a single subtree of dentries for unmount
- * - see the comments on shrink_dcache_for_umount() for a description of the
- *   locking
- */
-static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
-{
-       struct dentry *parent;
+       long freed;
 
-       BUG_ON(!IS_ROOT(dentry));
-
-       for (;;) {
-               /* descend to the first leaf in the current subtree */
-               while (!list_empty(&dentry->d_subdirs))
-                       dentry = list_entry(dentry->d_subdirs.next,
-                                           struct dentry, d_u.d_child);
-
-               /* consume the dentries from this leaf up through its parents
-                * until we find one with children or run out altogether */
-               do {
-                       struct inode *inode;
-
-                       /*
-                        * inform the fs that this dentry is about to be
-                        * unhashed and destroyed.
-                        */
-                       if ((dentry->d_flags & DCACHE_OP_PRUNE) &&
-                           !d_unhashed(dentry))
-                               dentry->d_op->d_prune(dentry);
-
-                       dentry_lru_del(dentry);
-                       __d_shrink(dentry);
-
-                       if (dentry->d_lockref.count != 0) {
-                               printk(KERN_ERR
-                                      "BUG: Dentry %p{i=%lx,n=%s}"
-                                      " still in use (%d)"
-                                      " [unmount of %s %s]\n",
-                                      dentry,
-                                      dentry->d_inode ?
-                                      dentry->d_inode->i_ino : 0UL,
-                                      dentry->d_name.name,
-                                      dentry->d_lockref.count,
-                                      dentry->d_sb->s_type->name,
-                                      dentry->d_sb->s_id);
-                               BUG();
-                       }
-
-                       if (IS_ROOT(dentry)) {
-                               parent = NULL;
-                               list_del(&dentry->d_u.d_child);
-                       } else {
-                               parent = dentry->d_parent;
-                               parent->d_lockref.count--;
-                               list_del(&dentry->d_u.d_child);
-                       }
-
-                       inode = dentry->d_inode;
-                       if (inode) {
-                               dentry->d_inode = NULL;
-                               hlist_del_init(&dentry->d_alias);
-                               if (dentry->d_op && dentry->d_op->d_iput)
-                                       dentry->d_op->d_iput(dentry, inode);
-                               else
-                                       iput(inode);
-                       }
-
-                       d_free(dentry);
-
-                       /* finished when we fall off the top of the tree,
-                        * otherwise we ascend to the parent and move to the
-                        * next sibling if there is one */
-                       if (!parent)
-                               return;
-                       dentry = parent;
-               } while (list_empty(&dentry->d_subdirs));
-
-               dentry = list_entry(dentry->d_subdirs.next,
-                                   struct dentry, d_u.d_child);
-       }
-}
-
-/*
- * destroy the dentries attached to a superblock on unmounting
- * - we don't need to use dentry->d_lock because:
- *   - the superblock is detached from all mountings and open files, so the
- *     dentry trees will not be rearranged by the VFS
- *   - s_umount is write-locked, so the memory pressure shrinker will ignore
- *     any dentries belonging to this superblock that it comes across
- *   - the filesystem itself is no longer permitted to rearrange the dentries
- *     in this superblock
- */
-void shrink_dcache_for_umount(struct super_block *sb)
-{
-       struct dentry *dentry;
-
-       if (down_read_trylock(&sb->s_umount))
-               BUG();
+       do {
+               LIST_HEAD(dispose);
 
-       dentry = sb->s_root;
-       sb->s_root = NULL;
-       dentry->d_lockref.count--;
-       shrink_dcache_for_umount_subtree(dentry);
+               freed = list_lru_walk(&sb->s_dentry_lru,
+                       dentry_lru_isolate_shrink, &dispose, UINT_MAX);
 
-       while (!hlist_bl_empty(&sb->s_anon)) {
-               dentry = hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash);
-               shrink_dcache_for_umount_subtree(dentry);
-       }
+               this_cpu_sub(nr_dentry_unused, freed);
+               shrink_dentry_list(&dispose);
+       } while (freed > 0);
 }
+EXPORT_SYMBOL(shrink_dcache_sb);
 
 /*
  * This tries to ascend one level of parenthood, but
@@ -1283,8 +1311,13 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
        if (dentry->d_lockref.count) {
                dentry_lru_del(dentry);
        } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
-               dentry_lru_move_list(dentry, &data->dispose);
-               dentry->d_flags |= DCACHE_SHRINK_LIST;
+               /*
+                * We can't use d_lru_shrink_move() because we
+                * need to get the global LRU lock and do the
+                * LRU accounting.
+                */
+               d_lru_del(dentry);
+               d_shrink_add(dentry, &data->dispose);
                data->found++;
                ret = D_WALK_NORETRY;
        }
@@ -1324,6 +1357,91 @@ void shrink_dcache_parent(struct dentry *parent)
 }
 EXPORT_SYMBOL(shrink_dcache_parent);
 
+static enum d_walk_ret umount_collect(void *_data, struct dentry *dentry)
+{
+       struct select_data *data = _data;
+       enum d_walk_ret ret = D_WALK_CONTINUE;
+
+       if (dentry->d_lockref.count) {
+               dentry_lru_del(dentry);
+               if (likely(!list_empty(&dentry->d_subdirs)))
+                       goto out;
+               if (dentry == data->start && dentry->d_lockref.count == 1)
+                       goto out;
+               printk(KERN_ERR
+                      "BUG: Dentry %p{i=%lx,n=%s}"
+                      " still in use (%d)"
+                      " [unmount of %s %s]\n",
+                      dentry,
+                      dentry->d_inode ?
+                      dentry->d_inode->i_ino : 0UL,
+                      dentry->d_name.name,
+                      dentry->d_lockref.count,
+                      dentry->d_sb->s_type->name,
+                      dentry->d_sb->s_id);
+               BUG();
+       } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
+               /*
+                * We can't use d_lru_shrink_move() because we
+                * need to get the global LRU lock and do the
+                * LRU accounting.
+                */
+               if (dentry->d_flags & DCACHE_LRU_LIST)
+                       d_lru_del(dentry);
+               d_shrink_add(dentry, &data->dispose);
+               data->found++;
+               ret = D_WALK_NORETRY;
+       }
+out:
+       if (data->found && need_resched())
+               ret = D_WALK_QUIT;
+       return ret;
+}
+
+/*
+ * destroy the dentries attached to a superblock on unmounting
+ */
+void shrink_dcache_for_umount(struct super_block *sb)
+{
+       struct dentry *dentry;
+
+       if (down_read_trylock(&sb->s_umount))
+               BUG();
+
+       dentry = sb->s_root;
+       sb->s_root = NULL;
+       for (;;) {
+               struct select_data data;
+
+               INIT_LIST_HEAD(&data.dispose);
+               data.start = dentry;
+               data.found = 0;
+
+               d_walk(dentry, &data, umount_collect, NULL);
+               if (!data.found)
+                       break;
+
+               shrink_dentry_list(&data.dispose);
+               cond_resched();
+       }
+       d_drop(dentry);
+       dput(dentry);
+
+       while (!hlist_bl_empty(&sb->s_anon)) {
+               struct select_data data;
+               dentry = hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash);
+
+               INIT_LIST_HEAD(&data.dispose);
+               data.start = NULL;
+               data.found = 0;
+
+               d_walk(dentry, &data, umount_collect, NULL);
+               if (data.found)
+                       shrink_dentry_list(&data.dispose);
+               cond_resched();
+       }
+}
+
 static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry)
 {
        struct select_data *data = _data;
@@ -1531,14 +1649,42 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 }
 EXPORT_SYMBOL(d_set_d_op);
 
+static unsigned d_flags_for_inode(struct inode *inode)
+{
+       unsigned add_flags = DCACHE_FILE_TYPE;
+
+       if (!inode)
+               return DCACHE_MISS_TYPE;
+
+       if (S_ISDIR(inode->i_mode)) {
+               add_flags = DCACHE_DIRECTORY_TYPE;
+               if (unlikely(!(inode->i_opflags & IOP_LOOKUP))) {
+                       if (unlikely(!inode->i_op->lookup))
+                               add_flags = DCACHE_AUTODIR_TYPE;
+                       else
+                               inode->i_opflags |= IOP_LOOKUP;
+               }
+       } else if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
+               if (unlikely(inode->i_op->follow_link))
+                       add_flags = DCACHE_SYMLINK_TYPE;
+               else
+                       inode->i_opflags |= IOP_NOFOLLOW;
+       }
+
+       if (unlikely(IS_AUTOMOUNT(inode)))
+               add_flags |= DCACHE_NEED_AUTOMOUNT;
+       return add_flags;
+}
+
 static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 {
+       unsigned add_flags = d_flags_for_inode(inode);
+
        spin_lock(&dentry->d_lock);
-       if (inode) {
-               if (unlikely(IS_AUTOMOUNT(inode)))
-                       dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+       dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
+       dentry->d_flags |= add_flags;
+       if (inode)
                hlist_add_head(&dentry->d_alias, &inode->i_dentry);
-       }
        dentry->d_inode = inode;
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
@@ -1647,6 +1793,33 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
 
 EXPORT_SYMBOL(d_instantiate_unique);
 
+/**
+ * d_instantiate_no_diralias - instantiate a non-aliased dentry
+ * @entry: dentry to complete
+ * @inode: inode to attach to this dentry
+ *
+ * Fill in inode information in the entry.  If a directory alias is found, then
+ * return an error (and drop inode).  Together with d_materialise_unique() this
+ * guarantees that a directory inode may never have more than one alias.
+ */
+int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
+{
+       BUG_ON(!hlist_unhashed(&entry->d_alias));
+
+       spin_lock(&inode->i_lock);
+       if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
+               spin_unlock(&inode->i_lock);
+               iput(inode);
+               return -EBUSY;
+       }
+       __d_instantiate(entry, inode);
+       spin_unlock(&inode->i_lock);
+       security_d_instantiate(entry, inode);
+
+       return 0;
+}
+EXPORT_SYMBOL(d_instantiate_no_diralias);
+
 struct dentry *d_make_root(struct inode *root_inode)
 {
        struct dentry *res = NULL;
@@ -1716,6 +1889,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
        static const struct qstr anonstring = QSTR_INIT("/", 1);
        struct dentry *tmp;
        struct dentry *res;
+       unsigned add_flags;
 
        if (!inode)
                return ERR_PTR(-ESTALE);
@@ -1741,9 +1915,11 @@ struct dentry *d_obtain_alias(struct inode *inode)
        }
 
        /* attach a disconnected dentry */
+       add_flags = d_flags_for_inode(inode) | DCACHE_DISCONNECTED;
+
        spin_lock(&tmp->d_lock);
        tmp->d_inode = inode;
-       tmp->d_flags |= DCACHE_DISCONNECTED;
+       tmp->d_flags |= add_flags;
        hlist_add_head(&tmp->d_alias, &inode->i_dentry);
        hlist_bl_lock(&tmp->d_sb->s_anon);
        hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
@@ -2731,23 +2907,28 @@ static int prepend_path(const struct path *path,
        struct vfsmount *vfsmnt = path->mnt;
        struct mount *mnt = real_mount(vfsmnt);
        int error = 0;
-       unsigned seq = 0;
+       unsigned seq, m_seq = 0;
        char *bptr;
        int blen;
 
        rcu_read_lock();
+restart_mnt:
+       read_seqbegin_or_lock(&mount_lock, &m_seq);
+       seq = 0;
 restart:
        bptr = *buffer;
        blen = *buflen;
+       error = 0;
        read_seqbegin_or_lock(&rename_lock, &seq);
        while (dentry != root->dentry || vfsmnt != root->mnt) {
                struct dentry * parent;
 
                if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+                       struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
                        /* Global root? */
-                       if (mnt_has_parent(mnt)) {
-                               dentry = mnt->mnt_mountpoint;
-                               mnt = mnt->mnt_parent;
+                       if (mnt != parent) {
+                               dentry = ACCESS_ONCE(mnt->mnt_mountpoint);
+                               mnt = parent;
                                vfsmnt = &mnt->mnt;
                                continue;
                        }
@@ -2781,6 +2962,11 @@ restart:
                goto restart;
        }
        done_seqretry(&rename_lock, seq);
+       if (need_seqretry(&mount_lock, m_seq)) {
+               m_seq = 1;
+               goto restart_mnt;
+       }
+       done_seqretry(&mount_lock, m_seq);
 
        if (error >= 0 && bptr == *buffer) {
                if (--blen < 0)
@@ -2817,9 +3003,7 @@ char *__d_path(const struct path *path,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
-       br_read_lock(&vfsmount_lock);
        error = prepend_path(path, root, &res, &buflen);
-       br_read_unlock(&vfsmount_lock);
 
        if (error < 0)
                return ERR_PTR(error);
@@ -2836,9 +3020,7 @@ char *d_absolute_path(const struct path *path,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
-       br_read_lock(&vfsmount_lock);
        error = prepend_path(path, &root, &res, &buflen);
-       br_read_unlock(&vfsmount_lock);
 
        if (error > 1)
                error = -EINVAL;
@@ -2869,6 +3051,16 @@ static int prepend_unreachable(char **buffer, int *buflen)
        return prepend(buffer, buflen, "(unreachable)", 13);
 }
 
+static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
+{
+       unsigned seq;
+
+       do {
+               seq = read_seqcount_begin(&fs->seq);
+               *root = fs->root;
+       } while (read_seqcount_retry(&fs->seq, seq));
+}
+
 /**
  * d_path - return the path of a dentry
  * @path: path to report
@@ -2901,13 +3093,13 @@ char *d_path(const struct path *path, char *buf, int buflen)
        if (path->dentry->d_op && path->dentry->d_op->d_dname)
                return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
 
-       get_fs_root(current->fs, &root);
-       br_read_lock(&vfsmount_lock);
+       rcu_read_lock();
+       get_fs_root_rcu(current->fs, &root);
        error = path_with_deleted(path, &root, &res, &buflen);
-       br_read_unlock(&vfsmount_lock);
+       rcu_read_unlock();
+
        if (error < 0)
                res = ERR_PTR(error);
-       path_put(&root);
        return res;
 }
 EXPORT_SYMBOL(d_path);
@@ -3049,7 +3241,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 {
        int error;
        struct path pwd, root;
-       char *page = (char *) __get_free_page(GFP_USER);
+       char *page = __getname();
 
        if (!page)
                return -ENOMEM;
@@ -3058,15 +3250,14 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
        get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
 
        error = -ENOENT;
-       br_read_lock(&vfsmount_lock);
        if (!d_unlinked(pwd.dentry)) {
                unsigned long len;
-               char *cwd = page + PAGE_SIZE;
-               int buflen = PAGE_SIZE;
+               char *cwd = page + PATH_MAX;
+               int buflen = PATH_MAX;
 
                prepend(&cwd, &buflen, "\0", 1);
                error = prepend_path(&pwd, &root, &cwd, &buflen);
-               br_read_unlock(&vfsmount_lock);
+               rcu_read_unlock();
 
                if (error < 0)
                        goto out;
@@ -3079,19 +3270,18 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
                }
 
                error = -ERANGE;
-               len = PAGE_SIZE + page - cwd;
+               len = PATH_MAX + page - cwd;
                if (len <= size) {
                        error = len;
                        if (copy_to_user(buf, cwd, len))
                                error = -EFAULT;
                }
        } else {
-               br_read_unlock(&vfsmount_lock);
+               rcu_read_unlock();
        }
 
 out:
-       rcu_read_unlock();
-       free_page((unsigned long) page);
+       __putname(page);
        return error;
 }