[kernel] r22392 - in dists/wheezy-security/linux/debian: . patches patches/bugfix/all patches/debian
Ben Hutchings
benh at moszumanska.debian.org
Tue Feb 17 04:40:53 UTC 2015
Author: benh
Date: Tue Feb 17 04:40:53 2015
New Revision: 22392
Log:
Add patches for CVE-2014-8559
Added:
dists/wheezy-security/linux/debian/patches/bugfix/all/aufs-move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch
dists/wheezy-security/linux/debian/patches/bugfix/all/dcache-fix-locking-bugs-in-backported-deal-with-deadlock-in-d_walk.patch
dists/wheezy-security/linux/debian/patches/bugfix/all/deal-with-deadlock-in-d_walk.patch
dists/wheezy-security/linux/debian/patches/bugfix/all/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch
dists/wheezy-security/linux/debian/patches/debian/vfs-avoid-abi-change-for-dentry-union-changes.patch
Modified:
dists/wheezy-security/linux/debian/changelog
dists/wheezy-security/linux/debian/patches/series
Modified: dists/wheezy-security/linux/debian/changelog
==============================================================================
--- dists/wheezy-security/linux/debian/changelog Mon Feb 16 03:57:44 2015 (r22391)
+++ dists/wheezy-security/linux/debian/changelog Tue Feb 17 04:40:53 2015 (r22392)
@@ -13,6 +13,9 @@
* [x86] KVM: x86 emulator: reject SYSENTER in compatibility mode on AMD
guests
* [x86] KVM: SYSENTER emulation is broken (CVE-2015-0239)
+ * vfs: move d_rcu from overlapping d_child to overlapping d_alias
+ * aufs: move d_rcu from overlapping d_child to overlapping d_alias
+ * vfs: deal with deadlock in d_walk() (CVE-2014-8559)
-- Ben Hutchings <ben at decadent.org.uk> Thu, 29 Jan 2015 04:02:31 +0000
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/aufs-move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/aufs-move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch Tue Feb 17 04:40:53 2015 (r22392)
@@ -0,0 +1,71 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Mon, 12 Jan 2015 04:12:45 +0000
+Subject: aufs: move d_rcu from overlapping d_child to overlapping d_alias
+Forwarded: not-needed
+
+Apply the renaming from commit 946e51f2bf37f1656916eb75bd0742ba33983c28
+upstream to aufs.
+
+---
+--- a/fs/aufs/dcsub.c
++++ b/fs/aufs/dcsub.c
+@@ -134,7 +134,7 @@ resume:
+ while (next != &this_parent->d_subdirs) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry,
+- d_u.d_child);
++ d_child);
+
+ next = tmp->next;
+ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+@@ -170,7 +170,7 @@ resume:
+ this_parent = tmp;
+ spin_lock(&this_parent->d_lock);
+ rcu_read_unlock();
+- next = child->d_u.d_child.next;
++ next = child->d_child.next;
+ goto resume;
+ }
+
+--- a/fs/aufs/debug.c
++++ b/fs/aufs/debug.c
+@@ -140,7 +140,7 @@ void au_dpri_dalias(struct inode *inode)
+ struct dentry *d;
+
+ spin_lock(&inode->i_lock);
+- list_for_each_entry(d, &inode->i_dentry, d_alias)
++ list_for_each_entry(d, &inode->i_dentry, d_u.d_alias)
+ au_dpri_dentry(d);
+ spin_unlock(&inode->i_lock);
+ }
+--- a/fs/aufs/export.c
++++ b/fs/aufs/export.c
+@@ -228,7 +228,7 @@ static struct dentry *decode_by_ino(stru
+ dentry = d_find_alias(inode);
+ else {
+ spin_lock(&inode->i_lock);
+- list_for_each_entry(d, &inode->i_dentry, d_alias) {
++ list_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
+ spin_lock(&d->d_lock);
+ if (!au_test_anon(d)
+ && d->d_parent->d_inode->i_ino == dir_ino) {
+--- a/fs/aufs/hnotify.c
++++ b/fs/aufs/hnotify.c
+@@ -212,7 +212,7 @@ static int hn_gen_by_inode(char *name, u
+ AuDebugOn(!name);
+ au_iigen_dec(inode);
+ spin_lock(&inode->i_lock);
+- list_for_each_entry(d, &inode->i_dentry, d_alias) {
++ list_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
+ spin_lock(&d->d_lock);
+ dname = &d->d_name;
+ if (dname->len != nlen
+@@ -378,7 +378,7 @@ static struct dentry *lookup_wlock_by_na
+
+ dentry = NULL;
+ spin_lock(&parent->d_lock);
+- list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
++ list_for_each_entry(d, &parent->d_subdirs, d_child) {
+ /* AuDbg("%.*s\n", AuDLNPair(d)); */
+ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
+ dname = &d->d_name;
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/dcache-fix-locking-bugs-in-backported-deal-with-deadlock-in-d_walk.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/dcache-fix-locking-bugs-in-backported-deal-with-deadlock-in-d_walk.patch Tue Feb 17 04:40:53 2015 (r22392)
@@ -0,0 +1,103 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Wed, 11 Feb 2015 03:16:35 +0000
+Subject: dcache: Fix locking bugs in backported "deal with deadlock in d_walk()"
+
+Steven Rostedt reported:
+> Porting -rt to the latest 3.2 stable tree I triggered this bug:
+>
+> =====================================
+> [ BUG: bad unlock balance detected! ]
+> -------------------------------------
+> rm/1638 is trying to release lock (rcu_read_lock) at:
+> [<c04fde6c>] rcu_read_unlock+0x0/0x23
+> but there are no more locks to release!
+>
+> other info that might help us debug this:
+> 2 locks held by rm/1638:
+> #0: (&sb->s_type->i_mutex_key#9/1){+.+.+.}, at: [<c04f93eb>] do_rmdir+0x5f/0xd2
+> #1: (&sb->s_type->i_mutex_key#9){+.+.+.}, at: [<c04f9329>] vfs_rmdir+0x49/0xac
+>
+> stack backtrace:
+> Pid: 1638, comm: rm Not tainted 3.2.66-test-rt96+ #2
+> Call Trace:
+> [<c083f390>] ? printk+0x1d/0x1f
+> [<c0463cdf>] print_unlock_inbalance_bug+0xc3/0xcd
+> [<c04653a8>] lock_release_non_nested+0x98/0x1ec
+> [<c046228d>] ? trace_hardirqs_off_caller+0x18/0x90
+> [<c0456f1c>] ? local_clock+0x2d/0x50
+> [<c04fde6c>] ? d_hash+0x2f/0x2f
+> [<c04fde6c>] ? d_hash+0x2f/0x2f
+> [<c046568e>] lock_release+0x192/0x1ad
+> [<c04fde83>] rcu_read_unlock+0x17/0x23
+> [<c04ff344>] shrink_dcache_parent+0x227/0x270
+> [<c04f9348>] vfs_rmdir+0x68/0xac
+> [<c04f9424>] do_rmdir+0x98/0xd2
+> [<c04f03ad>] ? fput+0x1a3/0x1ab
+> [<c084dd42>] ? sysenter_exit+0xf/0x1a
+> [<c0465b58>] ? trace_hardirqs_on_caller+0x118/0x149
+> [<c04fa3e0>] sys_unlinkat+0x2b/0x35
+> [<c084dd13>] sysenter_do_call+0x12/0x12
+>
+>
+>
+>
+> There's a path to calling rcu_read_unlock() without calling
+> rcu_read_lock() in have_submounts().
+>
+> goto positive;
+>
+> positive:
+> if (!locked && read_seqretry(&rename_lock, seq))
+> goto rename_retry;
+>
+> rename_retry:
+> rcu_read_unlock();
+>
+> in the above path, rcu_read_lock() is never done before calling
+> rcu_read_unlock();
+
+I reviewed locking contexts in all three functions that I changed when
+backporting "deal with deadlock in d_walk()". It's actually worse
+than this:
+
+- We don't hold this_parent->d_lock at the 'positive' label in
+ have_submounts(), but it is unlocked after 'rename_retry'.
+- There is an rcu_read_unlock() after the 'out' label in
+ select_parent(), but it's not held at the 'goto out'.
+
+Fix all three lock imbalances.
+
+Reported-by: Steven Rostedt <rostedt at goodmis.org>
+Signed-off-by: Ben Hutchings <ben at decadent.org.uk>
+Tested-by: Steven Rostedt <rostedt at goodmis.org>
+---
+ fs/dcache.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -1035,7 +1035,7 @@ ascend:
+ return 0; /* No mount points found in tree */
+ positive:
+ if (!locked && read_seqretry(&rename_lock, seq))
+- goto rename_retry;
++ goto rename_retry_unlocked;
+ if (locked)
+ write_sequnlock(&rename_lock);
+ return 1;
+@@ -1045,6 +1045,7 @@ rename_retry:
+ rcu_read_unlock();
+ if (locked)
+ goto again;
++rename_retry_unlocked:
+ locked = 1;
+ write_seqlock(&rename_lock);
+ goto again;
+@@ -1109,6 +1110,7 @@ resume:
+ */
+ if (found && need_resched()) {
+ spin_unlock(&dentry->d_lock);
++ rcu_read_lock();
+ goto out;
+ }
+
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/deal-with-deadlock-in-d_walk.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/deal-with-deadlock-in-d_walk.patch Tue Feb 17 04:40:53 2015 (r22392)
@@ -0,0 +1,206 @@
+From: Al Viro <viro at zeniv.linux.org.uk>
+Date: Sun, 26 Oct 2014 19:31:10 -0400
+Subject: deal with deadlock in d_walk()
+
+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 at zeniv.linux.org.uk>
+[bwh: Backported to 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: Ben Hutchings <ben at decadent.org.uk>
+---
+ fs/dcache.c | 31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -306,9 +306,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;
+@@ -949,34 +949,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.
+@@ -1032,17 +1004,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 */
+@@ -1054,6 +1041,8 @@ positive:
+ return 1;
+
+ rename_retry:
++ spin_unlock(&this_parent->d_lock);
++ rcu_read_unlock();
+ if (locked)
+ goto again;
+ locked = 1;
+@@ -1139,23 +1128,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)
+@@ -2914,26 +2920,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;
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch Tue Feb 17 04:40:53 2015 (r22392)
@@ -0,0 +1,754 @@
+From: Al Viro <viro at 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
+
+commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
+
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+[bwh: Backported to 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: Ben Hutchings <ben at decadent.org.uk>
+---
+--- a/arch/powerpc/platforms/cell/spufs/inode.c
++++ b/arch/powerpc/platforms/cell/spufs/inode.c
+@@ -165,7 +165,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);
+@@ -223,7 +223,7 @@ out:
+ * - free child's inode if possible
+ * - free child
+ */
+- 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) {
+ dput(dentry);
+ }
+
+--- a/drivers/usb/core/inode.c
++++ b/drivers/usb/core/inode.c
+@@ -212,7 +212,7 @@ static void update_bus(struct dentry *bu
+
+ mutex_lock(&bus->d_inode->i_mutex);
+
+- list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
++ list_for_each_entry(dev, &bus->d_subdirs, d_child)
+ if (dev->d_inode)
+ update_dev(dev);
+
+@@ -229,7 +229,7 @@ static void update_sb(struct super_block
+
+ mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
+
+- list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
++ list_for_each_entry(bus, &root->d_subdirs, d_child) {
+ if (bus->d_inode) {
+ switch (S_IFMT & bus->d_inode->i_mode) {
+ case S_IFDIR:
+@@ -345,7 +345,7 @@ static int usbfs_empty (struct dentry *d
+
+ spin_lock(&dentry->d_lock);
+ list_for_each(list, &dentry->d_subdirs) {
+- struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
++ struct dentry *de = list_entry(list, struct dentry, d_child);
+
+ spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
+ if (usbfs_positive(de)) {
+--- a/fs/9p/vfs_inode_dotl.c
++++ b/fs/9p/vfs_inode_dotl.c
+@@ -81,7 +81,7 @@ static struct dentry *v9fs_dentry_from_d
+ spin_lock(&inode->i_lock);
+ /* Directory should have only one entry. */
+ BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
+- dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
++ dentry = list_entry(inode->i_dentry.next, struct dentry, d_u.d_alias);
+ spin_unlock(&inode->i_lock);
+ return dentry;
+ }
+--- a/fs/affs/amigaffs.c
++++ b/fs/affs/amigaffs.c
+@@ -132,7 +132,7 @@ affs_fix_dcache(struct dentry *dentry, u
+ head = &inode->i_dentry;
+ next = head->next;
+ while (next != head) {
+- dentry = list_entry(next, struct dentry, d_alias);
++ dentry = list_entry(next, struct dentry, d_u.d_alias);
+ if (entry_ino == (u32)(long)dentry->d_fsdata) {
+ dentry->d_fsdata = data;
+ break;
+--- a/fs/autofs4/expire.c
++++ b/fs/autofs4/expire.c
+@@ -100,7 +100,7 @@ static struct dentry *get_next_positive_
+ p = prev;
+ spin_lock(&p->d_lock);
+ again:
+- next = p->d_u.d_child.next;
++ next = p->d_child.next;
+ start:
+ if (next == &root->d_subdirs) {
+ spin_unlock(&p->d_lock);
+@@ -109,7 +109,7 @@ start:
+ 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);
+ /* Negative dentry - try next */
+@@ -165,13 +165,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 */
+@@ -455,7 +455,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
+@@ -651,7 +651,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
+@@ -104,7 +104,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.
+ *
+@@ -140,11 +140,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,
+@@ -166,7 +166,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
+@@ -868,9 +868,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);
+ }
+@@ -1256,7 +1256,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
+@@ -823,7 +823,7 @@ inode_has_hashed_dentries(struct inode *
+ struct dentry *dentry;
+
+ spin_lock(&inode->i_lock);
+- list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++ list_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
+@@ -95,7 +95,7 @@ static void coda_flag_children(struct de
+ spin_lock(&parent->d_lock);
+ list_for_each(child, &parent->d_subdirs)
+ {
+- de = list_entry(child, struct dentry, d_u.d_child);
++ de = list_entry(child, struct dentry, d_child);
+ /* don't know what to do with negative dentries */
+ if ( ! de->d_inode )
+ continue;
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -42,7 +42,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:
+@@ -57,7 +57,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
+@@ -140,7 +140,6 @@ static void __d_free(struct rcu_head *he
+ {
+ struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
+
+- WARN_ON(!list_empty(&dentry->d_alias));
+ if (dname_external(dentry))
+ kfree(dentry->d_name.name);
+ kmem_cache_free(dentry_cache, dentry);
+@@ -151,6 +150,7 @@ static void __d_free(struct rcu_head *he
+ */
+ static void d_free(struct dentry *dentry)
+ {
++ WARN_ON(!list_empty(&dentry->d_u.d_alias));
+ BUG_ON(dentry->d_count);
+ this_cpu_dec(nr_dentry);
+ if (dentry->d_op && dentry->d_op->d_release)
+@@ -189,7 +189,7 @@ static void dentry_iput(struct dentry *
+ struct inode *inode = dentry->d_inode;
+ if (inode) {
+ dentry->d_inode = NULL;
+- list_del_init(&dentry->d_alias);
++ list_del_init(&dentry->d_u.d_alias);
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&inode->i_lock);
+ if (!inode->i_nlink)
+@@ -213,7 +213,7 @@ static void dentry_unlink_inode(struct d
+ {
+ struct inode *inode = dentry->d_inode;
+ dentry->d_inode = NULL;
+- list_del_init(&dentry->d_alias);
++ list_del_init(&dentry->d_u.d_alias);
+ dentry_rcuwalk_barrier(dentry);
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&inode->i_lock);
+@@ -306,7 +306,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
+@@ -624,7 +624,7 @@ static struct dentry *__d_find_alias(str
+
+ again:
+ discon_alias = NULL;
+- list_for_each_entry(alias, &inode->i_dentry, d_alias) {
++ list_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) &&
+@@ -677,7 +677,7 @@ void d_prune_aliases(struct inode *inode
+ struct dentry *dentry;
+ restart:
+ spin_lock(&inode->i_lock);
+- list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++ list_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+ spin_lock(&dentry->d_lock);
+ if (!dentry->d_count) {
+ __dget_dlock(dentry);
+@@ -857,7 +857,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 */
+@@ -889,17 +889,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;
+- list_del_init(&dentry->d_alias);
++ list_del_init(&dentry->d_u.d_alias);
+ if (dentry->d_op && dentry->d_op->d_iput)
+ dentry->d_op->d_iput(dentry, inode);
+ else
+@@ -917,7 +917,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);
+ }
+ }
+
+@@ -1010,7 +1010,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);
+@@ -1037,7 +1037,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);
+@@ -1093,7 +1093,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);
+@@ -1144,7 +1144,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:
+@@ -1230,8 +1230,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_LIST_HEAD(&dentry->d_alias);
+- INIT_LIST_HEAD(&dentry->d_u.d_child);
++ INIT_LIST_HEAD(&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);
+@@ -1261,7 +1261,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;
+@@ -1318,7 +1318,7 @@ static void __d_instantiate(struct dentr
+ if (inode) {
+ if (unlikely(IS_AUTOMOUNT(inode)))
+ dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+- list_add(&dentry->d_alias, &inode->i_dentry);
++ list_add(&dentry->d_u.d_alias, &inode->i_dentry);
+ }
+ dentry->d_inode = inode;
+ dentry_rcuwalk_barrier(dentry);
+@@ -1343,7 +1343,7 @@ static void __d_instantiate(struct dentr
+
+ void d_instantiate(struct dentry *entry, struct inode * inode)
+ {
+- BUG_ON(!list_empty(&entry->d_alias));
++ BUG_ON(!list_empty(&entry->d_u.d_alias));
+ if (inode)
+ spin_lock(&inode->i_lock);
+ __d_instantiate(entry, inode);
+@@ -1382,7 +1382,7 @@ static struct dentry *__d_instantiate_un
+ return NULL;
+ }
+
+- list_for_each_entry(alias, &inode->i_dentry, d_alias) {
++ list_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
+ struct qstr *qstr = &alias->d_name;
+
+ /*
+@@ -1408,7 +1408,7 @@ struct dentry *d_instantiate_unique(stru
+ {
+ struct dentry *result;
+
+- BUG_ON(!list_empty(&entry->d_alias));
++ BUG_ON(!list_empty(&entry->d_u.d_alias));
+
+ if (inode)
+ spin_lock(&inode->i_lock);
+@@ -1458,7 +1458,7 @@ static struct dentry * __d_find_any_alia
+
+ if (list_empty(&inode->i_dentry))
+ return NULL;
+- alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
++ alias = list_first_entry(&inode->i_dentry, struct dentry, d_u.d_alias);
+ __dget(alias);
+ return alias;
+ }
+@@ -1525,7 +1525,7 @@ struct dentry *d_obtain_alias(struct ino
+ spin_lock(&tmp->d_lock);
+ tmp->d_inode = inode;
+ tmp->d_flags |= DCACHE_DISCONNECTED;
+- list_add(&tmp->d_alias, &inode->i_dentry);
++ list_add(&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);
+@@ -1931,7 +1931,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);
+@@ -2178,8 +2178,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);
+@@ -2189,15 +2189,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);
+@@ -2304,18 +2304,18 @@ static void __d_materialise_dentry(struc
+ swap(dentry->d_name.hash, anon->d_name.hash);
+
+ dentry->d_parent = (aparent == anon) ? dentry : aparent;
+- list_del(&dentry->d_u.d_child);
++ list_del(&dentry->d_child);
+ if (!IS_ROOT(dentry))
+- list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
++ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
+ else
+- INIT_LIST_HEAD(&dentry->d_u.d_child);
++ INIT_LIST_HEAD(&dentry->d_child);
+
+ anon->d_parent = (dparent == dentry) ? anon : dparent;
+- list_del(&anon->d_u.d_child);
++ list_del(&anon->d_child);
+ if (!IS_ROOT(anon))
+- list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs);
++ list_add(&anon->d_child, &anon->d_parent->d_subdirs);
+ else
+- INIT_LIST_HEAD(&anon->d_u.d_child);
++ INIT_LIST_HEAD(&anon->d_child);
+
+ write_seqcount_end(&dentry->d_seq);
+ write_seqcount_end(&anon->d_seq);
+@@ -2893,7 +2893,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);
+@@ -2923,7 +2923,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
+@@ -546,7 +546,7 @@ void debugfs_remove_recursive(struct den
+ * use the d_u.d_child as the rcu head and corrupt this list.
+ */
+ spin_lock(&parent->d_lock);
+- list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) {
++ list_for_each_entry(child, &parent->d_subdirs, d_child) {
+ if (!debugfs_positive(child))
+ continue;
+
+--- 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);
+- list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
++ list_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+ dget(dentry);
+ spin_unlock(&inode->i_lock);
+ if (toput)
+--- a/fs/ext4/fsync.c
++++ b/fs/ext4/fsync.c
+@@ -139,7 +139,7 @@ static int ext4_sync_parent(struct inode
+ spin_lock(&inode->i_lock);
+ if (!list_empty(&inode->i_dentry)) {
+ dentry = list_first_entry(&inode->i_dentry,
+- struct dentry, d_alias);
++ struct dentry, d_u.d_alias);
+ dget(dentry);
+ }
+ spin_unlock(&inode->i_lock);
+--- 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);
+@@ -282,7 +282,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
+@@ -65,7 +65,7 @@ static int nfs_superblock_set_dummy_root
+ */
+ spin_lock(&sb->s_root->d_inode->i_lock);
+ spin_lock(&sb->s_root->d_lock);
+- list_del_init(&sb->s_root->d_alias);
++ list_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
+@@ -62,14 +62,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 */
+- list_for_each_entry(alias, &inode->i_dentry, d_alias) {
++ list_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
+@@ -175,7 +175,7 @@ struct dentry *ocfs2_find_local_alias(st
+
+ spin_lock(&inode->i_lock);
+ list_for_each(p, &inode->i_dentry) {
+- dentry = list_entry(p, struct dentry, d_alias);
++ dentry = list_entry(p, struct dentry, d_u.d_alias);
+
+ spin_lock(&dentry->d_lock);
+ if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -133,15 +133,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 list_head d_alias; /* inode alias list */
+ struct rcu_head d_rcu;
+ } d_u;
+- struct list_head d_subdirs; /* our children */
+- struct list_head d_alias; /* inode alias list */
+ };
+
+ /*
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -881,7 +881,7 @@ static void cgroup_clear_directory(struc
+ spin_lock(&dentry->d_lock);
+ node = dentry->d_subdirs.next;
+ while (node != &dentry->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);
+@@ -915,7 +915,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/security/selinux/selinuxfs.c
++++ b/security/selinux/selinuxfs.c
+@@ -1197,7 +1197,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);
+@@ -1704,12 +1704,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)
Added: dists/wheezy-security/linux/debian/patches/debian/vfs-avoid-abi-change-for-dentry-union-changes.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/debian/vfs-avoid-abi-change-for-dentry-union-changes.patch Tue Feb 17 04:40:53 2015 (r22392)
@@ -0,0 +1,76 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Mon, 12 Jan 2015 04:54:59 +0000
+Subject: vfs: Avoid ABI change for dentry union changes
+Forwarded: not-needed
+
+Commit 946e51f2bf37f1656916eb75bd0742ba33983c28 ("move d_rcu from
+overlapping d_child to overlapping d_alias") looks disruptive and
+it is an API change since the union is named. However, it doesn't
+actually move anything that modules need, so it is not an ABI
+change and we can safely hide it from genksysms.
+
+Verify this by adding an unused function with some BUILD_BUG_ONs
+to assert the size and alignment of fields remain the same.
+
+---
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -133,15 +133,31 @@ struct dentry {
+ void *d_fsdata; /* fs-specific data */
+
+ struct list_head d_lru; /* LRU list */
++#ifdef __GENKSYMS__
++ /*
++ * bwh: The union changes here don't move anything other than
++ * d_rcu (which modules definitely should not touch). This is
++ * checked by dcache_abi_check().
++ */
++ union {
++#endif
+ struct list_head d_child; /* child of parent list */
++#ifdef __GENKSYMS__
++ struct rcu_head d_rcu;
++ } d_u;
++#endif
+ struct list_head d_subdirs; /* our children */
+ /*
+ * d_alias and d_rcu can share memory
+ */
++#ifndef __GENKSYMS__
+ union {
++#endif
+ struct list_head d_alias; /* inode alias list */
++#ifndef __GENKSYMS__
+ struct rcu_head d_rcu;
+ } d_u;
++#endif
+ };
+
+ /*
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -163,6 +163,24 @@ static void d_free(struct dentry *dentry
+ call_rcu(&dentry->d_u.d_rcu, __d_free);
+ }
+
++/*
++ * bwh: Assert that dentry union changes didn't change the structure
++ * layout other than to move d_rcu.
++ */
++static void __always_unused dcache_abi_check(void)
++{
++ struct dentry dentry;
++ union {
++ struct list_head d_child;
++ struct rcu_head d_rcu;
++ } old_d_u;
++ BUILD_BUG_ON(sizeof(dentry.d_child) != sizeof(old_d_u) ||
++ __alignof__(dentry.d_child) != __alignof__(old_d_u));
++ BUILD_BUG_ON(sizeof(dentry.d_u.d_alias) != sizeof(dentry.d_u) ||
++ __alignof__(dentry.d_u.d_alias) !=
++ __alignof__(dentry.d_u));
++}
++
+ /**
+ * dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups
+ * @dentry: the target dentry
Modified: dists/wheezy-security/linux/debian/patches/series
==============================================================================
--- dists/wheezy-security/linux/debian/patches/series Mon Feb 16 03:57:44 2015 (r22391)
+++ dists/wheezy-security/linux/debian/patches/series Tue Feb 17 04:40:53 2015 (r22392)
@@ -1161,3 +1161,8 @@
bugfix/x86/x86_64-vdso-fix-the-vdso-address-randomization-algor.patch
bugfix/x86/kvm-x86-emulator-reject-sysenter-in-compatibility-mo.patch
bugfix/x86/kvm-x86-sysenter-emulation-is-broken.patch
+bugfix/all/move-d_rcu-from-overlapping-d_child-to-overlapping-d_alias.patch
+bugfix/all/aufs-move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch
+bugfix/all/deal-with-deadlock-in-d_walk.patch
+bugfix/all/dcache-fix-locking-bugs-in-backported-deal-with-deadlock-in-d_walk.patch
+debian/vfs-avoid-abi-change-for-dentry-union-changes.patch
More information about the Kernel-svn-changes
mailing list