From: Greg Kroah-Hartman Date: Sun, 26 Apr 2015 10:21:48 +0000 (+0200) Subject: 3.10-stable patches X-Git-Tag: v4.0.1~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4150d718dc548a03bf05f060049c5282e2f39fad;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: deal-with-deadlock-in-d_walk.patch move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch --- 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 index 00000000000..712038a4d81 --- /dev/null +++ b/queue-3.10/deal-with-deadlock-in-d_walk.patch @@ -0,0 +1,212 @@ +From ca5358ef75fc69fee5322a38a340f5739d997c10 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sun, 26 Oct 2014 19:31:10 -0400 +Subject: deal with deadlock in d_walk() + +From: Al Viro + +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 +Cc: Ben Hutchings +[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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..a3517b9d3a5 --- /dev/null +++ b/queue-3.10/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch @@ -0,0 +1,750 @@ +From 946e51f2bf37f1656916eb75bd0742ba33983c28 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sun, 26 Oct 2014 19:19:16 -0400 +Subject: move d_rcu from overlapping d_child to overlapping d_alias + +From: Al Viro + +commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream. + +Signed-off-by: Al Viro +Cc: Ben Hutchings +[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 +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-3.10/series b/queue-3.10/series index 32564565d61..5a766a75ecd 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -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