aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2006-01-08 04:03:32 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:13:58 -0500
commit5160ee6fc891a9ca114be0e90fa6655647bb64b2 (patch)
tree35d3740a777935582af1b78238f20d2c2971ed55
parent21b6bf143d05d77c350d9c6764ae090a877b66ea (diff)
[PATCH] shrink dentry struct
Some long time ago, dentry struct was carefully tuned so that on 32 bits UP, sizeof(struct dentry) was exactly 128, ie a power of 2, and a multiple of memory cache lines. Then RCU was added and dentry struct enlarged by two pointers, with nice results for SMP, but not so good on UP, because breaking the above tuning (128 + 8 = 136 bytes) This patch reverts this unwanted side effect, by using an union (d_u), where d_rcu and d_child are placed so that these two fields can share their memory needs. At the time d_free() is called (and d_rcu is really used), d_child is known to be empty and not touched by the dentry freeing. Lockless lookups only access d_name, d_parent, d_lock, d_op, d_flags (so the previous content of d_child is not needed if said dentry was unhashed but still accessed by a CPU because of RCU constraints) As dentry cache easily contains millions of entries, a size reduction is worth the extra complexity of the ugly C union. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Cc: Dipankar Sarma <dipankar@in.ibm.com> Cc: Maneesh Soni <maneesh@in.ibm.com> Cc: Miklos Szeredi <miklos@szeredi.hu> Cc: "Paul E. McKenney" <paulmck@us.ibm.com> Cc: Ian Kent <raven@themaw.net> Cc: Paul Jackson <pj@sgi.com> Cc: Al Viro <viro@ftp.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: Neil Brown <neilb@cse.unsw.edu.au> Cc: James Morris <jmorris@namei.org> Cc: Stephen Smalley <sds@epoch.ncsc.mil> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/usb/core/inode.c6
-rw-r--r--fs/autofs4/autofs_i.h2
-rw-r--r--fs/autofs4/expire.c12
-rw-r--r--fs/autofs4/inode.c4
-rw-r--r--fs/autofs4/root.c3
-rw-r--r--fs/coda/cache.c2
-rw-r--r--fs/dcache.c34
-rw-r--r--fs/libfs.c12
-rw-r--r--fs/ncpfs/dir.c2
-rw-r--r--fs/ncpfs/ncplib_kernel.h4
-rw-r--r--fs/smbfs/cache.c4
-rw-r--r--include/linux/dcache.h9
-rw-r--r--kernel/cpuset.c4
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--security/selinux/selinuxfs.c2
15 files changed, 54 insertions, 48 deletions
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index c44bbedec817..4ddc453023a2 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -186,7 +186,7 @@ static void update_bus(struct dentry *bus)
186 186
187 down(&bus->d_inode->i_sem); 187 down(&bus->d_inode->i_sem);
188 188
189 list_for_each_entry(dev, &bus->d_subdirs, d_child) 189 list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
190 if (dev->d_inode) 190 if (dev->d_inode)
191 update_dev(dev); 191 update_dev(dev);
192 192
@@ -203,7 +203,7 @@ static void update_sb(struct super_block *sb)
203 203
204 down(&root->d_inode->i_sem); 204 down(&root->d_inode->i_sem);
205 205
206 list_for_each_entry(bus, &root->d_subdirs, d_child) { 206 list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
207 if (bus->d_inode) { 207 if (bus->d_inode) {
208 switch (S_IFMT & bus->d_inode->i_mode) { 208 switch (S_IFMT & bus->d_inode->i_mode) {
209 case S_IFDIR: 209 case S_IFDIR:
@@ -319,7 +319,7 @@ static int usbfs_empty (struct dentry *dentry)
319 spin_lock(&dcache_lock); 319 spin_lock(&dcache_lock);
320 320
321 list_for_each(list, &dentry->d_subdirs) { 321 list_for_each(list, &dentry->d_subdirs) {
322 struct dentry *de = list_entry(list, struct dentry, d_child); 322 struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
323 if (usbfs_positive(de)) { 323 if (usbfs_positive(de)) {
324 spin_unlock(&dcache_lock); 324 spin_unlock(&dcache_lock);
325 return 0; 325 return 0;
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index fca83e28edcf..385bed09b0d8 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -209,7 +209,7 @@ static inline int simple_empty_nolock(struct dentry *dentry)
209 struct dentry *child; 209 struct dentry *child;
210 int ret = 0; 210 int ret = 0;
211 211
212 list_for_each_entry(child, &dentry->d_subdirs, d_child) 212 list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
213 if (simple_positive(child)) 213 if (simple_positive(child))
214 goto out; 214 goto out;
215 ret = 1; 215 ret = 1;
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index feb6ac427d05..dc39589df165 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -105,7 +105,7 @@ repeat:
105 next = this_parent->d_subdirs.next; 105 next = this_parent->d_subdirs.next;
106resume: 106resume:
107 while (next != &this_parent->d_subdirs) { 107 while (next != &this_parent->d_subdirs) {
108 struct dentry *dentry = list_entry(next, struct dentry, d_child); 108 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
109 109
110 /* Negative dentry - give up */ 110 /* Negative dentry - give up */
111 if (!simple_positive(dentry)) { 111 if (!simple_positive(dentry)) {
@@ -138,7 +138,7 @@ resume:
138 } 138 }
139 139
140 if (this_parent != top) { 140 if (this_parent != top) {
141 next = this_parent->d_child.next; 141 next = this_parent->d_u.d_child.next;
142 this_parent = this_parent->d_parent; 142 this_parent = this_parent->d_parent;
143 goto resume; 143 goto resume;
144 } 144 }
@@ -163,7 +163,7 @@ repeat:
163 next = this_parent->d_subdirs.next; 163 next = this_parent->d_subdirs.next;
164resume: 164resume:
165 while (next != &this_parent->d_subdirs) { 165 while (next != &this_parent->d_subdirs) {
166 struct dentry *dentry = list_entry(next, struct dentry, d_child); 166 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
167 167
168 /* Negative dentry - give up */ 168 /* Negative dentry - give up */
169 if (!simple_positive(dentry)) { 169 if (!simple_positive(dentry)) {
@@ -199,7 +199,7 @@ cont:
199 } 199 }
200 200
201 if (this_parent != parent) { 201 if (this_parent != parent) {
202 next = this_parent->d_child.next; 202 next = this_parent->d_u.d_child.next;
203 this_parent = this_parent->d_parent; 203 this_parent = this_parent->d_parent;
204 goto resume; 204 goto resume;
205 } 205 }
@@ -238,7 +238,7 @@ static struct dentry *autofs4_expire(struct super_block *sb,
238 /* On exit from the loop expire is set to a dgot dentry 238 /* On exit from the loop expire is set to a dgot dentry
239 * to expire or it's NULL */ 239 * to expire or it's NULL */
240 while ( next != &root->d_subdirs ) { 240 while ( next != &root->d_subdirs ) {
241 struct dentry *dentry = list_entry(next, struct dentry, d_child); 241 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
242 242
243 /* Negative dentry - give up */ 243 /* Negative dentry - give up */
244 if ( !simple_positive(dentry) ) { 244 if ( !simple_positive(dentry) ) {
@@ -302,7 +302,7 @@ next:
302 expired, (int)expired->d_name.len, expired->d_name.name); 302 expired, (int)expired->d_name.len, expired->d_name.name);
303 spin_lock(&dcache_lock); 303 spin_lock(&dcache_lock);
304 list_del(&expired->d_parent->d_subdirs); 304 list_del(&expired->d_parent->d_subdirs);
305 list_add(&expired->d_parent->d_subdirs, &expired->d_child); 305 list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
306 spin_unlock(&dcache_lock); 306 spin_unlock(&dcache_lock);
307 return expired; 307 return expired;
308 } 308 }
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 818b37be5153..2d3082854a29 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -91,7 +91,7 @@ repeat:
91 next = this_parent->d_subdirs.next; 91 next = this_parent->d_subdirs.next;
92resume: 92resume:
93 while (next != &this_parent->d_subdirs) { 93 while (next != &this_parent->d_subdirs) {
94 struct dentry *dentry = list_entry(next, struct dentry, d_child); 94 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
95 95
96 /* Negative dentry - don`t care */ 96 /* Negative dentry - don`t care */
97 if (!simple_positive(dentry)) { 97 if (!simple_positive(dentry)) {
@@ -117,7 +117,7 @@ resume:
117 if (this_parent != sbi->root) { 117 if (this_parent != sbi->root) {
118 struct dentry *dentry = this_parent; 118 struct dentry *dentry = this_parent;
119 119
120 next = this_parent->d_child.next; 120 next = this_parent->d_u.d_child.next;
121 this_parent = this_parent->d_parent; 121 this_parent = this_parent->d_parent;
122 spin_unlock(&dcache_lock); 122 spin_unlock(&dcache_lock);
123 DPRINTK("parent dentry %p %.*s", 123 DPRINTK("parent dentry %p %.*s",
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 2a771ec66956..2241405ffc41 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -143,7 +143,8 @@ static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t f
143 } 143 }
144 144
145 while(1) { 145 while(1) {
146 struct dentry *de = list_entry(list, struct dentry, d_child); 146 struct dentry *de = list_entry(list,
147 struct dentry, d_u.d_child);
147 148
148 if (!d_unhashed(de) && de->d_inode) { 149 if (!d_unhashed(de) && de->d_inode) {
149 spin_unlock(&dcache_lock); 150 spin_unlock(&dcache_lock);
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 80072fd9b7fa..c607d923350a 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -93,7 +93,7 @@ static void coda_flag_children(struct dentry *parent, int flag)
93 spin_lock(&dcache_lock); 93 spin_lock(&dcache_lock);
94 list_for_each(child, &parent->d_subdirs) 94 list_for_each(child, &parent->d_subdirs)
95 { 95 {
96 de = list_entry(child, struct dentry, d_child); 96 de = list_entry(child, struct dentry, d_u.d_child);
97 /* don't know what to do with negative dentries */ 97 /* don't know what to do with negative dentries */
98 if ( ! de->d_inode ) 98 if ( ! de->d_inode )
99 continue; 99 continue;
diff --git a/fs/dcache.c b/fs/dcache.c
index 17e439138681..1536f15c4d4c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -71,7 +71,7 @@ struct dentry_stat_t dentry_stat = {
71 71
72static void d_callback(struct rcu_head *head) 72static void d_callback(struct rcu_head *head)
73{ 73{
74 struct dentry * dentry = container_of(head, struct dentry, d_rcu); 74 struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu);
75 75
76 if (dname_external(dentry)) 76 if (dname_external(dentry))
77 kfree(dentry->d_name.name); 77 kfree(dentry->d_name.name);
@@ -86,7 +86,7 @@ static void d_free(struct dentry *dentry)
86{ 86{
87 if (dentry->d_op && dentry->d_op->d_release) 87 if (dentry->d_op && dentry->d_op->d_release)
88 dentry->d_op->d_release(dentry); 88 dentry->d_op->d_release(dentry);
89 call_rcu(&dentry->d_rcu, d_callback); 89 call_rcu(&dentry->d_u.d_rcu, d_callback);
90} 90}
91 91
92/* 92/*
@@ -193,7 +193,7 @@ kill_it: {
193 list_del(&dentry->d_lru); 193 list_del(&dentry->d_lru);
194 dentry_stat.nr_unused--; 194 dentry_stat.nr_unused--;
195 } 195 }
196 list_del(&dentry->d_child); 196 list_del(&dentry->d_u.d_child);
197 dentry_stat.nr_dentry--; /* For d_free, below */ 197 dentry_stat.nr_dentry--; /* For d_free, below */
198 /*drops the locks, at that point nobody can reach this dentry */ 198 /*drops the locks, at that point nobody can reach this dentry */
199 dentry_iput(dentry); 199 dentry_iput(dentry);
@@ -367,7 +367,7 @@ static inline void prune_one_dentry(struct dentry * dentry)
367 struct dentry * parent; 367 struct dentry * parent;
368 368
369 __d_drop(dentry); 369 __d_drop(dentry);
370 list_del(&dentry->d_child); 370 list_del(&dentry->d_u.d_child);
371 dentry_stat.nr_dentry--; /* For d_free, below */ 371 dentry_stat.nr_dentry--; /* For d_free, below */
372 dentry_iput(dentry); 372 dentry_iput(dentry);
373 parent = dentry->d_parent; 373 parent = dentry->d_parent;
@@ -518,7 +518,7 @@ repeat:
518resume: 518resume:
519 while (next != &this_parent->d_subdirs) { 519 while (next != &this_parent->d_subdirs) {
520 struct list_head *tmp = next; 520 struct list_head *tmp = next;
521 struct dentry *dentry = list_entry(tmp, struct dentry, d_child); 521 struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
522 next = tmp->next; 522 next = tmp->next;
523 /* Have we found a mount point ? */ 523 /* Have we found a mount point ? */
524 if (d_mountpoint(dentry)) 524 if (d_mountpoint(dentry))
@@ -532,7 +532,7 @@ resume:
532 * All done at this level ... ascend and resume the search. 532 * All done at this level ... ascend and resume the search.
533 */ 533 */
534 if (this_parent != parent) { 534 if (this_parent != parent) {
535 next = this_parent->d_child.next; 535 next = this_parent->d_u.d_child.next;
536 this_parent = this_parent->d_parent; 536 this_parent = this_parent->d_parent;
537 goto resume; 537 goto resume;
538 } 538 }
@@ -569,7 +569,7 @@ repeat:
569resume: 569resume:
570 while (next != &this_parent->d_subdirs) { 570 while (next != &this_parent->d_subdirs) {
571 struct list_head *tmp = next; 571 struct list_head *tmp = next;
572 struct dentry *dentry = list_entry(tmp, struct dentry, d_child); 572 struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
573 next = tmp->next; 573 next = tmp->next;
574 574
575 if (!list_empty(&dentry->d_lru)) { 575 if (!list_empty(&dentry->d_lru)) {
@@ -610,7 +610,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, found);
610 * All done at this level ... ascend and resume the search. 610 * All done at this level ... ascend and resume the search.
611 */ 611 */
612 if (this_parent != parent) { 612 if (this_parent != parent) {
613 next = this_parent->d_child.next; 613 next = this_parent->d_u.d_child.next;
614 this_parent = this_parent->d_parent; 614 this_parent = this_parent->d_parent;
615#ifdef DCACHE_DEBUG 615#ifdef DCACHE_DEBUG
616printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n", 616printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n",
@@ -753,12 +753,12 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
753 dentry->d_parent = dget(parent); 753 dentry->d_parent = dget(parent);
754 dentry->d_sb = parent->d_sb; 754 dentry->d_sb = parent->d_sb;
755 } else { 755 } else {
756 INIT_LIST_HEAD(&dentry->d_child); 756 INIT_LIST_HEAD(&dentry->d_u.d_child);
757 } 757 }
758 758
759 spin_lock(&dcache_lock); 759 spin_lock(&dcache_lock);
760 if (parent) 760 if (parent)
761 list_add(&dentry->d_child, &parent->d_subdirs); 761 list_add(&dentry->d_u.d_child, &parent->d_subdirs);
762 dentry_stat.nr_dentry++; 762 dentry_stat.nr_dentry++;
763 spin_unlock(&dcache_lock); 763 spin_unlock(&dcache_lock);
764 764
@@ -1310,8 +1310,8 @@ already_unhashed:
1310 /* Unhash the target: dput() will then get rid of it */ 1310 /* Unhash the target: dput() will then get rid of it */
1311 __d_drop(target); 1311 __d_drop(target);
1312 1312
1313 list_del(&dentry->d_child); 1313 list_del(&dentry->d_u.d_child);
1314 list_del(&target->d_child); 1314 list_del(&target->d_u.d_child);
1315 1315
1316 /* Switch the names.. */ 1316 /* Switch the names.. */
1317 switch_names(dentry, target); 1317 switch_names(dentry, target);
@@ -1322,15 +1322,15 @@ already_unhashed:
1322 if (IS_ROOT(dentry)) { 1322 if (IS_ROOT(dentry)) {
1323 dentry->d_parent = target->d_parent; 1323 dentry->d_parent = target->d_parent;
1324 target->d_parent = target; 1324 target->d_parent = target;
1325 INIT_LIST_HEAD(&target->d_child); 1325 INIT_LIST_HEAD(&target->d_u.d_child);
1326 } else { 1326 } else {
1327 do_switch(dentry->d_parent, target->d_parent); 1327 do_switch(dentry->d_parent, target->d_parent);
1328 1328
1329 /* And add them back to the (new) parent lists */ 1329 /* And add them back to the (new) parent lists */
1330 list_add(&target->d_child, &target->d_parent->d_subdirs); 1330 list_add(&target->d_u.d_child, &target->d_parent->d_subdirs);
1331 } 1331 }
1332 1332
1333 list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); 1333 list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
1334 spin_unlock(&target->d_lock); 1334 spin_unlock(&target->d_lock);
1335 spin_unlock(&dentry->d_lock); 1335 spin_unlock(&dentry->d_lock);
1336 write_sequnlock(&rename_lock); 1336 write_sequnlock(&rename_lock);
@@ -1568,7 +1568,7 @@ repeat:
1568resume: 1568resume:
1569 while (next != &this_parent->d_subdirs) { 1569 while (next != &this_parent->d_subdirs) {
1570 struct list_head *tmp = next; 1570 struct list_head *tmp = next;
1571 struct dentry *dentry = list_entry(tmp, struct dentry, d_child); 1571 struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
1572 next = tmp->next; 1572 next = tmp->next;
1573 if (d_unhashed(dentry)||!dentry->d_inode) 1573 if (d_unhashed(dentry)||!dentry->d_inode)
1574 continue; 1574 continue;
@@ -1579,7 +1579,7 @@ resume:
1579 atomic_dec(&dentry->d_count); 1579 atomic_dec(&dentry->d_count);
1580 } 1580 }
1581 if (this_parent != root) { 1581 if (this_parent != root) {
1582 next = this_parent->d_child.next; 1582 next = this_parent->d_u.d_child.next;
1583 atomic_dec(&this_parent->d_count); 1583 atomic_dec(&this_parent->d_count);
1584 this_parent = this_parent->d_parent; 1584 this_parent = this_parent->d_parent;
1585 goto resume; 1585 goto resume;
diff --git a/fs/libfs.c b/fs/libfs.c
index 58101dff2c66..9c50523382e7 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -93,16 +93,16 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
93 loff_t n = file->f_pos - 2; 93 loff_t n = file->f_pos - 2;
94 94
95 spin_lock(&dcache_lock); 95 spin_lock(&dcache_lock);
96 list_del(&cursor->d_child); 96 list_del(&cursor->d_u.d_child);
97 p = file->f_dentry->d_subdirs.next; 97 p = file->f_dentry->d_subdirs.next;
98 while (n && p != &file->f_dentry->d_subdirs) { 98 while (n && p != &file->f_dentry->d_subdirs) {
99 struct dentry *next; 99 struct dentry *next;
100 next = list_entry(p, struct dentry, d_child); 100 next = list_entry(p, struct dentry, d_u.d_child);
101 if (!d_unhashed(next) && next->d_inode) 101 if (!d_unhashed(next) && next->d_inode)
102 n--; 102 n--;
103 p = p->next; 103 p = p->next;
104 } 104 }
105 list_add_tail(&cursor->d_child, p); 105 list_add_tail(&cursor->d_u.d_child, p);
106 spin_unlock(&dcache_lock); 106 spin_unlock(&dcache_lock);
107 } 107 }
108 } 108 }
@@ -126,7 +126,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
126{ 126{
127 struct dentry *dentry = filp->f_dentry; 127 struct dentry *dentry = filp->f_dentry;
128 struct dentry *cursor = filp->private_data; 128 struct dentry *cursor = filp->private_data;
129 struct list_head *p, *q = &cursor->d_child; 129 struct list_head *p, *q = &cursor->d_u.d_child;
130 ino_t ino; 130 ino_t ino;
131 int i = filp->f_pos; 131 int i = filp->f_pos;
132 132
@@ -153,7 +153,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
153 } 153 }
154 for (p=q->next; p != &dentry->d_subdirs; p=p->next) { 154 for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
155 struct dentry *next; 155 struct dentry *next;
156 next = list_entry(p, struct dentry, d_child); 156 next = list_entry(p, struct dentry, d_u.d_child);
157 if (d_unhashed(next) || !next->d_inode) 157 if (d_unhashed(next) || !next->d_inode)
158 continue; 158 continue;
159 159
@@ -261,7 +261,7 @@ int simple_empty(struct dentry *dentry)
261 int ret = 0; 261 int ret = 0;
262 262
263 spin_lock(&dcache_lock); 263 spin_lock(&dcache_lock);
264 list_for_each_entry(child, &dentry->d_subdirs, d_child) 264 list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
265 if (simple_positive(child)) 265 if (simple_positive(child))
266 goto out; 266 goto out;
267 ret = 1; 267 ret = 1;
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index a9f7a8ab1d59..cfd76f431dc0 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -365,7 +365,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
365 spin_lock(&dcache_lock); 365 spin_lock(&dcache_lock);
366 next = parent->d_subdirs.next; 366 next = parent->d_subdirs.next;
367 while (next != &parent->d_subdirs) { 367 while (next != &parent->d_subdirs) {
368 dent = list_entry(next, struct dentry, d_child); 368 dent = list_entry(next, struct dentry, d_u.d_child);
369 if ((unsigned long)dent->d_fsdata == fpos) { 369 if ((unsigned long)dent->d_fsdata == fpos) {
370 if (dent->d_inode) 370 if (dent->d_inode)
371 dget_locked(dent); 371 dget_locked(dent);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 9e4dc30c2435..799e5c2bec55 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -196,7 +196,7 @@ ncp_renew_dentries(struct dentry *parent)
196 spin_lock(&dcache_lock); 196 spin_lock(&dcache_lock);
197 next = parent->d_subdirs.next; 197 next = parent->d_subdirs.next;
198 while (next != &parent->d_subdirs) { 198 while (next != &parent->d_subdirs) {
199 dentry = list_entry(next, struct dentry, d_child); 199 dentry = list_entry(next, struct dentry, d_u.d_child);
200 200
201 if (dentry->d_fsdata == NULL) 201 if (dentry->d_fsdata == NULL)
202 ncp_age_dentry(server, dentry); 202 ncp_age_dentry(server, dentry);
@@ -218,7 +218,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
218 spin_lock(&dcache_lock); 218 spin_lock(&dcache_lock);
219 next = parent->d_subdirs.next; 219 next = parent->d_subdirs.next;
220 while (next != &parent->d_subdirs) { 220 while (next != &parent->d_subdirs) {
221 dentry = list_entry(next, struct dentry, d_child); 221 dentry = list_entry(next, struct dentry, d_u.d_child);
222 dentry->d_fsdata = NULL; 222 dentry->d_fsdata = NULL;
223 ncp_age_dentry(server, dentry); 223 ncp_age_dentry(server, dentry);
224 next = next->next; 224 next = next->next;
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index f3e6b81288ab..74b86d9725a6 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -66,7 +66,7 @@ smb_invalidate_dircache_entries(struct dentry *parent)
66 spin_lock(&dcache_lock); 66 spin_lock(&dcache_lock);
67 next = parent->d_subdirs.next; 67 next = parent->d_subdirs.next;
68 while (next != &parent->d_subdirs) { 68 while (next != &parent->d_subdirs) {
69 dentry = list_entry(next, struct dentry, d_child); 69 dentry = list_entry(next, struct dentry, d_u.d_child);
70 dentry->d_fsdata = NULL; 70 dentry->d_fsdata = NULL;
71 smb_age_dentry(server, dentry); 71 smb_age_dentry(server, dentry);
72 next = next->next; 72 next = next->next;
@@ -100,7 +100,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
100 spin_lock(&dcache_lock); 100 spin_lock(&dcache_lock);
101 next = parent->d_subdirs.next; 101 next = parent->d_subdirs.next;
102 while (next != &parent->d_subdirs) { 102 while (next != &parent->d_subdirs) {
103 dent = list_entry(next, struct dentry, d_child); 103 dent = list_entry(next, struct dentry, d_u.d_child);
104 if ((unsigned long)dent->d_fsdata == fpos) { 104 if ((unsigned long)dent->d_fsdata == fpos) {
105 if (dent->d_inode) 105 if (dent->d_inode)
106 dget_locked(dent); 106 dget_locked(dent);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 46a2ba617595..a3ed5e059d47 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -95,14 +95,19 @@ struct dentry {
95 struct qstr d_name; 95 struct qstr d_name;
96 96
97 struct list_head d_lru; /* LRU list */ 97 struct list_head d_lru; /* LRU list */
98 struct list_head d_child; /* child of parent list */ 98 /*
99 * d_child and d_rcu can share memory
100 */
101 union {
102 struct list_head d_child; /* child of parent list */
103 struct rcu_head d_rcu;
104 } d_u;
99 struct list_head d_subdirs; /* our children */ 105 struct list_head d_subdirs; /* our children */
100 struct list_head d_alias; /* inode alias list */ 106 struct list_head d_alias; /* inode alias list */
101 unsigned long d_time; /* used by d_revalidate */ 107 unsigned long d_time; /* used by d_revalidate */
102 struct dentry_operations *d_op; 108 struct dentry_operations *d_op;
103 struct super_block *d_sb; /* The root of the dentry tree */ 109 struct super_block *d_sb; /* The root of the dentry tree */
104 void *d_fsdata; /* fs-specific data */ 110 void *d_fsdata; /* fs-specific data */
105 struct rcu_head d_rcu;
106 struct dcookie_struct *d_cookie; /* cookie, if any */ 111 struct dcookie_struct *d_cookie; /* cookie, if any */
107 int d_mounted; 112 int d_mounted;
108 unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ 113 unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index e04c2da9dadb..eab64e23bcae 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -331,7 +331,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry)
331 spin_lock(&dcache_lock); 331 spin_lock(&dcache_lock);
332 node = dentry->d_subdirs.next; 332 node = dentry->d_subdirs.next;
333 while (node != &dentry->d_subdirs) { 333 while (node != &dentry->d_subdirs) {
334 struct dentry *d = list_entry(node, struct dentry, d_child); 334 struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
335 list_del_init(node); 335 list_del_init(node);
336 if (d->d_inode) { 336 if (d->d_inode) {
337 d = dget_locked(d); 337 d = dget_locked(d);
@@ -343,7 +343,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry)
343 } 343 }
344 node = dentry->d_subdirs.next; 344 node = dentry->d_subdirs.next;
345 } 345 }
346 list_del_init(&dentry->d_child); 346 list_del_init(&dentry->d_u.d_child);
347 spin_unlock(&dcache_lock); 347 spin_unlock(&dcache_lock);
348 remove_dir(dentry); 348 remove_dir(dentry);
349} 349}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 24cc23af9b95..e14c1cae7460 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -495,7 +495,7 @@ rpc_depopulate(struct dentry *parent)
495repeat: 495repeat:
496 spin_lock(&dcache_lock); 496 spin_lock(&dcache_lock);
497 list_for_each_safe(pos, next, &parent->d_subdirs) { 497 list_for_each_safe(pos, next, &parent->d_subdirs) {
498 dentry = list_entry(pos, struct dentry, d_child); 498 dentry = list_entry(pos, struct dentry, d_u.d_child);
499 spin_lock(&dentry->d_lock); 499 spin_lock(&dentry->d_lock);
500 if (!d_unhashed(dentry)) { 500 if (!d_unhashed(dentry)) {
501 dget_locked(dentry); 501 dget_locked(dentry);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index e59da6398d44..b5fa02d17b1e 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -889,7 +889,7 @@ static void sel_remove_bools(struct dentry *de)
889 spin_lock(&dcache_lock); 889 spin_lock(&dcache_lock);
890 node = de->d_subdirs.next; 890 node = de->d_subdirs.next;
891 while (node != &de->d_subdirs) { 891 while (node != &de->d_subdirs) {
892 struct dentry *d = list_entry(node, struct dentry, d_child); 892 struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
893 list_del_init(node); 893 list_del_init(node);
894 894
895 if (d->d_inode) { 895 if (d->d_inode) {