]> Git Repo - linux.git/commitdiff
Merge tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <[email protected]>
Fri, 12 Jan 2024 04:11:35 +0000 (20:11 -0800)
committerLinus Torvalds <[email protected]>
Fri, 12 Jan 2024 04:11:35 +0000 (20:11 -0800)
Pull dcache updates from Al Viro:
 "Change of locking rules for __dentry_kill(), regularized refcounting
  rules in that area, assorted cleanups and removal of weird corner
  cases (e.g. now ->d_iput() on child is always called before the parent
  might hit __dentry_kill(), etc)"

* tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
  dcache: remove unnecessary NULL check in dget_dlock()
  kill DCACHE_MAY_FREE
  __d_unalias() doesn't use inode argument
  d_alloc_parallel(): in-lookup hash insertion doesn't need an RCU variant
  get rid of DCACHE_GENOCIDE
  d_genocide(): move the extern into fs/internal.h
  simple_fill_super(): don't bother with d_genocide() on failure
  nsfs: use d_make_root()
  d_alloc_pseudo(): move setting ->d_op there from the (sole) caller
  kill d_instantate_anon(), fold __d_instantiate_anon() into remaining caller
  retain_dentry(): introduce a trimmed-down lockless variant
  __dentry_kill(): new locking scheme
  d_prune_aliases(): use a shrink list
  switch select_collect{,2}() to use of to_shrink_list()
  to_shrink_list(): call only if refcount is 0
  fold dentry_kill() into dput()
  don't try to cut corners in shrink_lock_dentry()
  fold the call of retain_dentry() into fast_dput()
  Call retain_dentry() with refcount 0
  dentry_kill(): don't bother with retain_dentry() on slow path
  ...

1  2 
Documentation/filesystems/porting.rst
fs/afs/dynroot.c
fs/dcache.c
fs/file_table.c
fs/internal.h
fs/libfs.c
fs/nfsd/nfsctl.c
fs/overlayfs/export.c
fs/tracefs/inode.c

index c549fb2fc3ba7adb85edbdb573f2b801215372b1,d890ef07a9fdff726fa357c3efb9d7a8dda16bb4..1be76ef117b3f80051713c8dc24f0f2568248075
@@@ -1066,37 -1066,32 +1066,71 @@@ generic_encode_ino32_fh() explicitly
  
  **mandatory**
  
 ---
 +If ->rename() update of .. on cross-directory move needs an exclusion with
 +directory modifications, do *not* lock the subdirectory in question in your
 +->rename() - it's done by the caller now [that item should've been added in
 +28eceeda130f "fs: Lock moved directories"].
 +
 +---
 +
 +**mandatory**
 +
 +On same-directory ->rename() the (tautological) update of .. is not protected
 +by any locks; just don't do it if the old parent is the same as the new one.
 +We really can't lock two subdirectories in same-directory rename - not without
 +deadlocks.
 +
 +---
 +
 +**mandatory**
 +
 +lock_rename() and lock_rename_child() may fail in cross-directory case, if
 +their arguments do not have a common ancestor.  In that case ERR_PTR(-EXDEV)
 +is returned, with no locks taken.  In-tree users updated; out-of-tree ones
 +would need to do so.
 +
 +---
 +
++**mandatory**
++
+ The list of children anchored in parent dentry got turned into hlist now.
+ Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child
+ for anchor/entries resp.), so any affected places will be immediately caught
+ by compiler.
+ ---
+ **mandatory**
+ ->d_delete() instances are now called for dentries with ->d_lock held
+ and refcount equal to 0.  They are not permitted to drop/regain ->d_lock.
+ None of in-tree instances did anything of that sort.  Make sure yours do not...
++---
+ **mandatory**
+ ->d_prune() instances are now called without ->d_lock held on the parent.
+ ->d_lock on dentry itself is still held; if you need per-parent exclusions (none
+ of the in-tree instances did), use your own spinlock.
+ ->d_iput() and ->d_release() are called with victim dentry still in the
+ list of parent's children.  It is still unhashed, marked killed, etc., just not
+ removed from parent's ->d_children yet.
+ Anyone iterating through the list of children needs to be aware of the
+ half-killed dentries that might be seen there; taking ->d_lock on those will
+ see them negative, unhashed and with negative refcount, which means that most
+ of the in-kernel users would've done the right thing anyway without any adjustment.
++
++---
++
 +**recommended**
 +
 +Block device freezing and thawing have been moved to holder operations.
 +
 +Before this change, get_active_super() would only be able to find the
 +superblock of the main block device, i.e., the one stored in sb->s_bdev. Block
 +device freezing now works for any block device owned by a given superblock, not
 +just the main block device. The get_active_super() helper and bd_fsfreeze_sb
 +pointer are gone.
diff --combined fs/afs/dynroot.c
index 1f656005018ea07db18ed3944548ed0424dbab67,fe45462834ccd60befbae517f6e5602f8ab3bf6d..2cd40ba601f1cd45a8f80106b8c550cb5e3d94a7
@@@ -114,7 -114,6 +114,7 @@@ static int afs_probe_cell_name(struct d
        struct afs_net *net = afs_d2net(dentry);
        const char *name = dentry->d_name.name;
        size_t len = dentry->d_name.len;
 +      char *result = NULL;
        int ret;
  
        /* Names prefixed with a dot are R/W mounts. */
        }
  
        ret = dns_query(net->net, "afsdb", name, len, "srv=1",
 -                      NULL, NULL, false);
 -      if (ret == -ENODATA)
 -              ret = -EDESTADDRREQ;
 +                      &result, NULL, false);
 +      if (ret == -ENODATA || ret == -ENOKEY || ret == 0)
 +              ret = -ENOENT;
 +      if (ret > 0 && ret >= sizeof(struct dns_server_list_v1_header)) {
 +              struct dns_server_list_v1_header *v1 = (void *)result;
 +
 +              if (v1->hdr.zero == 0 &&
 +                  v1->hdr.content == DNS_PAYLOAD_IS_SERVER_LIST &&
 +                  v1->hdr.version == 1 &&
 +                  (v1->status != DNS_LOOKUP_GOOD &&
 +                   v1->status != DNS_LOOKUP_GOOD_WITH_BAD))
 +                      return -ENOENT;
 +
 +      }
 +
 +      kfree(result);
        return ret;
  }
  
@@@ -266,9 -252,20 +266,9 @@@ static int afs_dynroot_d_revalidate(str
        return 1;
  }
  
 -/*
 - * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
 - * sleep)
 - * - called from dput() when d_count is going to 0.
 - * - return 1 to request dentry be unhashed, 0 otherwise
 - */
 -static int afs_dynroot_d_delete(const struct dentry *dentry)
 -{
 -      return d_really_is_positive(dentry);
 -}
 -
  const struct dentry_operations afs_dynroot_dentry_operations = {
        .d_revalidate   = afs_dynroot_d_revalidate,
 -      .d_delete       = afs_dynroot_d_delete,
 +      .d_delete       = always_delete_dentry,
        .d_release      = afs_d_release,
        .d_automount    = afs_d_automount,
  };
@@@ -373,7 -370,7 +373,7 @@@ error
  void afs_dynroot_depopulate(struct super_block *sb)
  {
        struct afs_net *net = afs_sb2net(sb);
-       struct dentry *root = sb->s_root, *subdir, *tmp;
+       struct dentry *root = sb->s_root, *subdir;
  
        /* Prevent more subdirs from being created */
        mutex_lock(&net->proc_cells_lock);
        mutex_unlock(&net->proc_cells_lock);
  
        if (root) {
+               struct hlist_node *n;
                inode_lock(root->d_inode);
  
                /* Remove all the pins for dirs created for manually added cells */
-               list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
+               hlist_for_each_entry_safe(subdir, n, &root->d_children, d_sib) {
                        if (subdir->d_fsdata) {
                                subdir->d_fsdata = NULL;
                                dput(subdir);
diff --combined fs/dcache.c
index df49d29ca15453399f822ea4db0c8179be42446a,bb18ea91d717978ea9b07c0c027815ebe91d0ff0..b813528fb147784c6f308e67d47f3069e3a96e33
@@@ -51,8 -51,8 +51,8 @@@
   *   - d_lru
   *   - d_count
   *   - d_unhashed()
-  *   - d_parent and d_subdirs
-  *   - childrens' d_child and d_parent
+  *   - d_parent and d_chilren
+  *   - childrens' d_sib and d_parent
   *   - d_u.d_alias, d_inode
   *
   * Ordering:
@@@ -191,6 -191,7 +191,6 @@@ static struct ctl_table fs_dcache_sysct
                .mode           = 0444,
                .proc_handler   = proc_nr_dentry,
        },
 -      { }
  };
  
  static int __init init_fs_dcache_sysctls(void)
@@@ -343,7 -344,7 +343,7 @@@ static inline void __d_set_inode_and_ty
  
        dentry->d_inode = inode;
        flags = READ_ONCE(dentry->d_flags);
-       flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
+       flags &= ~DCACHE_ENTRY_TYPE;
        flags |= type_flags;
        smp_store_release(&dentry->d_flags, flags);
  }
@@@ -352,7 -353,7 +352,7 @@@ static inline void __d_clear_type_and_i
  {
        unsigned flags = READ_ONCE(dentry->d_flags);
  
-       flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
+       flags &= ~DCACHE_ENTRY_TYPE;
        WRITE_ONCE(dentry->d_flags, flags);
        dentry->d_inode = NULL;
        if (dentry->d_flags & DCACHE_LRU_LIST)
@@@ -427,8 -428,7 +427,8 @@@ static void d_lru_add(struct dentry *de
        this_cpu_inc(nr_dentry_unused);
        if (d_is_negative(dentry))
                this_cpu_inc(nr_dentry_negative);
 -      WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 +      WARN_ON_ONCE(!list_lru_add_obj(
 +                      &dentry->d_sb->s_dentry_lru, &dentry->d_lru));
  }
  
  static void d_lru_del(struct dentry *dentry)
        this_cpu_dec(nr_dentry_unused);
        if (d_is_negative(dentry))
                this_cpu_dec(nr_dentry_negative);
 -      WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 +      WARN_ON_ONCE(!list_lru_del_obj(
 +                      &dentry->d_sb->s_dentry_lru, &dentry->d_lru));
  }
  
  static void d_shrink_del(struct dentry *dentry)
@@@ -538,7 -537,7 +538,7 @@@ void d_drop(struct dentry *dentry
  }
  EXPORT_SYMBOL(d_drop);
  
- static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent)
+ static inline void dentry_unlist(struct dentry *dentry)
  {
        struct dentry *next;
        /*
         * attached to the dentry tree
         */
        dentry->d_flags |= DCACHE_DENTRY_KILLED;
-       if (unlikely(list_empty(&dentry->d_child)))
+       if (unlikely(hlist_unhashed(&dentry->d_sib)))
                return;
-       __list_del_entry(&dentry->d_child);
+       __hlist_del(&dentry->d_sib);
        /*
         * Cursors can move around the list of children.  While we'd been
-        * a normal list member, it didn't matter - ->d_child.next would've
+        * a normal list member, it didn't matter - ->d_sib.next would've
         * been updated.  However, from now on it won't be and for the
         * things like d_walk() it might end up with a nasty surprise.
         * Normally d_walk() doesn't care about cursors moving around -
         * of its own, we get through it without ever unlocking the parent.
         * There is one exception, though - if we ascend from a child that
         * gets killed as soon as we unlock it, the next sibling is found
-        * using the value left in its ->d_child.next.  And if _that_
+        * using the value left in its ->d_sib.next.  And if _that_
         * pointed to a cursor, and cursor got moved (e.g. by lseek())
         * before d_walk() regains parent->d_lock, we'll end up skipping
         * everything the cursor had been moved past.
         *
-        * Solution: make sure that the pointer left behind in ->d_child.next
+        * Solution: make sure that the pointer left behind in ->d_sib.next
         * points to something that won't be moving around.  I.e. skip the
         * cursors.
         */
-       while (dentry->d_child.next != &parent->d_subdirs) {
-               next = list_entry(dentry->d_child.next, struct dentry, d_child);
+       while (dentry->d_sib.next) {
+               next = hlist_entry(dentry->d_sib.next, struct dentry, d_sib);
                if (likely(!(next->d_flags & DCACHE_DENTRY_CURSOR)))
                        break;
-               dentry->d_child.next = next->d_child.next;
+               dentry->d_sib.next = next->d_sib.next;
        }
  }
  
- static void __dentry_kill(struct dentry *dentry)
+ static struct dentry *__dentry_kill(struct dentry *dentry)
  {
        struct dentry *parent = NULL;
        bool can_free = true;
-       if (!IS_ROOT(dentry))
-               parent = dentry->d_parent;
  
        /*
         * The dentry is now unrecoverably dead to the world.
        }
        /* if it was on the hash then remove it */
        __d_drop(dentry);
-       dentry_unlist(dentry, parent);
-       if (parent)
-               spin_unlock(&parent->d_lock);
        if (dentry->d_inode)
                dentry_unlink_inode(dentry);
        else
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
  
-       spin_lock(&dentry->d_lock);
-       if (dentry->d_flags & DCACHE_SHRINK_LIST) {
-               dentry->d_flags |= DCACHE_MAY_FREE;
-               can_free = false;
+       cond_resched();
+       /* now that it's negative, ->d_parent is stable */
+       if (!IS_ROOT(dentry)) {
+               parent = dentry->d_parent;
+               spin_lock(&parent->d_lock);
        }
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+       dentry_unlist(dentry);
+       if (dentry->d_flags & DCACHE_SHRINK_LIST)
+               can_free = false;
        spin_unlock(&dentry->d_lock);
        if (likely(can_free))
                dentry_free(dentry);
-       cond_resched();
- }
- static struct dentry *__lock_parent(struct dentry *dentry)
- {
-       struct dentry *parent;
-       rcu_read_lock();
-       spin_unlock(&dentry->d_lock);
- again:
-       parent = READ_ONCE(dentry->d_parent);
-       spin_lock(&parent->d_lock);
-       /*
-        * We can't blindly lock dentry until we are sure
-        * that we won't violate the locking order.
-        * Any changes of dentry->d_parent must have
-        * been done with parent->d_lock held, so
-        * spin_lock() above is enough of a barrier
-        * for checking if it's still our child.
-        */
-       if (unlikely(parent != dentry->d_parent)) {
+       if (parent && --parent->d_lockref.count) {
                spin_unlock(&parent->d_lock);
-               goto again;
+               return NULL;
        }
-       rcu_read_unlock();
-       if (parent != dentry)
-               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-       else
-               parent = NULL;
        return parent;
  }
  
- static inline struct dentry *lock_parent(struct dentry *dentry)
+ /*
+  * Lock a dentry for feeding it to __dentry_kill().
+  * Called under rcu_read_lock() and dentry->d_lock; the former
+  * guarantees that nothing we access will be freed under us.
+  * Note that dentry is *not* protected from concurrent dentry_kill(),
+  * d_delete(), etc.
+  *
+  * Return false if dentry is busy.  Otherwise, return true and have
+  * that dentry's inode locked.
+  */
+ static bool lock_for_kill(struct dentry *dentry)
  {
-       struct dentry *parent = dentry->d_parent;
-       if (IS_ROOT(dentry))
-               return NULL;
-       if (likely(spin_trylock(&parent->d_lock)))
-               return parent;
-       return __lock_parent(dentry);
+       struct inode *inode = dentry->d_inode;
+       if (unlikely(dentry->d_lockref.count))
+               return false;
+       if (!inode || likely(spin_trylock(&inode->i_lock)))
+               return true;
+       do {
+               spin_unlock(&dentry->d_lock);
+               spin_lock(&inode->i_lock);
+               spin_lock(&dentry->d_lock);
+               if (likely(inode == dentry->d_inode))
+                       break;
+               spin_unlock(&inode->i_lock);
+               inode = dentry->d_inode;
+       } while (inode);
+       if (likely(!dentry->d_lockref.count))
+               return true;
+       if (inode)
+               spin_unlock(&inode->i_lock);
+       return false;
  }
  
- static inline bool retain_dentry(struct dentry *dentry)
+ /*
+  * Decide if dentry is worth retaining.  Usually this is called with dentry
+  * locked; if not locked, we are more limited and might not be able to tell
+  * without a lock.  False in this case means "punt to locked path and recheck".
+  *
+  * In case we aren't locked, these predicates are not "stable". However, it is
+  * sufficient that at some point after we dropped the reference the dentry was
+  * hashed and the flags had the proper value. Other dentry users may have
+  * re-gotten a reference to the dentry and change that, but our work is done -
+  * we can leave the dentry around with a zero refcount.
+  */
+ static inline bool retain_dentry(struct dentry *dentry, bool locked)
  {
-       WARN_ON(d_in_lookup(dentry));
+       unsigned int d_flags;
  
-       /* Unreachable? Get rid of it */
+       smp_rmb();
+       d_flags = READ_ONCE(dentry->d_flags);
+       // Unreachable? Nobody would be able to look it up, no point retaining
        if (unlikely(d_unhashed(dentry)))
                return false;
  
-       if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+       // Same if it's disconnected
+       if (unlikely(d_flags & DCACHE_DISCONNECTED))
                return false;
  
-       if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
-               if (dentry->d_op->d_delete(dentry))
+       // ->d_delete() might tell us not to bother, but that requires
+       // ->d_lock; can't decide without it
+       if (unlikely(d_flags & DCACHE_OP_DELETE)) {
+               if (!locked || dentry->d_op->d_delete(dentry))
                        return false;
        }
  
-       if (unlikely(dentry->d_flags & DCACHE_DONTCACHE))
+       // Explicitly told not to bother
+       if (unlikely(d_flags & DCACHE_DONTCACHE))
                return false;
  
-       /* retain; LRU fodder */
-       dentry->d_lockref.count--;
-       if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
+       // At this point it looks like we ought to keep it.  We also might
+       // need to do something - put it on LRU if it wasn't there already
+       // and mark it referenced if it was on LRU, but not marked yet.
+       // Unfortunately, both actions require ->d_lock, so in lockless
+       // case we'd have to punt rather than doing those.
+       if (unlikely(!(d_flags & DCACHE_LRU_LIST))) {
+               if (!locked)
+                       return false;
                d_lru_add(dentry);
-       else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED)))
+       } else if (unlikely(!(d_flags & DCACHE_REFERENCED))) {
+               if (!locked)
+                       return false;
                dentry->d_flags |= DCACHE_REFERENCED;
+       }
        return true;
  }
  
@@@ -704,61 -732,12 +733,12 @@@ void d_mark_dontcache(struct inode *ino
  }
  EXPORT_SYMBOL(d_mark_dontcache);
  
- /*
-  * Finish off a dentry we've decided to kill.
-  * dentry->d_lock must be held, returns with it unlocked.
-  * Returns dentry requiring refcount drop, or NULL if we're done.
-  */
- static struct dentry *dentry_kill(struct dentry *dentry)
-       __releases(dentry->d_lock)
- {
-       struct inode *inode = dentry->d_inode;
-       struct dentry *parent = NULL;
-       if (inode && unlikely(!spin_trylock(&inode->i_lock)))
-               goto slow_positive;
-       if (!IS_ROOT(dentry)) {
-               parent = dentry->d_parent;
-               if (unlikely(!spin_trylock(&parent->d_lock))) {
-                       parent = __lock_parent(dentry);
-                       if (likely(inode || !dentry->d_inode))
-                               goto got_locks;
-                       /* negative that became positive */
-                       if (parent)
-                               spin_unlock(&parent->d_lock);
-                       inode = dentry->d_inode;
-                       goto slow_positive;
-               }
-       }
-       __dentry_kill(dentry);
-       return parent;
- slow_positive:
-       spin_unlock(&dentry->d_lock);
-       spin_lock(&inode->i_lock);
-       spin_lock(&dentry->d_lock);
-       parent = lock_parent(dentry);
- got_locks:
-       if (unlikely(dentry->d_lockref.count != 1)) {
-               dentry->d_lockref.count--;
-       } else if (likely(!retain_dentry(dentry))) {
-               __dentry_kill(dentry);
-               return parent;
-       }
-       /* we are keeping it, after all */
-       if (inode)
-               spin_unlock(&inode->i_lock);
-       if (parent)
-               spin_unlock(&parent->d_lock);
-       spin_unlock(&dentry->d_lock);
-       return NULL;
- }
  /*
   * Try to do a lockless dput(), and return whether that was successful.
   *
   * If unsuccessful, we return false, having already taken the dentry lock.
+  * In that case refcount is guaranteed to be zero and we have already
+  * decided that it's not worth keeping around.
   *
   * The caller needs to hold the RCU read lock, so that the dentry is
   * guaranteed to stay around even if the refcount goes down to zero!
  static inline bool fast_dput(struct dentry *dentry)
  {
        int ret;
-       unsigned int d_flags;
-       /*
-        * If we have a d_op->d_delete() operation, we sould not
-        * let the dentry count go to zero, so use "put_or_lock".
-        */
-       if (unlikely(dentry->d_flags & DCACHE_OP_DELETE))
-               return lockref_put_or_lock(&dentry->d_lockref);
  
        /*
-        * .. otherwise, we can try to just decrement the
-        * lockref optimistically.
+        * try to decrement the lockref optimistically.
         */
        ret = lockref_put_return(&dentry->d_lockref);
  
         */
        if (unlikely(ret < 0)) {
                spin_lock(&dentry->d_lock);
-               if (dentry->d_lockref.count > 1) {
-                       dentry->d_lockref.count--;
+               if (WARN_ON_ONCE(dentry->d_lockref.count <= 0)) {
                        spin_unlock(&dentry->d_lock);
                        return true;
                }
-               return false;
+               dentry->d_lockref.count--;
+               goto locked;
        }
  
        /*
                return true;
  
        /*
-        * Careful, careful. The reference count went down
-        * to zero, but we don't hold the dentry lock, so
-        * somebody else could get it again, and do another
-        * dput(), and we need to not race with that.
-        *
-        * However, there is a very special and common case
-        * where we don't care, because there is nothing to
-        * do: the dentry is still hashed, it does not have
-        * a 'delete' op, and it's referenced and already on
-        * the LRU list.
-        *
-        * NOTE! Since we aren't locked, these values are
-        * not "stable". However, it is sufficient that at
-        * some point after we dropped the reference the
-        * dentry was hashed and the flags had the proper
-        * value. Other dentry users may have re-gotten
-        * a reference to the dentry and change that, but
-        * our work is done - we can leave the dentry
-        * around with a zero refcount.
-        *
-        * Nevertheless, there are two cases that we should kill
-        * the dentry anyway.
-        * 1. free disconnected dentries as soon as their refcount
-        *    reached zero.
-        * 2. free dentries if they should not be cached.
+        * Can we decide that decrement of refcount is all we needed without
+        * taking the lock?  There's a very common case when it's all we need -
+        * dentry looks like it ought to be retained and there's nothing else
+        * to do.
         */
-       smp_rmb();
-       d_flags = READ_ONCE(dentry->d_flags);
-       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST |
-                       DCACHE_DISCONNECTED | DCACHE_DONTCACHE;
-       /* Nothing to do? Dropping the reference was all we needed? */
-       if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry))
+       if (retain_dentry(dentry, false))
                return true;
  
        /*
-        * Not the fast normal case? Get the lock. We've already decremented
-        * the refcount, but we'll need to re-check the situation after
-        * getting the lock.
+        * Either not worth retaining or we can't tell without the lock.
+        * Get the lock, then.  We've already decremented the refcount to 0,
+        * but we'll need to re-check the situation after getting the lock.
         */
        spin_lock(&dentry->d_lock);
  
         * else could have killed it and marked it dead. Either way, we
         * don't need to do anything else.
         */
-       if (dentry->d_lockref.count) {
+ locked:
+       if (dentry->d_lockref.count || retain_dentry(dentry, true)) {
                spin_unlock(&dentry->d_lock);
                return true;
        }
-       /*
-        * Re-get the reference we optimistically dropped. We hold the
-        * lock, and we just tested that it was zero, so we can just
-        * set it to 1.
-        */
-       dentry->d_lockref.count = 1;
        return false;
  }
  
   */
  void dput(struct dentry *dentry)
  {
-       while (dentry) {
-               might_sleep();
-               rcu_read_lock();
-               if (likely(fast_dput(dentry))) {
-                       rcu_read_unlock();
-                       return;
-               }
-               /* Slow case: now with the dentry lock held */
+       if (!dentry)
+               return;
+       might_sleep();
+       rcu_read_lock();
+       if (likely(fast_dput(dentry))) {
                rcu_read_unlock();
-               if (likely(retain_dentry(dentry))) {
+               return;
+       }
+       while (lock_for_kill(dentry)) {
+               rcu_read_unlock();
+               dentry = __dentry_kill(dentry);
+               if (!dentry)
+                       return;
+               if (retain_dentry(dentry, true)) {
                        spin_unlock(&dentry->d_lock);
                        return;
                }
-               dentry = dentry_kill(dentry);
+               rcu_read_lock();
        }
+       rcu_read_unlock();
+       spin_unlock(&dentry->d_lock);
  }
  EXPORT_SYMBOL(dput);
  
- static void __dput_to_list(struct dentry *dentry, struct list_head *list)
+ static void to_shrink_list(struct dentry *dentry, struct list_head *list)
  __must_hold(&dentry->d_lock)
  {
-       if (dentry->d_flags & DCACHE_SHRINK_LIST) {
-               /* let the owner of the list it's on deal with it */
-               --dentry->d_lockref.count;
-       } else {
+       if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
                if (dentry->d_flags & DCACHE_LRU_LIST)
                        d_lru_del(dentry);
-               if (!--dentry->d_lockref.count)
-                       d_shrink_add(dentry, list);
+               d_shrink_add(dentry, list);
        }
  }
  
@@@ -938,22 -873,10 +874,10 @@@ void dput_to_list(struct dentry *dentry
                return;
        }
        rcu_read_unlock();
-       if (!retain_dentry(dentry))
-               __dput_to_list(dentry, list);
+       to_shrink_list(dentry, list);
        spin_unlock(&dentry->d_lock);
  }
  
- /* This must be called with d_lock held */
- static inline void __dget_dlock(struct dentry *dentry)
- {
-       dentry->d_lockref.count++;
- }
- static inline void __dget(struct dentry *dentry)
- {
-       lockref_get(&dentry->d_lockref);
- }
  struct dentry *dget_parent(struct dentry *dentry)
  {
        int gotref;
@@@ -1003,7 -926,7 +927,7 @@@ static struct dentry * __d_find_any_ali
        if (hlist_empty(&inode->i_dentry))
                return NULL;
        alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
-       __dget(alias);
+       lockref_get(&alias->d_lockref);
        return alias;
  }
  
@@@ -1035,7 -958,7 +959,7 @@@ static struct dentry *__d_find_alias(st
        hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
                spin_lock(&alias->d_lock);
                if (!d_unhashed(alias)) {
-                       __dget_dlock(alias);
+                       dget_dlock(alias);
                        spin_unlock(&alias->d_lock);
                        return alias;
                }
@@@ -1102,104 -1025,53 +1026,53 @@@ struct dentry *d_find_alias_rcu(struct 
   */
  void d_prune_aliases(struct inode *inode)
  {
+       LIST_HEAD(dispose);
        struct dentry *dentry;
- restart:
        spin_lock(&inode->i_lock);
        hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
                spin_lock(&dentry->d_lock);
-               if (!dentry->d_lockref.count) {
-                       struct dentry *parent = lock_parent(dentry);
-                       if (likely(!dentry->d_lockref.count)) {
-                               __dentry_kill(dentry);
-                               dput(parent);
-                               goto restart;
-                       }
-                       if (parent)
-                               spin_unlock(&parent->d_lock);
-               }
+               if (!dentry->d_lockref.count)
+                       to_shrink_list(dentry, &dispose);
                spin_unlock(&dentry->d_lock);
        }
        spin_unlock(&inode->i_lock);
+       shrink_dentry_list(&dispose);
  }
  EXPORT_SYMBOL(d_prune_aliases);
  
- /*
-  * Lock a dentry from shrink list.
-  * Called under rcu_read_lock() and dentry->d_lock; the former
-  * guarantees that nothing we access will be freed under us.
-  * Note that dentry is *not* protected from concurrent dentry_kill(),
-  * d_delete(), etc.
-  *
-  * Return false if dentry has been disrupted or grabbed, leaving
-  * the caller to kick it off-list.  Otherwise, return true and have
-  * that dentry's inode and parent both locked.
-  */
- static bool shrink_lock_dentry(struct dentry *dentry)
+ static inline void shrink_kill(struct dentry *victim)
  {
-       struct inode *inode;
-       struct dentry *parent;
-       if (dentry->d_lockref.count)
-               return false;
-       inode = dentry->d_inode;
-       if (inode && unlikely(!spin_trylock(&inode->i_lock))) {
-               spin_unlock(&dentry->d_lock);
-               spin_lock(&inode->i_lock);
-               spin_lock(&dentry->d_lock);
-               if (unlikely(dentry->d_lockref.count))
-                       goto out;
-               /* changed inode means that somebody had grabbed it */
-               if (unlikely(inode != dentry->d_inode))
-                       goto out;
-       }
-       parent = dentry->d_parent;
-       if (IS_ROOT(dentry) || likely(spin_trylock(&parent->d_lock)))
-               return true;
-       spin_unlock(&dentry->d_lock);
-       spin_lock(&parent->d_lock);
-       if (unlikely(parent != dentry->d_parent)) {
-               spin_unlock(&parent->d_lock);
-               spin_lock(&dentry->d_lock);
-               goto out;
-       }
-       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-       if (likely(!dentry->d_lockref.count))
-               return true;
-       spin_unlock(&parent->d_lock);
- out:
-       if (inode)
-               spin_unlock(&inode->i_lock);
-       return false;
+       do {
+               rcu_read_unlock();
+               victim = __dentry_kill(victim);
+               rcu_read_lock();
+       } while (victim && lock_for_kill(victim));
+       rcu_read_unlock();
+       if (victim)
+               spin_unlock(&victim->d_lock);
  }
  
  void shrink_dentry_list(struct list_head *list)
  {
        while (!list_empty(list)) {
-               struct dentry *dentry, *parent;
+               struct dentry *dentry;
  
                dentry = list_entry(list->prev, struct dentry, d_lru);
                spin_lock(&dentry->d_lock);
                rcu_read_lock();
-               if (!shrink_lock_dentry(dentry)) {
-                       bool can_free = false;
+               if (!lock_for_kill(dentry)) {
+                       bool can_free;
                        rcu_read_unlock();
                        d_shrink_del(dentry);
-                       if (dentry->d_lockref.count < 0)
-                               can_free = dentry->d_flags & DCACHE_MAY_FREE;
+                       can_free = dentry->d_flags & DCACHE_DENTRY_KILLED;
                        spin_unlock(&dentry->d_lock);
                        if (can_free)
                                dentry_free(dentry);
                        continue;
                }
-               rcu_read_unlock();
                d_shrink_del(dentry);
-               parent = dentry->d_parent;
-               if (parent != dentry)
-                       __dput_to_list(parent, list);
-               __dentry_kill(dentry);
+               shrink_kill(dentry);
        }
  }
  
@@@ -1241,7 -1113,7 +1114,7 @@@ static enum lru_status dentry_lru_isola
                 *
                 * 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
 +               * list_lru_add_obj and list_lru_del_obj. List movement in this file
                 * only ever occur through this functions or through callbacks
                 * like this one, that are called from the LRU API.
                 *
@@@ -1349,8 -1221,7 +1222,7 @@@ enum d_walk_ret 
  static void d_walk(struct dentry *parent, void *data,
                   enum d_walk_ret (*enter)(void *, struct dentry *))
  {
-       struct dentry *this_parent;
-       struct list_head *next;
+       struct dentry *this_parent, *dentry;
        unsigned seq = 0;
        enum d_walk_ret ret;
        bool retry = true;
@@@ -1372,13 -1243,9 +1244,9 @@@ again
                break;
        }
  repeat:
-       next = this_parent->d_subdirs.next;
+       dentry = d_first_child(this_parent);
  resume:
-       while (next != &this_parent->d_subdirs) {
-               struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
-               next = tmp->next;
+       hlist_for_each_entry_from(dentry, d_sib) {
                if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR))
                        continue;
  
                        continue;
                }
  
-               if (!list_empty(&dentry->d_subdirs)) {
+               if (!hlist_empty(&dentry->d_children)) {
                        spin_unlock(&this_parent->d_lock);
                        spin_release(&dentry->d_lock.dep_map, _RET_IP_);
                        this_parent = dentry;
        rcu_read_lock();
  ascend:
        if (this_parent != parent) {
-               struct dentry *child = this_parent;
-               this_parent = child->d_parent;
+               dentry = this_parent;
+               this_parent = dentry->d_parent;
  
-               spin_unlock(&child->d_lock);
+               spin_unlock(&dentry->d_lock);
                spin_lock(&this_parent->d_lock);
  
                /* might go back up the wrong parent if we have had a rename. */
                if (need_seqretry(&rename_lock, seq))
                        goto rename_retry;
                /* go into the first sibling still alive */
-               do {
-                       next = child->d_child.next;
-                       if (next == &this_parent->d_subdirs)
-                               goto ascend;
-                       child = list_entry(next, struct dentry, d_child);
-               } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
-               rcu_read_unlock();
-               goto resume;
+               hlist_for_each_entry_continue(dentry, d_sib) {
+                       if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) {
+                               rcu_read_unlock();
+                               goto resume;
+                       }
+               }
+               goto ascend;
        }
        if (need_seqretry(&rename_lock, seq))
                goto rename_retry;
@@@ -1531,7 -1397,7 +1398,7 @@@ out
   * Search the dentry child list of the specified parent,
   * and move any unused dentries to the end of the unused
   * list for prune_dcache(). We descend to the next level
-  * whenever the d_subdirs list is non-empty and continue
+  * whenever the d_children list is non-empty and continue
   * searching.
   *
   * It returns zero iff there are no unused children,
@@@ -1561,13 -1427,11 +1428,11 @@@ static enum d_walk_ret select_collect(v
  
        if (dentry->d_flags & DCACHE_SHRINK_LIST) {
                data->found++;
-       } else {
-               if (dentry->d_flags & DCACHE_LRU_LIST)
-                       d_lru_del(dentry);
-               if (!dentry->d_lockref.count) {
-                       d_shrink_add(dentry, &data->dispose);
-                       data->found++;
-               }
+       } else if (!dentry->d_lockref.count) {
+               to_shrink_list(dentry, &data->dispose);
+               data->found++;
+       } else if (dentry->d_lockref.count < 0) {
+               data->found++;
        }
        /*
         * We can return to the caller if we have found some (this
@@@ -1588,17 -1452,13 +1453,13 @@@ static enum d_walk_ret select_collect2(
        if (data->start == dentry)
                goto out;
  
-       if (dentry->d_flags & DCACHE_SHRINK_LIST) {
-               if (!dentry->d_lockref.count) {
+       if (!dentry->d_lockref.count) {
+               if (dentry->d_flags & DCACHE_SHRINK_LIST) {
                        rcu_read_lock();
                        data->victim = dentry;
                        return D_WALK_QUIT;
                }
-       } else {
-               if (dentry->d_flags & DCACHE_LRU_LIST)
-                       d_lru_del(dentry);
-               if (!dentry->d_lockref.count)
-                       d_shrink_add(dentry, &data->dispose);
+               to_shrink_list(dentry, &data->dispose);
        }
        /*
         * We can return to the caller if we have found some (this
@@@ -1636,17 -1496,12 +1497,12 @@@ void shrink_dcache_parent(struct dentr
                data.victim = NULL;
                d_walk(parent, &data, select_collect2);
                if (data.victim) {
-                       struct dentry *parent;
                        spin_lock(&data.victim->d_lock);
-                       if (!shrink_lock_dentry(data.victim)) {
+                       if (!lock_for_kill(data.victim)) {
                                spin_unlock(&data.victim->d_lock);
                                rcu_read_unlock();
                        } else {
-                               rcu_read_unlock();
-                               parent = data.victim->d_parent;
-                               if (parent != data.victim)
-                                       __dput_to_list(parent, &data.dispose);
-                               __dentry_kill(data.victim);
+                               shrink_kill(data.victim);
                        }
                }
                if (!list_empty(&data.dispose))
@@@ -1658,7 -1513,7 +1514,7 @@@ EXPORT_SYMBOL(shrink_dcache_parent)
  static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
  {
        /* it has busy descendents; complain about those instead */
-       if (!list_empty(&dentry->d_subdirs))
+       if (!hlist_empty(&dentry->d_children))
                return D_WALK_CONTINUE;
  
        /* root with refcount 1 is fine */
@@@ -1708,8 -1563,7 +1564,7 @@@ static enum d_walk_ret find_submount(vo
  {
        struct dentry **victim = _data;
        if (d_mountpoint(dentry)) {
-               __dget_dlock(dentry);
-               *victim = dentry;
+               *victim = dget_dlock(dentry);
                return D_WALK_QUIT;
        }
        return D_WALK_CONTINUE;
@@@ -1815,9 -1669,9 +1670,9 @@@ static struct dentry *__d_alloc(struct 
        dentry->d_fsdata = NULL;
        INIT_HLIST_BL_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
-       INIT_LIST_HEAD(&dentry->d_subdirs);
+       INIT_HLIST_HEAD(&dentry->d_children);
        INIT_HLIST_NODE(&dentry->d_u.d_alias);
-       INIT_LIST_HEAD(&dentry->d_child);
+       INIT_HLIST_NODE(&dentry->d_sib);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
  
        if (dentry->d_op && dentry->d_op->d_init) {
@@@ -1854,9 -1708,8 +1709,8 @@@ struct dentry *d_alloc(struct dentry * 
         * don't need child lock because it is not subject
         * to concurrency here
         */
-       __dget_dlock(parent);
-       dentry->d_parent = parent;
-       list_add(&dentry->d_child, &parent->d_subdirs);
+       dentry->d_parent = dget_dlock(parent);
+       hlist_add_head(&dentry->d_sib, &parent->d_children);
        spin_unlock(&parent->d_lock);
  
        return dentry;
@@@ -1896,9 -1749,15 +1750,15 @@@ struct dentry *d_alloc_cursor(struct de
   */
  struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
  {
+       static const struct dentry_operations anon_ops = {
+               .d_dname = simple_dname
+       };
        struct dentry *dentry = __d_alloc(sb, name);
-       if (likely(dentry))
+       if (likely(dentry)) {
                dentry->d_flags |= DCACHE_NORCU;
+               if (!sb->s_d_op)
+                       d_set_d_op(dentry, &anon_ops);
+       }
        return dentry;
  }
  
@@@ -1942,22 -1801,6 +1802,6 @@@ void d_set_d_op(struct dentry *dentry, 
  }
  EXPORT_SYMBOL(d_set_d_op);
  
- /*
-  * d_set_fallthru - Mark a dentry as falling through to a lower layer
-  * @dentry - The dentry to mark
-  *
-  * Mark a dentry as falling through to the lower layer (as set with
-  * d_pin_lower()).  This flag may be recorded on the medium.
-  */
- void d_set_fallthru(struct dentry *dentry)
- {
-       spin_lock(&dentry->d_lock);
-       dentry->d_flags |= DCACHE_FALLTHRU;
-       spin_unlock(&dentry->d_lock);
- }
- EXPORT_SYMBOL(d_set_fallthru);
  static unsigned d_flags_for_inode(struct inode *inode)
  {
        unsigned add_flags = DCACHE_REGULAR_TYPE;
@@@ -2076,75 -1919,55 +1920,55 @@@ struct dentry *d_make_root(struct inod
  }
  EXPORT_SYMBOL(d_make_root);
  
- static struct dentry *__d_instantiate_anon(struct dentry *dentry,
-                                          struct inode *inode,
-                                          bool disconnected)
- {
-       struct dentry *res;
-       unsigned add_flags;
-       security_d_instantiate(dentry, inode);
-       spin_lock(&inode->i_lock);
-       res = __d_find_any_alias(inode);
-       if (res) {
-               spin_unlock(&inode->i_lock);
-               dput(dentry);
-               goto out_iput;
-       }
-       /* attach a disconnected dentry */
-       add_flags = d_flags_for_inode(inode);
-       if (disconnected)
-               add_flags |= DCACHE_DISCONNECTED;
-       spin_lock(&dentry->d_lock);
-       __d_set_inode_and_type(dentry, inode, add_flags);
-       hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
-       if (!disconnected) {
-               hlist_bl_lock(&dentry->d_sb->s_roots);
-               hlist_bl_add_head(&dentry->d_hash, &dentry->d_sb->s_roots);
-               hlist_bl_unlock(&dentry->d_sb->s_roots);
-       }
-       spin_unlock(&dentry->d_lock);
-       spin_unlock(&inode->i_lock);
-       return dentry;
-  out_iput:
-       iput(inode);
-       return res;
- }
- struct dentry *d_instantiate_anon(struct dentry *dentry, struct inode *inode)
- {
-       return __d_instantiate_anon(dentry, inode, true);
- }
- EXPORT_SYMBOL(d_instantiate_anon);
  static struct dentry *__d_obtain_alias(struct inode *inode, bool disconnected)
  {
-       struct dentry *tmp;
-       struct dentry *res;
+       struct super_block *sb;
+       struct dentry *new, *res;
  
        if (!inode)
                return ERR_PTR(-ESTALE);
        if (IS_ERR(inode))
                return ERR_CAST(inode);
  
-       res = d_find_any_alias(inode);
+       sb = inode->i_sb;
+       res = d_find_any_alias(inode); /* existing alias? */
        if (res)
-               goto out_iput;
+               goto out;
  
-       tmp = d_alloc_anon(inode->i_sb);
-       if (!tmp) {
+       new = d_alloc_anon(sb);
+       if (!new) {
                res = ERR_PTR(-ENOMEM);
-               goto out_iput;
+               goto out;
        }
  
-       return __d_instantiate_anon(tmp, inode, disconnected);
+       security_d_instantiate(new, inode);
+       spin_lock(&inode->i_lock);
+       res = __d_find_any_alias(inode); /* recheck under lock */
+       if (likely(!res)) { /* still no alias, attach a disconnected dentry */
+               unsigned add_flags = d_flags_for_inode(inode);
+               if (disconnected)
+                       add_flags |= DCACHE_DISCONNECTED;
  
- out_iput:
+               spin_lock(&new->d_lock);
+               __d_set_inode_and_type(new, inode, add_flags);
+               hlist_add_head(&new->d_u.d_alias, &inode->i_dentry);
+               if (!disconnected) {
+                       hlist_bl_lock(&sb->s_roots);
+                       hlist_bl_add_head(&new->d_hash, &sb->s_roots);
+                       hlist_bl_unlock(&sb->s_roots);
+               }
+               spin_unlock(&new->d_lock);
+               spin_unlock(&inode->i_lock);
+               inode = NULL; /* consumed by new->d_inode */
+               res = new;
+       } else {
+               spin_unlock(&inode->i_lock);
+               dput(new);
+       }
+  out:
        iput(inode);
        return res;
  }
@@@ -2728,7 -2551,7 +2552,7 @@@ retry
        /* we can't take ->d_lock here; it's OK, though. */
        new->d_flags |= DCACHE_PAR_LOOKUP;
        new->d_wait = wq;
-       hlist_bl_add_head_rcu(&new->d_u.d_in_lookup_hash, b);
+       hlist_bl_add_head(&new->d_u.d_in_lookup_hash, b);
        hlist_bl_unlock(b);
        return new;
  mismatch:
@@@ -2852,7 -2675,7 +2676,7 @@@ struct dentry *d_exact_alias(struct den
                        spin_unlock(&alias->d_lock);
                        alias = NULL;
                } else {
-                       __dget_dlock(alias);
+                       dget_dlock(alias);
                        __d_rehash(alias);
                        spin_unlock(&alias->d_lock);
                }
@@@ -2994,11 -2817,15 +2818,15 @@@ static void __d_move(struct dentry *den
        } else {
                target->d_parent = old_parent;
                swap_names(dentry, target);
-               list_move(&target->d_child, &target->d_parent->d_subdirs);
+               if (!hlist_unhashed(&target->d_sib))
+                       __hlist_del(&target->d_sib);
+               hlist_add_head(&target->d_sib, &target->d_parent->d_children);
                __d_rehash(target);
                fsnotify_update_flags(target);
        }
-       list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
+       if (!hlist_unhashed(&dentry->d_sib))
+               __hlist_del(&dentry->d_sib);
+       hlist_add_head(&dentry->d_sib, &dentry->d_parent->d_children);
        __d_rehash(dentry);
        fsnotify_update_flags(dentry);
        fscrypt_handle_d_move(dentry);
@@@ -3081,8 -2908,7 +2909,7 @@@ struct dentry *d_ancestor(struct dentr
   * Note: If ever the locking in lock_rename() changes, then please
   * remember to update this too...
   */
- static int __d_unalias(struct inode *inode,
-               struct dentry *dentry, struct dentry *alias)
+ static int __d_unalias(struct dentry *dentry, struct dentry *alias)
  {
        struct mutex *m1 = NULL;
        struct rw_semaphore *m2 = NULL;
@@@ -3163,7 -2989,7 +2990,7 @@@ struct dentry *d_splice_alias(struct in
                                        inode->i_sb->s_id);
                        } else if (!IS_ROOT(new)) {
                                struct dentry *old_parent = dget(new->d_parent);
-                               int err = __d_unalias(inode, dentry, new);
+                               int err = __d_unalias(dentry, new);
                                write_sequnlock(&rename_lock);
                                if (err) {
                                        dput(new);
@@@ -3234,10 -3060,7 +3061,7 @@@ static enum d_walk_ret d_genocide_kill(
                if (d_unhashed(dentry) || !dentry->d_inode)
                        return D_WALK_SKIP;
  
-               if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
-                       dentry->d_flags |= DCACHE_GENOCIDE;
-                       dentry->d_lockref.count--;
-               }
+               dentry->d_lockref.count--;
        }
        return D_WALK_CONTINUE;
  }
diff --combined fs/file_table.c
index c5ac2cc051356afeada8e8eeeddaf666454ce67d,8889cbee13f8b36b48a25756cc77bb3daedd1186..b991f90571b4d3089a0c00884fea3e38f317b1da
@@@ -75,6 -75,18 +75,6 @@@ static inline void file_free(struct fil
        }
  }
  
 -void release_empty_file(struct file *f)
 -{
 -      WARN_ON_ONCE(f->f_mode & (FMODE_BACKING | FMODE_OPENED));
 -      if (atomic_long_dec_and_test(&f->f_count)) {
 -              security_file_free(f);
 -              put_cred(f->f_cred);
 -              if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
 -                      percpu_counter_dec(&nr_files);
 -              kmem_cache_free(filp_cachep, f);
 -      }
 -}
 -
  /*
   * Return the total number of open files in the system
   */
@@@ -130,6 -142,7 +130,6 @@@ static struct ctl_table fs_stat_sysctls
                .extra1         = &sysctl_nr_open_min,
                .extra2         = &sysctl_nr_open_max,
        },
 -      { }
  };
  
  static int __init init_fs_stat_sysctls(void)
@@@ -316,9 -329,6 +316,6 @@@ struct file *alloc_file_pseudo(struct i
                                const char *name, int flags,
                                const struct file_operations *fops)
  {
-       static const struct dentry_operations anon_ops = {
-               .d_dname = simple_dname
-       };
        struct qstr this = QSTR_INIT(name, strlen(name));
        struct path path;
        struct file *file;
        path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
        if (!path.dentry)
                return ERR_PTR(-ENOMEM);
-       if (!mnt->mnt_sb->s_d_op)
-               d_set_d_op(path.dentry, &anon_ops);
        path.mnt = mntget(mnt);
        d_instantiate(path.dentry, inode);
        file = alloc_file(&path, flags, fops);
@@@ -406,7 -414,7 +401,7 @@@ static void delayed_fput(struct work_st
  
  static void ____fput(struct callback_head *work)
  {
 -      __fput(container_of(work, struct file, f_rcuhead));
 +      __fput(container_of(work, struct file, f_task_work));
  }
  
  /*
@@@ -432,13 -440,9 +427,13 @@@ void fput(struct file *file
        if (atomic_long_dec_and_test(&file->f_count)) {
                struct task_struct *task = current;
  
 +              if (unlikely(!(file->f_mode & (FMODE_BACKING | FMODE_OPENED)))) {
 +                      file_free(file);
 +                      return;
 +              }
                if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
 -                      init_task_work(&file->f_rcuhead, ____fput);
 -                      if (!task_work_add(task, &file->f_rcuhead, TWA_RESUME))
 +                      init_task_work(&file->f_task_work, ____fput);
 +                      if (!task_work_add(task, &file->f_task_work, TWA_RESUME))
                                return;
                        /*
                         * After this task has run exit_task_work(),
diff --combined fs/internal.h
index 93cdeeb858cb4b1d4d937ddcda830b5c6c62b992,d9a920e2636e23abcf4379ca3520dd1639eead01..b67406435fc02763299e8732fa4cf6dfe1d51bf6
@@@ -83,8 -83,6 +83,8 @@@ int path_mount(const char *dev_name, st
                const char *type_page, unsigned long flags, void *data_page);
  int path_umount(struct path *path, int flags);
  
 +int show_path(struct seq_file *m, struct dentry *root);
 +
  /*
   * fs_struct.c
   */
@@@ -96,6 -94,7 +96,6 @@@ extern void chroot_fs_refs(const struc
  struct file *alloc_empty_file(int flags, const struct cred *cred);
  struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
  struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
 -void release_empty_file(struct file *f);
  
  static inline void file_put_write_access(struct file *file)
  {
@@@ -181,7 -180,7 +181,7 @@@ extern struct file *do_file_open_root(c
                const char *, const struct open_flags *);
  extern struct open_how build_open_how(int flags, umode_t mode);
  extern int build_open_flags(const struct open_how *how, struct open_flags *op);
 -extern struct file *__close_fd_get_file(unsigned int fd);
 +struct file *file_close_fd_locked(struct files_struct *files, unsigned fd);
  
  long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
  int chmod_common(const struct path *path, umode_t mode);
@@@ -197,6 -196,8 +197,6 @@@ extern long prune_icache_sb(struct supe
  int dentry_needs_remove_privs(struct mnt_idmap *, struct dentry *dentry);
  bool in_group_or_capable(struct mnt_idmap *idmap,
                         const struct inode *inode, vfsgid_t vfsgid);
 -void lock_two_inodes(struct inode *inode1, struct inode *inode2,
 -                   unsigned subclass1, unsigned subclass2);
  
  /*
   * fs-writeback.c
@@@ -214,6 -215,11 +214,11 @@@ extern struct dentry * d_alloc_pseudo(s
  extern char *simple_dname(struct dentry *, char *, int);
  extern void dput_to_list(struct dentry *, struct list_head *);
  extern void shrink_dentry_list(struct list_head *);
+ extern void shrink_dcache_for_umount(struct super_block *);
+ extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
+ extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
+                               const struct qstr *name, unsigned *seq);
+ extern void d_genocide(struct dentry *);
  
  /*
   * pipe.c
@@@ -242,10 -248,10 +247,10 @@@ int do_statx(int dfd, struct filename *
  /*
   * fs/splice.c:
   */
 -long splice_file_to_pipe(struct file *in,
 -                       struct pipe_inode_info *opipe,
 -                       loff_t *offset,
 -                       size_t len, unsigned int flags);
 +ssize_t splice_file_to_pipe(struct file *in,
 +                          struct pipe_inode_info *opipe,
 +                          loff_t *offset,
 +                          size_t len, unsigned int flags);
  
  /*
   * fs/xattr.c:
diff --combined fs/libfs.c
index c2aa6fd4795c44340fbc16c0c4138ff004b8f53e,75eeb9621e20d37b6ae50abb711836493c4c31cc..eec6031b0155442eab924ce946c2295c711105d2
@@@ -104,15 -104,16 +104,16 @@@ EXPORT_SYMBOL(dcache_dir_close)
   * If no such element exists, NULL is returned.
   */
  static struct dentry *scan_positives(struct dentry *cursor,
-                                       struct list_head *p,
+                                       struct hlist_node **p,
                                        loff_t count,
                                        struct dentry *last)
  {
        struct dentry *dentry = cursor->d_parent, *found = NULL;
  
        spin_lock(&dentry->d_lock);
-       while ((p = p->next) != &dentry->d_subdirs) {
-               struct dentry *d = list_entry(p, struct dentry, d_child);
+       while (*p) {
+               struct dentry *d = hlist_entry(*p, struct dentry, d_sib);
+               p = &d->d_sib.next;
                // we must at least skip cursors, to avoid livelocks
                if (d->d_flags & DCACHE_DENTRY_CURSOR)
                        continue;
                        count = 1;
                }
                if (need_resched()) {
-                       list_move(&cursor->d_child, p);
-                       p = &cursor->d_child;
+                       if (!hlist_unhashed(&cursor->d_sib))
+                               __hlist_del(&cursor->d_sib);
+                       hlist_add_behind(&cursor->d_sib, &d->d_sib);
+                       p = &cursor->d_sib.next;
                        spin_unlock(&dentry->d_lock);
                        cond_resched();
                        spin_lock(&dentry->d_lock);
@@@ -159,13 -162,12 +162,12 @@@ loff_t dcache_dir_lseek(struct file *fi
                inode_lock_shared(dentry->d_inode);
  
                if (offset > 2)
-                       to = scan_positives(cursor, &dentry->d_subdirs,
+                       to = scan_positives(cursor, &dentry->d_children.first,
                                            offset - 2, NULL);
                spin_lock(&dentry->d_lock);
+               hlist_del_init(&cursor->d_sib);
                if (to)
-                       list_move(&cursor->d_child, &to->d_child);
-               else
-                       list_del_init(&cursor->d_child);
+                       hlist_add_behind(&cursor->d_sib, &to->d_sib);
                spin_unlock(&dentry->d_lock);
                dput(to);
  
@@@ -187,19 -189,16 +189,16 @@@ int dcache_readdir(struct file *file, s
  {
        struct dentry *dentry = file->f_path.dentry;
        struct dentry *cursor = file->private_data;
-       struct list_head *anchor = &dentry->d_subdirs;
        struct dentry *next = NULL;
-       struct list_head *p;
+       struct hlist_node **p;
  
        if (!dir_emit_dots(file, ctx))
                return 0;
  
        if (ctx->pos == 2)
-               p = anchor;
-       else if (!list_empty(&cursor->d_child))
-               p = &cursor->d_child;
+               p = &dentry->d_children.first;
        else
-               return 0;
+               p = &cursor->d_sib.next;
  
        while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
                if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
                              fs_umode_to_dtype(d_inode(next)->i_mode)))
                        break;
                ctx->pos++;
-               p = &next->d_child;
+               p = &next->d_sib.next;
        }
        spin_lock(&dentry->d_lock);
+       hlist_del_init(&cursor->d_sib);
        if (next)
-               list_move_tail(&cursor->d_child, &next->d_child);
-       else
-               list_del_init(&cursor->d_child);
+               hlist_add_before(&cursor->d_sib, &next->d_sib);
        spin_unlock(&dentry->d_lock);
        dput(next);
  
@@@ -399,8 -397,6 +397,8 @@@ static loff_t offset_dir_llseek(struct 
                return -EINVAL;
        }
  
 +      /* In this case, ->private_data is protected by f_pos_lock */
 +      file->private_data = NULL;
        return vfs_setpos(file, offset, U32_MAX);
  }
  
@@@ -430,7 -426,7 +428,7 @@@ static bool offset_dir_emit(struct dir_
                          inode->i_ino, fs_umode_to_dtype(inode->i_mode));
  }
  
 -static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 +static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
  {
        struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
        XA_STATE(xas, &so_ctx->xa, ctx->pos);
        while (true) {
                dentry = offset_find_next(&xas);
                if (!dentry)
 -                      break;
 +                      return ERR_PTR(-ENOENT);
  
                if (!offset_dir_emit(ctx, dentry)) {
                        dput(dentry);
                dput(dentry);
                ctx->pos = xas.xa_index + 1;
        }
 +      return NULL;
  }
  
  /**
@@@ -482,12 -477,7 +480,12 @@@ static int offset_readdir(struct file *
        if (!dir_emit_dots(file, ctx))
                return 0;
  
 -      offset_iterate_dir(d_inode(dir), ctx);
 +      /* In this case, ->private_data is protected by f_pos_lock */
 +      if (ctx->pos == 2)
 +              file->private_data = NULL;
 +      else if (file->private_data == ERR_PTR(-ENOENT))
 +              return 0;
 +      file->private_data = offset_iterate_dir(d_inode(dir), ctx);
        return 0;
  }
  
@@@ -500,12 -490,11 +498,11 @@@ const struct file_operations simple_off
  
  static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev)
  {
-       struct dentry *child = NULL;
-       struct list_head *p = prev ? &prev->d_child : &parent->d_subdirs;
+       struct dentry *child = NULL, *d;
  
        spin_lock(&parent->d_lock);
-       while ((p = p->next) != &parent->d_subdirs) {
-               struct dentry *d = container_of(p, struct dentry, d_child);
+       d = prev ? d_next_sibling(prev) : d_first_child(parent);
+       hlist_for_each_entry_from(d, d_sib) {
                if (simple_positive(d)) {
                        spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
                        if (simple_positive(d))
@@@ -666,7 -655,7 +663,7 @@@ int simple_empty(struct dentry *dentry
        int ret = 0;
  
        spin_lock(&dentry->d_lock);
-       list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+       hlist_for_each_entry(child, &dentry->d_children, d_sib) {
                spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
                if (simple_positive(child)) {
                        spin_unlock(&child->d_lock);
@@@ -920,7 -909,6 +917,6 @@@ int simple_fill_super(struct super_bloc
                      const struct tree_descr *files)
  {
        struct inode *inode;
-       struct dentry *root;
        struct dentry *dentry;
        int i;
  
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        set_nlink(inode, 2);
-       root = d_make_root(inode);
-       if (!root)
+       s->s_root = d_make_root(inode);
+       if (!s->s_root)
                return -ENOMEM;
        for (i = 0; !files->name || files->name[0]; i++, files++) {
                if (!files->name)
                                "with an index of 1!\n", __func__,
                                s->s_type->name);
  
-               dentry = d_alloc_name(root, files->name);
+               dentry = d_alloc_name(s->s_root, files->name);
                if (!dentry)
-                       goto out;
+                       return -ENOMEM;
                inode = new_inode(s);
                if (!inode) {
                        dput(dentry);
-                       goto out;
+                       return -ENOMEM;
                }
                inode->i_mode = S_IFREG | files->mode;
                simple_inode_init_ts(inode);
                inode->i_ino = i;
                d_add(dentry, inode);
        }
-       s->s_root = root;
        return 0;
- out:
-       d_genocide(root);
-       shrink_dcache_parent(root);
-       dput(root);
-       return -ENOMEM;
  }
  EXPORT_SYMBOL(simple_fill_super);
  
diff --combined fs/nfsd/nfsctl.c
index 8e6dbe9e0b6503428a397ab30ed2c9bd5e2276de,50df5e9d00698c2076dcd1b9a09b5a3efa3a7ead..c9f9590f056b5de23698039b05e30942356c87dc
@@@ -76,9 -76,7 +76,9 @@@ static ssize_t write_maxconn(struct fil
  #ifdef CONFIG_NFSD_V4
  static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
  static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
 +#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
  static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
 +#endif
  static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
  #endif
  
@@@ -95,9 -93,7 +95,9 @@@ static ssize_t (*const write_op[])(stru
  #ifdef CONFIG_NFSD_V4
        [NFSD_Leasetime] = write_leasetime,
        [NFSD_Gracetime] = write_gracetime,
 +#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
        [NFSD_RecoveryDir] = write_recoverydir,
 +#endif
        [NFSD_V4EndGrace] = write_v4_end_grace,
  #endif
  };
@@@ -183,7 -179,7 +183,7 @@@ static const struct file_operations poo
        .open           = nfsd_pool_stats_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
 -      .release        = nfsd_pool_stats_release,
 +      .release        = seq_release,
  };
  
  DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats);
@@@ -697,7 -693,6 +697,7 @@@ static ssize_t __write_ports_addfd(cha
        char *mesg = buf;
        int fd, err;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct svc_serv *serv;
  
        err = get_int(&mesg, &fd);
        if (err != 0 || fd < 0)
        if (err != 0)
                return err;
  
 -      err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
 +      serv = nn->nfsd_serv;
 +      err = svc_addsock(serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
  
 -      if (err >= 0 &&
 -          !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1))
 -              svc_get(nn->nfsd_serv);
 +      if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
 +              nfsd_destroy_serv(net);
  
 -      nfsd_put(net);
        return err;
  }
  
@@@ -727,7 -723,6 +727,7 @@@ static ssize_t __write_ports_addxprt(ch
        struct svc_xprt *xprt;
        int port, err;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 +      struct svc_serv *serv;
  
        if (sscanf(buf, "%15s %5u", transport, &port) != 2)
                return -EINVAL;
        if (err != 0)
                return err;
  
 -      err = svc_xprt_create(nn->nfsd_serv, transport, net,
 +      serv = nn->nfsd_serv;
 +      err = svc_xprt_create(serv, transport, net,
                              PF_INET, port, SVC_SOCK_ANONYMOUS, cred);
        if (err < 0)
                goto out_err;
  
 -      err = svc_xprt_create(nn->nfsd_serv, transport, net,
 +      err = svc_xprt_create(serv, transport, net,
                              PF_INET6, port, SVC_SOCK_ANONYMOUS, cred);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
  
 -      if (!nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1))
 -              svc_get(nn->nfsd_serv);
 -
 -      nfsd_put(net);
        return 0;
  out_close:
 -      xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port);
 +      xprt = svc_find_xprt(serv, transport, net, PF_INET, port);
        if (xprt != NULL) {
                svc_xprt_close(xprt);
                svc_xprt_put(xprt);
        }
  out_err:
 -      nfsd_put(net);
 +      if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
 +              nfsd_destroy_serv(net);
 +
        return err;
  }
  
@@@ -1017,7 -1013,6 +1017,7 @@@ static ssize_t write_gracetime(struct f
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
  }
  
 +#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
  static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
                                   struct nfsd_net *nn)
  {
@@@ -1078,7 -1073,6 +1078,7 @@@ static ssize_t write_recoverydir(struc
        mutex_unlock(&nfsd_mutex);
        return rv;
  }
 +#endif
  
  /*
   * write_v4_end_grace - release grace period for nfsd's v4.x lock manager
@@@ -1242,63 -1236,34 +1242,34 @@@ static inline void _nfsd_symlink(struc
  
  #endif
  
- static void clear_ncl(struct inode *inode)
+ static void clear_ncl(struct dentry *dentry)
  {
+       struct inode *inode = d_inode(dentry);
        struct nfsdfs_client *ncl = inode->i_private;
  
+       spin_lock(&inode->i_lock);
        inode->i_private = NULL;
+       spin_unlock(&inode->i_lock);
        kref_put(&ncl->cl_ref, ncl->cl_release);
  }
  
- static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
- {
-       struct nfsdfs_client *nc = inode->i_private;
-       if (nc)
-               kref_get(&nc->cl_ref);
-       return nc;
- }
  struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
  {
        struct nfsdfs_client *nc;
  
-       inode_lock_shared(inode);
-       nc = __get_nfsdfs_client(inode);
-       inode_unlock_shared(inode);
+       spin_lock(&inode->i_lock);
+       nc = inode->i_private;
+       if (nc)
+               kref_get(&nc->cl_ref);
+       spin_unlock(&inode->i_lock);
        return nc;
  }
- /* from __rpc_unlink */
- static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
- {
-       int ret;
-       clear_ncl(d_inode(dentry));
-       dget(dentry);
-       ret = simple_unlink(dir, dentry);
-       d_drop(dentry);
-       fsnotify_unlink(dir, dentry);
-       dput(dentry);
-       WARN_ON_ONCE(ret);
- }
- static void nfsdfs_remove_files(struct dentry *root)
- {
-       struct dentry *dentry, *tmp;
-       list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) {
-               if (!simple_positive(dentry)) {
-                       WARN_ON_ONCE(1); /* I think this can't happen? */
-                       continue;
-               }
-               nfsdfs_remove_file(d_inode(root), dentry);
-       }
- }
  
  /* XXX: cut'n'paste from simple_fill_super; figure out if we could share
   * code instead. */
  static  int nfsdfs_create_files(struct dentry *root,
                                const struct tree_descr *files,
+                               struct nfsdfs_client *ncl,
                                struct dentry **fdentries)
  {
        struct inode *dir = d_inode(root);
                        dput(dentry);
                        goto out;
                }
+               kref_get(&ncl->cl_ref);
                inode->i_fop = files->ops;
-               inode->i_private = __get_nfsdfs_client(dir);
+               inode->i_private = ncl;
                d_add(dentry, inode);
                fsnotify_create(dir, dentry);
                if (fdentries)
        inode_unlock(dir);
        return 0;
  out:
-       nfsdfs_remove_files(root);
        inode_unlock(dir);
        return -ENOMEM;
  }
@@@ -1347,7 -1312,7 +1318,7 @@@ struct dentry *nfsd_client_mkdir(struc
        dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
        if (IS_ERR(dentry)) /* XXX: tossing errors? */
                return NULL;
-       ret = nfsdfs_create_files(dentry, files, fdentries);
+       ret = nfsdfs_create_files(dentry, files, ncl, fdentries);
        if (ret) {
                nfsd_client_rmdir(dentry);
                return NULL;
  /* Taken from __rpc_rmdir: */
  void nfsd_client_rmdir(struct dentry *dentry)
  {
-       struct inode *dir = d_inode(dentry->d_parent);
-       struct inode *inode = d_inode(dentry);
-       int ret;
-       inode_lock(dir);
-       nfsdfs_remove_files(dentry);
-       clear_ncl(inode);
-       dget(dentry);
-       ret = simple_rmdir(dir, dentry);
-       WARN_ON_ONCE(ret);
-       d_drop(dentry);
-       fsnotify_rmdir(dir, dentry);
-       dput(dentry);
-       inode_unlock(dir);
+       simple_recursive_removal(dentry, clear_ncl);
  }
  
  static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
@@@ -1516,10 -1468,11 +1474,10 @@@ int nfsd_nl_rpc_status_get_start(struc
        int ret = -ENODEV;
  
        mutex_lock(&nfsd_mutex);
 -      if (nn->nfsd_serv) {
 -              svc_get(nn->nfsd_serv);
 +      if (nn->nfsd_serv)
                ret = 0;
 -      }
 -      mutex_unlock(&nfsd_mutex);
 +      else
 +              mutex_unlock(&nfsd_mutex);
  
        return ret;
  }
@@@ -1691,6 -1644,8 +1649,6 @@@ out
   */
  int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb)
  {
 -      mutex_lock(&nfsd_mutex);
 -      nfsd_put(sock_net(cb->skb->sk));
        mutex_unlock(&nfsd_mutex);
  
        return 0;
diff --combined fs/overlayfs/export.c
index 6909c4a5da561ea3c9017ad522b594e28e4a91ac,9e316d5f936e9134258bd34fcae97554b15703b8..063409069f56d036fded768844da97164a7cf197
@@@ -289,7 -289,6 +289,6 @@@ static struct dentry *ovl_obtain_alias(
  {
        struct dentry *lower = lowerpath ? lowerpath->dentry : NULL;
        struct dentry *upper = upper_alias ?: index;
-       struct dentry *dentry;
        struct inode *inode = NULL;
        struct ovl_entry *oe;
        struct ovl_inode_params oip = {
        if (upper)
                ovl_set_flag(OVL_UPPERDATA, inode);
  
-       dentry = d_find_any_alias(inode);
-       if (dentry)
-               goto out_iput;
-       dentry = d_alloc_anon(inode->i_sb);
-       if (unlikely(!dentry))
-               goto nomem;
-       if (upper_alias)
-               ovl_dentry_set_upper_alias(dentry);
-       ovl_dentry_init_reval(dentry, upper, OVL_I_E(inode));
-       return d_instantiate_anon(dentry, inode);
- nomem:
-       dput(dentry);
-       dentry = ERR_PTR(-ENOMEM);
- out_iput:
-       iput(inode);
-       return dentry;
+       return d_obtain_alias(inode);
  }
  
  /* Get the upper or lower dentry in stack whose on layer @idx */
@@@ -460,7 -439,7 +439,7 @@@ static struct dentry *ovl_lookup_real_i
         * For decoded lower dir file handle, lookup index by origin to check
         * if lower dir was copied up and and/or removed.
         */
 -      if (!this && layer->idx && ofs->indexdir && !WARN_ON(!d_is_dir(real))) {
 +      if (!this && layer->idx && ovl_indexdir(sb) && !WARN_ON(!d_is_dir(real))) {
                index = ovl_lookup_index(ofs, NULL, real, false);
                if (IS_ERR(index))
                        return index;
@@@ -733,7 -712,7 +712,7 @@@ static struct dentry *ovl_lower_fh_to_d
        }
  
        /* Then lookup indexed upper/whiteout by origin fh */
 -      if (ofs->indexdir) {
 +      if (ovl_indexdir(sb)) {
                index = ovl_get_index_fh(ofs, fh);
                err = PTR_ERR(index);
                if (IS_ERR(index)) {
diff --combined fs/tracefs/inode.c
index bc86ffdb103bc526846884a8b78ba9f1bfb7a5d4,61ca5fcf10f9160d9016a280c494a489ceec7589..ad20e6af938d9b68df7b27e08d44a5351f0d977e
@@@ -199,36 -199,21 +199,32 @@@ static void change_gid(struct dentry *d
   */
  static void set_gid(struct dentry *parent, kgid_t gid)
  {
-       struct dentry *this_parent;
-       struct list_head *next;
+       struct dentry *this_parent, *dentry;
  
        this_parent = parent;
        spin_lock(&this_parent->d_lock);
  
        change_gid(this_parent, gid);
  repeat:
-       next = this_parent->d_subdirs.next;
+       dentry = d_first_child(this_parent);
  resume:
-       while (next != &this_parent->d_subdirs) {
+       hlist_for_each_entry_from(dentry, d_sib) {
 +              struct tracefs_inode *ti;
-               struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
-               next = tmp->next;
 +
 +              /* Note, getdents() can add a cursor dentry with no inode */
 +              if (!dentry->d_inode)
 +                      continue;
 +
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
  
                change_gid(dentry, gid);
  
-               if (!list_empty(&dentry->d_subdirs)) {
 +              /* If this is the events directory, update that too */
 +              ti = get_tracefs(dentry->d_inode);
 +              if (ti && (ti->flags & TRACEFS_EVENT_INODE))
 +                      eventfs_update_gid(dentry, gid);
 +
+               if (!hlist_empty(&dentry->d_children)) {
                        spin_unlock(&this_parent->d_lock);
                        spin_release(&dentry->d_lock.dep_map, _RET_IP_);
                        this_parent = dentry;
        rcu_read_lock();
  ascend:
        if (this_parent != parent) {
-               struct dentry *child = this_parent;
-               this_parent = child->d_parent;
+               dentry = this_parent;
+               this_parent = dentry->d_parent;
  
-               spin_unlock(&child->d_lock);
+               spin_unlock(&dentry->d_lock);
                spin_lock(&this_parent->d_lock);
  
                /* go into the first sibling still alive */
-               do {
-                       next = child->d_child.next;
-                       if (next == &this_parent->d_subdirs)
-                               goto ascend;
-                       child = list_entry(next, struct dentry, d_child);
-               } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
-               rcu_read_unlock();
-               goto resume;
+               hlist_for_each_entry_continue(dentry, d_sib) {
+                       if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) {
+                               rcu_read_unlock();
+                               goto resume;
+                       }
+               }
+               goto ascend;
        }
        rcu_read_unlock();
        spin_unlock(&this_parent->d_lock);
@@@ -519,15 -503,20 +514,15 @@@ struct dentry *eventfs_start_creating(c
        struct dentry *dentry;
        int error;
  
 +      /* Must always have a parent. */
 +      if (WARN_ON_ONCE(!parent))
 +              return ERR_PTR(-EINVAL);
 +
        error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
                              &tracefs_mount_count);
        if (error)
                return ERR_PTR(error);
  
 -      /*
 -       * If the parent is not specified, we create it in the root.
 -       * We need the root dentry to do this, which is in the super
 -       * block. A pointer to that is in the struct vfsmount that we
 -       * have around.
 -       */
 -      if (!parent)
 -              parent = tracefs_mount->mnt_root;
 -
        if (unlikely(IS_DEADDIR(parent->d_inode)))
                dentry = ERR_PTR(-ENOENT);
        else
This page took 0.214692 seconds and 4 git commands to generate.