]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 26 Apr 2015 10:21:48 +0000 (12:21 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 26 Apr 2015 10:21:48 +0000 (12:21 +0200)
added patches:
deal-with-deadlock-in-d_walk.patch
move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch

queue-3.10/deal-with-deadlock-in-d_walk.patch [new file with mode: 0644]
queue-3.10/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch [new file with mode: 0644]
queue-3.10/series

diff --git a/queue-3.10/deal-with-deadlock-in-d_walk.patch b/queue-3.10/deal-with-deadlock-in-d_walk.patch
new file mode 100644 (file)
index 0000000..712038a
--- /dev/null
@@ -0,0 +1,212 @@
+From ca5358ef75fc69fee5322a38a340f5739d997c10 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sun, 26 Oct 2014 19:31:10 -0400
+Subject: deal with deadlock in d_walk()
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit ca5358ef75fc69fee5322a38a340f5739d997c10 upstream.
+
+... by not hitting rename_retry for reasons other than rename having
+happened.  In other words, do _not_ restart when finding that
+between unlocking the child and locking the parent the former got
+into __dentry_kill().  Skip the killed siblings instead...
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+[hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2:
+ - As we only have try_to_ascend() and not d_walk(), apply this
+   change to all callers of try_to_ascend()
+ - Adjust context to make __dentry_kill() apply to d_kill()]
+Signed-off-by: hujianyang <hujianyang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/dcache.c |  102 ++++++++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 62 insertions(+), 40 deletions(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -364,9 +364,9 @@ static struct dentry *d_kill(struct dent
+       __releases(parent->d_lock)
+       __releases(dentry->d_inode->i_lock)
+ {
+-      list_del(&dentry->d_child);
++      __list_del_entry(&dentry->d_child);
+       /*
+-       * Inform try_to_ascend() that we are no longer attached to the
++       * Inform ascending readers that we are no longer attached to the
+        * dentry tree
+        */
+       dentry->d_flags |= DCACHE_DENTRY_KILLED;
+@@ -988,35 +988,6 @@ void shrink_dcache_for_umount(struct sup
+ }
+ /*
+- * This tries to ascend one level of parenthood, but
+- * we can race with renaming, so we need to re-check
+- * the parenthood after dropping the lock and check
+- * that the sequence number still matches.
+- */
+-static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
+-{
+-      struct dentry *new = old->d_parent;
+-
+-      rcu_read_lock();
+-      spin_unlock(&old->d_lock);
+-      spin_lock(&new->d_lock);
+-
+-      /*
+-       * might go back up the wrong parent if we have had a rename
+-       * or deletion
+-       */
+-      if (new != old->d_parent ||
+-               (old->d_flags & DCACHE_DENTRY_KILLED) ||
+-               (!locked && read_seqretry(&rename_lock, seq))) {
+-              spin_unlock(&new->d_lock);
+-              new = NULL;
+-      }
+-      rcu_read_unlock();
+-      return new;
+-}
+-
+-
+-/*
+  * Search for at least 1 mount point in the dentry's subdirs.
+  * We descend to the next level whenever the d_subdirs
+  * list is non-empty and continue searching.
+@@ -1070,17 +1041,32 @@ resume:
+       /*
+        * All done at this level ... ascend and resume the search.
+        */
++      rcu_read_lock();
++ascend:
+       if (this_parent != parent) {
+               struct dentry *child = this_parent;
+-              this_parent = try_to_ascend(this_parent, locked, seq);
+-              if (!this_parent)
++              this_parent = child->d_parent;
++
++              spin_unlock(&child->d_lock);
++              spin_lock(&this_parent->d_lock);
++
++              /* might go back up the wrong parent if we have had a rename. */
++              if (!locked && read_seqretry(&rename_lock, seq))
+                       goto rename_retry;
+               next = child->d_child.next;
++              while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
++                      if (next == &this_parent->d_subdirs)
++                              goto ascend;
++                      child = list_entry(next, struct dentry, d_child);
++                      next = next->next;
++              }
++              rcu_read_unlock();
+               goto resume;
+       }
+-      spin_unlock(&this_parent->d_lock);
+       if (!locked && read_seqretry(&rename_lock, seq))
+               goto rename_retry;
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (locked)
+               write_sequnlock(&rename_lock);
+       return 0; /* No mount points found in tree */
+@@ -1092,6 +1078,8 @@ positive:
+       return 1;
+ rename_retry:
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (locked)
+               goto again;
+       locked = 1;
+@@ -1177,23 +1165,40 @@ resume:
+       /*
+        * All done at this level ... ascend and resume the search.
+        */
++      rcu_read_lock();
++ascend:
+       if (this_parent != parent) {
+               struct dentry *child = this_parent;
+-              this_parent = try_to_ascend(this_parent, locked, seq);
+-              if (!this_parent)
++              this_parent = child->d_parent;
++
++              spin_unlock(&child->d_lock);
++              spin_lock(&this_parent->d_lock);
++
++              /* might go back up the wrong parent if we have had a rename. */
++              if (!locked && read_seqretry(&rename_lock, seq))
+                       goto rename_retry;
+               next = child->d_child.next;
++              while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
++                      if (next == &this_parent->d_subdirs)
++                              goto ascend;
++                      child = list_entry(next, struct dentry, d_child);
++                      next = next->next;
++              }
++              rcu_read_unlock();
+               goto resume;
+       }
+ out:
+-      spin_unlock(&this_parent->d_lock);
+       if (!locked && read_seqretry(&rename_lock, seq))
+               goto rename_retry;
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (locked)
+               write_sequnlock(&rename_lock);
+       return found;
+ rename_retry:
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (found)
+               return found;
+       if (locked)
+@@ -2954,26 +2959,43 @@ resume:
+               }
+               spin_unlock(&dentry->d_lock);
+       }
++      rcu_read_lock();
++ascend:
+       if (this_parent != root) {
+               struct dentry *child = this_parent;
+               if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
+                       this_parent->d_flags |= DCACHE_GENOCIDE;
+                       this_parent->d_count--;
+               }
+-              this_parent = try_to_ascend(this_parent, locked, seq);
+-              if (!this_parent)
++              this_parent = child->d_parent;
++
++              spin_unlock(&child->d_lock);
++              spin_lock(&this_parent->d_lock);
++
++              /* might go back up the wrong parent if we have had a rename. */
++              if (!locked && read_seqretry(&rename_lock, seq))
+                       goto rename_retry;
+               next = child->d_child.next;
++              while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
++                      if (next == &this_parent->d_subdirs)
++                              goto ascend;
++                      child = list_entry(next, struct dentry, d_child);
++                      next = next->next;
++              }
++              rcu_read_unlock();
+               goto resume;
+       }
+-      spin_unlock(&this_parent->d_lock);
+       if (!locked && read_seqretry(&rename_lock, seq))
+               goto rename_retry;
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (locked)
+               write_sequnlock(&rename_lock);
+       return;
+ rename_retry:
++      spin_unlock(&this_parent->d_lock);
++      rcu_read_unlock();
+       if (locked)
+               goto again;
+       locked = 1;
diff --git a/queue-3.10/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch b/queue-3.10/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch
new file mode 100644 (file)
index 0000000..a3517b9
--- /dev/null
@@ -0,0 +1,750 @@
+From 946e51f2bf37f1656916eb75bd0742ba33983c28 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sun, 26 Oct 2014 19:19:16 -0400
+Subject: move d_rcu from overlapping d_child to overlapping d_alias
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+[hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2:
+ - Apply name changes in all the different places we use d_alias and d_child
+ - Move the WARN_ON() in __d_free() to d_free() as we don't have dentry_free()]
+Signed-off-by: hujianyang <hujianyang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/platforms/cell/spufs/inode.c |    2 
+ fs/affs/amigaffs.c                        |    2 
+ fs/autofs4/expire.c                       |   12 ++---
+ fs/autofs4/root.c                         |    2 
+ fs/ceph/dir.c                             |    8 +--
+ fs/ceph/inode.c                           |    6 +-
+ fs/cifs/inode.c                           |    2 
+ fs/coda/cache.c                           |    2 
+ fs/dcache.c                               |   72 +++++++++++++++---------------
+ fs/debugfs/inode.c                        |    6 +-
+ fs/exportfs/expfs.c                       |    2 
+ fs/libfs.c                                |   12 ++---
+ fs/ncpfs/dir.c                            |    2 
+ fs/ncpfs/ncplib_kernel.h                  |    4 -
+ fs/nfs/getroot.c                          |    2 
+ fs/notify/fsnotify.c                      |    4 -
+ fs/ocfs2/dcache.c                         |    2 
+ include/linux/dcache.h                    |    8 +--
+ kernel/cgroup.c                           |    2 
+ kernel/trace/trace.c                      |    4 -
+ kernel/trace/trace_events.c               |    2 
+ security/selinux/selinuxfs.c              |    6 +-
+ 22 files changed, 82 insertions(+), 82 deletions(-)
+
+--- a/arch/powerpc/platforms/cell/spufs/inode.c
++++ b/arch/powerpc/platforms/cell/spufs/inode.c
+@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentr
+       struct dentry *dentry, *tmp;
+       mutex_lock(&dir->d_inode->i_mutex);
+-      list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
++      list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
+               spin_lock(&dentry->d_lock);
+               if (!(d_unhashed(dentry)) && dentry->d_inode) {
+                       dget_dlock(dentry);
+--- a/fs/affs/amigaffs.c
++++ b/fs/affs/amigaffs.c
+@@ -126,7 +126,7 @@ affs_fix_dcache(struct inode *inode, u32
+ {
+       struct dentry *dentry;
+       spin_lock(&inode->i_lock);
+-      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+               if (entry_ino == (u32)(long)dentry->d_fsdata) {
+                       dentry->d_fsdata = (void *)inode->i_ino;
+                       break;
+--- a/fs/autofs4/expire.c
++++ b/fs/autofs4/expire.c
+@@ -91,7 +91,7 @@ static struct dentry *get_next_positive_
+       spin_lock(&root->d_lock);
+       if (prev)
+-              next = prev->d_u.d_child.next;
++              next = prev->d_child.next;
+       else {
+               prev = dget_dlock(root);
+               next = prev->d_subdirs.next;
+@@ -105,13 +105,13 @@ cont:
+               return NULL;
+       }
+-      q = list_entry(next, struct dentry, d_u.d_child);
++      q = list_entry(next, struct dentry, d_child);
+       spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
+       /* Already gone or negative dentry (under construction) - try next */
+       if (q->d_count == 0 || !simple_positive(q)) {
+               spin_unlock(&q->d_lock);
+-              next = q->d_u.d_child.next;
++              next = q->d_child.next;
+               goto cont;
+       }
+       dget_dlock(q);
+@@ -161,13 +161,13 @@ again:
+                               goto relock;
+                       }
+                       spin_unlock(&p->d_lock);
+-                      next = p->d_u.d_child.next;
++                      next = p->d_child.next;
+                       p = parent;
+                       if (next != &parent->d_subdirs)
+                               break;
+               }
+       }
+-      ret = list_entry(next, struct dentry, d_u.d_child);
++      ret = list_entry(next, struct dentry, d_child);
+       spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
+       /* Negative dentry - try next */
+@@ -447,7 +447,7 @@ found:
+       spin_lock(&sbi->lookup_lock);
+       spin_lock(&expired->d_parent->d_lock);
+       spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
+-      list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
++      list_move(&expired->d_parent->d_subdirs, &expired->d_child);
+       spin_unlock(&expired->d_lock);
+       spin_unlock(&expired->d_parent->d_lock);
+       spin_unlock(&sbi->lookup_lock);
+--- a/fs/autofs4/root.c
++++ b/fs/autofs4/root.c
+@@ -655,7 +655,7 @@ static void autofs_clear_leaf_automount_
+       /* only consider parents below dentrys in the root */
+       if (IS_ROOT(parent->d_parent))
+               return;
+-      d_child = &dentry->d_u.d_child;
++      d_child = &dentry->d_child;
+       /* Set parent managed if it's becoming empty */
+       if (d_child->next == &parent->d_subdirs &&
+           d_child->prev == &parent->d_subdirs)
+--- a/fs/ceph/dir.c
++++ b/fs/ceph/dir.c
+@@ -103,7 +103,7 @@ static unsigned fpos_off(loff_t p)
+ /*
+  * When possible, we try to satisfy a readdir by peeking at the
+  * dcache.  We make this work by carefully ordering dentries on
+- * d_u.d_child when we initially get results back from the MDS, and
++ * d_child when we initially get results back from the MDS, and
+  * falling back to a "normal" sync readdir if any dentries in the dir
+  * are dropped.
+  *
+@@ -139,11 +139,11 @@ static int __dcache_readdir(struct file
+               p = parent->d_subdirs.prev;
+               dout(" initial p %p/%p\n", p->prev, p->next);
+       } else {
+-              p = last->d_u.d_child.prev;
++              p = last->d_child.prev;
+       }
+ more:
+-      dentry = list_entry(p, struct dentry, d_u.d_child);
++      dentry = list_entry(p, struct dentry, d_child);
+       di = ceph_dentry(dentry);
+       while (1) {
+               dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
+@@ -165,7 +165,7 @@ more:
+                    !dentry->d_inode ? " null" : "");
+               spin_unlock(&dentry->d_lock);
+               p = p->prev;
+-              dentry = list_entry(p, struct dentry, d_u.d_child);
++              dentry = list_entry(p, struct dentry, d_child);
+               di = ceph_dentry(dentry);
+       }
+--- a/fs/ceph/inode.c
++++ b/fs/ceph/inode.c
+@@ -867,9 +867,9 @@ static void ceph_set_dentry_offset(struc
+       spin_lock(&dir->d_lock);
+       spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
+-      list_move(&dn->d_u.d_child, &dir->d_subdirs);
++      list_move(&dn->d_child, &dir->d_subdirs);
+       dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
+-           dn->d_u.d_child.prev, dn->d_u.d_child.next);
++           dn->d_child.prev, dn->d_child.next);
+       spin_unlock(&dn->d_lock);
+       spin_unlock(&dir->d_lock);
+ }
+@@ -1296,7 +1296,7 @@ retry_lookup:
+                       /* reorder parent's d_subdirs */
+                       spin_lock(&parent->d_lock);
+                       spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
+-                      list_move(&dn->d_u.d_child, &parent->d_subdirs);
++                      list_move(&dn->d_child, &parent->d_subdirs);
+                       spin_unlock(&dn->d_lock);
+                       spin_unlock(&parent->d_lock);
+               }
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -832,7 +832,7 @@ inode_has_hashed_dentries(struct inode *
+       struct dentry *dentry;
+       spin_lock(&inode->i_lock);
+-      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+               if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
+                       spin_unlock(&inode->i_lock);
+                       return true;
+--- a/fs/coda/cache.c
++++ b/fs/coda/cache.c
+@@ -92,7 +92,7 @@ static void coda_flag_children(struct de
+       struct dentry *de;
+       spin_lock(&parent->d_lock);
+-      list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
++      list_for_each_entry(de, &parent->d_subdirs, d_child) {
+               /* don't know what to do with negative dentries */
+               if (de->d_inode ) 
+                       coda_flag_inode(de->d_inode, flag);
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -43,7 +43,7 @@
+ /*
+  * Usage:
+  * dcache->d_inode->i_lock protects:
+- *   - i_dentry, d_alias, d_inode of aliases
++ *   - i_dentry, d_u.d_alias, d_inode of aliases
+  * dcache_hash_bucket lock protects:
+  *   - the dcache hash table
+  * s_anon bl list spinlock protects:
+@@ -58,7 +58,7 @@
+  *   - d_unhashed()
+  *   - d_parent and d_subdirs
+  *   - childrens' d_child and d_parent
+- *   - d_alias, d_inode
++ *   - d_u.d_alias, d_inode
+  *
+  * Ordering:
+  * dentry->d_inode->i_lock
+@@ -215,7 +215,6 @@ static void __d_free(struct rcu_head *he
+ {
+       struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
+-      WARN_ON(!hlist_unhashed(&dentry->d_alias));
+       if (dname_external(dentry))
+               kfree(dentry->d_name.name);
+       kmem_cache_free(dentry_cache, dentry); 
+@@ -226,6 +225,7 @@ static void __d_free(struct rcu_head *he
+  */
+ static void d_free(struct dentry *dentry)
+ {
++      WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
+       BUG_ON(dentry->d_count);
+       this_cpu_dec(nr_dentry);
+       if (dentry->d_op && dentry->d_op->d_release)
+@@ -264,7 +264,7 @@ static void dentry_iput(struct dentry *
+       struct inode *inode = dentry->d_inode;
+       if (inode) {
+               dentry->d_inode = NULL;
+-              hlist_del_init(&dentry->d_alias);
++              hlist_del_init(&dentry->d_u.d_alias);
+               spin_unlock(&dentry->d_lock);
+               spin_unlock(&inode->i_lock);
+               if (!inode->i_nlink)
+@@ -288,7 +288,7 @@ static void dentry_unlink_inode(struct d
+ {
+       struct inode *inode = dentry->d_inode;
+       dentry->d_inode = NULL;
+-      hlist_del_init(&dentry->d_alias);
++      hlist_del_init(&dentry->d_u.d_alias);
+       dentry_rcuwalk_barrier(dentry);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&inode->i_lock);
+@@ -364,7 +364,7 @@ static struct dentry *d_kill(struct dent
+       __releases(parent->d_lock)
+       __releases(dentry->d_inode->i_lock)
+ {
+-      list_del(&dentry->d_u.d_child);
++      list_del(&dentry->d_child);
+       /*
+        * Inform try_to_ascend() that we are no longer attached to the
+        * dentry tree
+@@ -660,7 +660,7 @@ static struct dentry *__d_find_alias(str
+ again:
+       discon_alias = NULL;
+-      hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
+               spin_lock(&alias->d_lock);
+               if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
+                       if (IS_ROOT(alias) &&
+@@ -713,7 +713,7 @@ void d_prune_aliases(struct inode *inode
+       struct dentry *dentry;
+ restart:
+       spin_lock(&inode->i_lock);
+-      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+               spin_lock(&dentry->d_lock);
+               if (!dentry->d_count) {
+                       __dget_dlock(dentry);
+@@ -893,7 +893,7 @@ static void shrink_dcache_for_umount_sub
+               /* 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);
++                                          struct dentry, d_child);
+               /* consume the dentries from this leaf up through its parents
+                * until we find one with children or run out altogether */
+@@ -927,17 +927,17 @@ static void shrink_dcache_for_umount_sub
+                       if (IS_ROOT(dentry)) {
+                               parent = NULL;
+-                              list_del(&dentry->d_u.d_child);
++                              list_del(&dentry->d_child);
+                       } else {
+                               parent = dentry->d_parent;
+                               parent->d_count--;
+-                              list_del(&dentry->d_u.d_child);
++                              list_del(&dentry->d_child);
+                       }
+                       inode = dentry->d_inode;
+                       if (inode) {
+                               dentry->d_inode = NULL;
+-                              hlist_del_init(&dentry->d_alias);
++                              hlist_del_init(&dentry->d_u.d_alias);
+                               if (dentry->d_op && dentry->d_op->d_iput)
+                                       dentry->d_op->d_iput(dentry, inode);
+                               else
+@@ -955,7 +955,7 @@ static void shrink_dcache_for_umount_sub
+               } while (list_empty(&dentry->d_subdirs));
+               dentry = list_entry(dentry->d_subdirs.next,
+-                                  struct dentry, d_u.d_child);
++                                  struct dentry, d_child);
+       }
+ }
+@@ -1048,7 +1048,7 @@ repeat:
+ resume:
+       while (next != &this_parent->d_subdirs) {
+               struct list_head *tmp = next;
+-              struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
++              struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               next = tmp->next;
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+@@ -1075,7 +1075,7 @@ resume:
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
+                       goto rename_retry;
+-              next = child->d_u.d_child.next;
++              next = child->d_child.next;
+               goto resume;
+       }
+       spin_unlock(&this_parent->d_lock);
+@@ -1131,7 +1131,7 @@ repeat:
+ resume:
+       while (next != &this_parent->d_subdirs) {
+               struct list_head *tmp = next;
+-              struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
++              struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               next = tmp->next;
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+@@ -1182,7 +1182,7 @@ resume:
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
+                       goto rename_retry;
+-              next = child->d_u.d_child.next;
++              next = child->d_child.next;
+               goto resume;
+       }
+ out:
+@@ -1278,8 +1278,8 @@ struct dentry *__d_alloc(struct super_bl
+       INIT_HLIST_BL_NODE(&dentry->d_hash);
+       INIT_LIST_HEAD(&dentry->d_lru);
+       INIT_LIST_HEAD(&dentry->d_subdirs);
+-      INIT_HLIST_NODE(&dentry->d_alias);
+-      INIT_LIST_HEAD(&dentry->d_u.d_child);
++      INIT_HLIST_NODE(&dentry->d_u.d_alias);
++      INIT_LIST_HEAD(&dentry->d_child);
+       d_set_d_op(dentry, dentry->d_sb->s_d_op);
+       this_cpu_inc(nr_dentry);
+@@ -1309,7 +1309,7 @@ struct dentry *d_alloc(struct dentry * p
+        */
+       __dget_dlock(parent);
+       dentry->d_parent = parent;
+-      list_add(&dentry->d_u.d_child, &parent->d_subdirs);
++      list_add(&dentry->d_child, &parent->d_subdirs);
+       spin_unlock(&parent->d_lock);
+       return dentry;
+@@ -1369,7 +1369,7 @@ static void __d_instantiate(struct dentr
+       if (inode) {
+               if (unlikely(IS_AUTOMOUNT(inode)))
+                       dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+-              hlist_add_head(&dentry->d_alias, &inode->i_dentry);
++              hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
+       }
+       dentry->d_inode = inode;
+       dentry_rcuwalk_barrier(dentry);
+@@ -1394,7 +1394,7 @@ static void __d_instantiate(struct dentr
+  
+ void d_instantiate(struct dentry *entry, struct inode * inode)
+ {
+-      BUG_ON(!hlist_unhashed(&entry->d_alias));
++      BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
+       if (inode)
+               spin_lock(&inode->i_lock);
+       __d_instantiate(entry, inode);
+@@ -1433,7 +1433,7 @@ static struct dentry *__d_instantiate_un
+               return NULL;
+       }
+-      hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
+               /*
+                * Don't need alias->d_lock here, because aliases with
+                * d_parent == entry->d_parent are not subject to name or
+@@ -1459,7 +1459,7 @@ struct dentry *d_instantiate_unique(stru
+ {
+       struct dentry *result;
+-      BUG_ON(!hlist_unhashed(&entry->d_alias));
++      BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
+       if (inode)
+               spin_lock(&inode->i_lock);
+@@ -1502,7 +1502,7 @@ static struct dentry * __d_find_any_alia
+       if (hlist_empty(&inode->i_dentry))
+               return NULL;
+-      alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
++      alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
+       __dget(alias);
+       return alias;
+ }
+@@ -1576,7 +1576,7 @@ struct dentry *d_obtain_alias(struct ino
+       spin_lock(&tmp->d_lock);
+       tmp->d_inode = inode;
+       tmp->d_flags |= DCACHE_DISCONNECTED;
+-      hlist_add_head(&tmp->d_alias, &inode->i_dentry);
++      hlist_add_head(&tmp->d_u.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);
+       hlist_bl_unlock(&tmp->d_sb->s_anon);
+@@ -2019,7 +2019,7 @@ int d_validate(struct dentry *dentry, st
+       struct dentry *child;
+       spin_lock(&dparent->d_lock);
+-      list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
++      list_for_each_entry(child, &dparent->d_subdirs, d_child) {
+               if (dentry == child) {
+                       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+                       __dget_dlock(dentry);
+@@ -2266,8 +2266,8 @@ static void __d_move(struct dentry * den
+       /* Unhash the target: dput() will then get rid of it */
+       __d_drop(target);
+-      list_del(&dentry->d_u.d_child);
+-      list_del(&target->d_u.d_child);
++      list_del(&dentry->d_child);
++      list_del(&target->d_child);
+       /* Switch the names.. */
+       switch_names(dentry, target);
+@@ -2277,15 +2277,15 @@ static void __d_move(struct dentry * den
+       if (IS_ROOT(dentry)) {
+               dentry->d_parent = target->d_parent;
+               target->d_parent = target;
+-              INIT_LIST_HEAD(&target->d_u.d_child);
++              INIT_LIST_HEAD(&target->d_child);
+       } else {
+               swap(dentry->d_parent, target->d_parent);
+               /* And add them back to the (new) parent lists */
+-              list_add(&target->d_u.d_child, &target->d_parent->d_subdirs);
++              list_add(&target->d_child, &target->d_parent->d_subdirs);
+       }
+-      list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
++      list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
+       write_seqcount_end(&target->d_seq);
+       write_seqcount_end(&dentry->d_seq);
+@@ -2392,9 +2392,9 @@ static void __d_materialise_dentry(struc
+       swap(dentry->d_name.hash, anon->d_name.hash);
+       dentry->d_parent = dentry;
+-      list_del_init(&dentry->d_u.d_child);
++      list_del_init(&dentry->d_child);
+       anon->d_parent = dparent;
+-      list_move(&anon->d_u.d_child, &dparent->d_subdirs);
++      list_move(&anon->d_child, &dparent->d_subdirs);
+       write_seqcount_end(&dentry->d_seq);
+       write_seqcount_end(&anon->d_seq);
+@@ -2933,7 +2933,7 @@ repeat:
+ resume:
+       while (next != &this_parent->d_subdirs) {
+               struct list_head *tmp = next;
+-              struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
++              struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               next = tmp->next;
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+@@ -2963,7 +2963,7 @@ resume:
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
+                       goto rename_retry;
+-              next = child->d_u.d_child.next;
++              next = child->d_child.next;
+               goto resume;
+       }
+       spin_unlock(&this_parent->d_lock);
+--- a/fs/debugfs/inode.c
++++ b/fs/debugfs/inode.c
+@@ -545,7 +545,7 @@ void debugfs_remove_recursive(struct den
+       parent = dentry;
+  down:
+       mutex_lock(&parent->d_inode->i_mutex);
+-      list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) {
++      list_for_each_entry_safe(child, next, &parent->d_subdirs, d_child) {
+               if (!debugfs_positive(child))
+                       continue;
+@@ -566,8 +566,8 @@ void debugfs_remove_recursive(struct den
+       mutex_lock(&parent->d_inode->i_mutex);
+       if (child != dentry) {
+-              next = list_entry(child->d_u.d_child.next, struct dentry,
+-                                      d_u.d_child);
++              next = list_entry(child->d_child.next, struct dentry,
++                                      d_child);
+               goto up;
+       }
+--- a/fs/exportfs/expfs.c
++++ b/fs/exportfs/expfs.c
+@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *res
+       inode = result->d_inode;
+       spin_lock(&inode->i_lock);
+-      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+               dget(dentry);
+               spin_unlock(&inode->i_lock);
+               if (toput)
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -104,18 +104,18 @@ loff_t dcache_dir_lseek(struct file *fil
+                       spin_lock(&dentry->d_lock);
+                       /* d_lock not required for cursor */
+-                      list_del(&cursor->d_u.d_child);
++                      list_del(&cursor->d_child);
+                       p = dentry->d_subdirs.next;
+                       while (n && p != &dentry->d_subdirs) {
+                               struct dentry *next;
+-                              next = list_entry(p, struct dentry, d_u.d_child);
++                              next = list_entry(p, struct dentry, d_child);
+                               spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
+                               if (simple_positive(next))
+                                       n--;
+                               spin_unlock(&next->d_lock);
+                               p = p->next;
+                       }
+-                      list_add_tail(&cursor->d_u.d_child, p);
++                      list_add_tail(&cursor->d_child, p);
+                       spin_unlock(&dentry->d_lock);
+               }
+       }
+@@ -139,7 +139,7 @@ int dcache_readdir(struct file * filp, v
+ {
+       struct dentry *dentry = filp->f_path.dentry;
+       struct dentry *cursor = filp->private_data;
+-      struct list_head *p, *q = &cursor->d_u.d_child;
++      struct list_head *p, *q = &cursor->d_child;
+       ino_t ino;
+       int i = filp->f_pos;
+@@ -165,7 +165,7 @@ int dcache_readdir(struct file * filp, v
+                       for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
+                               struct dentry *next;
+-                              next = list_entry(p, struct dentry, d_u.d_child);
++                              next = list_entry(p, struct dentry, d_child);
+                               spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
+                               if (!simple_positive(next)) {
+                                       spin_unlock(&next->d_lock);
+@@ -289,7 +289,7 @@ int simple_empty(struct dentry *dentry)
+       int ret = 0;
+       spin_lock(&dentry->d_lock);
+-      list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
++      list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+               spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
+               if (simple_positive(child)) {
+                       spin_unlock(&child->d_lock);
+--- a/fs/ncpfs/dir.c
++++ b/fs/ncpfs/dir.c
+@@ -391,7 +391,7 @@ ncp_dget_fpos(struct dentry *dentry, str
+       spin_lock(&parent->d_lock);
+       next = parent->d_subdirs.next;
+       while (next != &parent->d_subdirs) {
+-              dent = list_entry(next, struct dentry, d_u.d_child);
++              dent = list_entry(next, struct dentry, d_child);
+               if ((unsigned long)dent->d_fsdata == fpos) {
+                       if (dent->d_inode)
+                               dget(dent);
+--- a/fs/ncpfs/ncplib_kernel.h
++++ b/fs/ncpfs/ncplib_kernel.h
+@@ -194,7 +194,7 @@ ncp_renew_dentries(struct dentry *parent
+       spin_lock(&parent->d_lock);
+       next = parent->d_subdirs.next;
+       while (next != &parent->d_subdirs) {
+-              dentry = list_entry(next, struct dentry, d_u.d_child);
++              dentry = list_entry(next, struct dentry, d_child);
+               if (dentry->d_fsdata == NULL)
+                       ncp_age_dentry(server, dentry);
+@@ -216,7 +216,7 @@ ncp_invalidate_dircache_entries(struct d
+       spin_lock(&parent->d_lock);
+       next = parent->d_subdirs.next;
+       while (next != &parent->d_subdirs) {
+-              dentry = list_entry(next, struct dentry, d_u.d_child);
++              dentry = list_entry(next, struct dentry, d_child);
+               dentry->d_fsdata = NULL;
+               ncp_age_dentry(server, dentry);
+               next = next->next;
+--- a/fs/nfs/getroot.c
++++ b/fs/nfs/getroot.c
+@@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root
+                */
+               spin_lock(&sb->s_root->d_inode->i_lock);
+               spin_lock(&sb->s_root->d_lock);
+-              hlist_del_init(&sb->s_root->d_alias);
++              hlist_del_init(&sb->s_root->d_u.d_alias);
+               spin_unlock(&sb->s_root->d_lock);
+               spin_unlock(&sb->s_root->d_inode->i_lock);
+       }
+--- a/fs/notify/fsnotify.c
++++ b/fs/notify/fsnotify.c
+@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flag
+       spin_lock(&inode->i_lock);
+       /* run all of the dentries associated with this inode.  Since this is a
+        * directory, there damn well better only be one item on this list */
+-      hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
+               struct dentry *child;
+               /* run all of the children of the original inode and fix their
+                * d_flags to indicate parental interest (their parent is the
+                * original inode) */
+               spin_lock(&alias->d_lock);
+-              list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
++              list_for_each_entry(child, &alias->d_subdirs, d_child) {
+                       if (!child->d_inode)
+                               continue;
+--- a/fs/ocfs2/dcache.c
++++ b/fs/ocfs2/dcache.c
+@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(st
+       struct dentry *dentry;
+       spin_lock(&inode->i_lock);
+-      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+               spin_lock(&dentry->d_lock);
+               if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
+                       trace_ocfs2_find_local_alias(dentry->d_name.len,
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -120,15 +120,15 @@ struct dentry {
+       void *d_fsdata;                 /* fs-specific data */
+       struct list_head d_lru;         /* LRU list */
++      struct list_head d_child;       /* child of parent list */
++      struct list_head d_subdirs;     /* our children */
+       /*
+-       * d_child and d_rcu can share memory
++       * d_alias and d_rcu can share memory
+        */
+       union {
+-              struct list_head d_child;       /* child of parent list */
++              struct hlist_node d_alias;      /* inode alias list */
+               struct rcu_head d_rcu;
+       } d_u;
+-      struct list_head d_subdirs;     /* our children */
+-      struct hlist_node d_alias;      /* inode alias list */
+ };
+ /*
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -984,7 +984,7 @@ static void cgroup_d_remove_dir(struct d
+       parent = dentry->d_parent;
+       spin_lock(&parent->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+-      list_del_init(&dentry->d_u.d_child);
++      list_del_init(&dentry->d_child);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
+       remove_dir(dentry);
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -6063,7 +6063,7 @@ static int instance_mkdir (struct inode
+       int ret;
+       /* Paranoid: Make sure the parent is the "instances" directory */
+-      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
++      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
+       if (WARN_ON_ONCE(parent != trace_instance_dir))
+               return -ENOENT;
+@@ -6090,7 +6090,7 @@ static int instance_rmdir(struct inode *
+       int ret;
+       /* Paranoid: Make sure the parent is the "instances" directory */
+-      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
++      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
+       if (WARN_ON_ONCE(parent != trace_instance_dir))
+               return -ENOENT;
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -425,7 +425,7 @@ static void remove_event_file_dir(struct
+       if (dir) {
+               spin_lock(&dir->d_lock);        /* probably unneeded */
+-              list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
++              list_for_each_entry(child, &dir->d_subdirs, d_child) {
+                       if (child->d_inode)     /* probably unneeded */
+                               child->d_inode->i_private = NULL;
+               }
+--- a/security/selinux/selinuxfs.c
++++ b/security/selinux/selinuxfs.c
+@@ -1190,7 +1190,7 @@ static void sel_remove_entries(struct de
+       spin_lock(&de->d_lock);
+       node = de->d_subdirs.next;
+       while (node != &de->d_subdirs) {
+-              struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
++              struct dentry *d = list_entry(node, struct dentry, d_child);
+               spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
+               list_del_init(node);
+@@ -1664,12 +1664,12 @@ static void sel_remove_classes(void)
+       list_for_each(class_node, &class_dir->d_subdirs) {
+               struct dentry *class_subdir = list_entry(class_node,
+-                                      struct dentry, d_u.d_child);
++                                      struct dentry, d_child);
+               struct list_head *class_subdir_node;
+               list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
+                       struct dentry *d = list_entry(class_subdir_node,
+-                                              struct dentry, d_u.d_child);
++                                              struct dentry, d_child);
+                       if (d->d_inode)
+                               if (d->d_inode->i_mode & S_IFDIR)
index 32564565d610b257c600edf58d98f5d67c48a56b..5a766a75ecd6e9ca51dbb631c27847df97e98fea 100644 (file)
@@ -23,3 +23,5 @@ bluetooth-ignore-isochronous-endpoints-for-intel-usb-bootloader.patch
 netfilter-conntrack-disable-generic-tracking-for-known-protocols.patch
 kvm-x86-sysenter-emulation-is-broken.patch
 utf-8-q-kconfig-20fix-20warning-20-e2-80-98jump.patch
+move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch
+deal-with-deadlock-in-d_walk.patch