[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