diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:33 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:21 -0500 |
commit | da5029563a0a026c64821b09e8e7b4fd81d3fe1b (patch) | |
tree | 5d5618e0cb382390073377b1be7d0aa76879ac54 | |
parent | b7ab39f631f505edc2bbdb86620d5493f995c9da (diff) |
fs: dcache scale d_unhashed
Protect d_unhashed(dentry) condition with d_lock. This means keeping
DCACHE_UNHASHED bit in synch with hash manipulations.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 3 | ||||
-rw-r--r-- | fs/autofs4/autofs_i.h | 13 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 21 | ||||
-rw-r--r-- | fs/ceph/dir.c | 5 | ||||
-rw-r--r-- | fs/configfs/configfs_internal.h | 2 | ||||
-rw-r--r-- | fs/dcache.c | 74 | ||||
-rw-r--r-- | fs/libfs.c | 29 | ||||
-rw-r--r-- | fs/ocfs2/dcache.c | 5 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 1 |
10 files changed, 102 insertions, 54 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 29a406a77547..5aef1a7f5e4b 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -166,6 +166,9 @@ static void spufs_prune_dir(struct dentry *dir) | |||
166 | __d_drop(dentry); | 166 | __d_drop(dentry); |
167 | spin_unlock(&dentry->d_lock); | 167 | spin_unlock(&dentry->d_lock); |
168 | simple_unlink(dir->d_inode, dentry); | 168 | simple_unlink(dir->d_inode, dentry); |
169 | /* XXX: what is dcache_lock protecting here? Other | ||
170 | * filesystems (IB, configfs) release dcache_lock | ||
171 | * before unlink */ | ||
169 | spin_unlock(&dcache_lock); | 172 | spin_unlock(&dcache_lock); |
170 | dput(dentry); | 173 | dput(dentry); |
171 | } else { | 174 | } else { |
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index b690aa35df9a..e3ab4437ea96 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
@@ -347,10 +347,13 @@ static int usbfs_empty (struct dentry *dentry) | |||
347 | 347 | ||
348 | list_for_each(list, &dentry->d_subdirs) { | 348 | list_for_each(list, &dentry->d_subdirs) { |
349 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); | 349 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); |
350 | spin_lock(&de->d_lock); | ||
350 | if (usbfs_positive(de)) { | 351 | if (usbfs_positive(de)) { |
352 | spin_unlock(&de->d_lock); | ||
351 | spin_unlock(&dcache_lock); | 353 | spin_unlock(&dcache_lock); |
352 | return 0; | 354 | return 0; |
353 | } | 355 | } |
356 | spin_unlock(&de->d_lock); | ||
354 | } | 357 | } |
355 | 358 | ||
356 | spin_unlock(&dcache_lock); | 359 | spin_unlock(&dcache_lock); |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 3d283abf67d7..3912dcf047e5 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -254,19 +254,6 @@ static inline int simple_positive(struct dentry *dentry) | |||
254 | return dentry->d_inode && !d_unhashed(dentry); | 254 | return dentry->d_inode && !d_unhashed(dentry); |
255 | } | 255 | } |
256 | 256 | ||
257 | static inline int __simple_empty(struct dentry *dentry) | ||
258 | { | ||
259 | struct dentry *child; | ||
260 | int ret = 0; | ||
261 | |||
262 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | ||
263 | if (simple_positive(child)) | ||
264 | goto out; | ||
265 | ret = 1; | ||
266 | out: | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static inline void autofs4_add_expiring(struct dentry *dentry) | 257 | static inline void autofs4_add_expiring(struct dentry *dentry) |
271 | { | 258 | { |
272 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 259 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 413b5642e6cf..ee6402050f13 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -160,14 +160,18 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
160 | 160 | ||
161 | spin_lock(&dcache_lock); | 161 | spin_lock(&dcache_lock); |
162 | for (p = top; p; p = next_dentry(p, top)) { | 162 | for (p = top; p; p = next_dentry(p, top)) { |
163 | spin_lock(&p->d_lock); | ||
163 | /* Negative dentry - give up */ | 164 | /* Negative dentry - give up */ |
164 | if (!simple_positive(p)) | 165 | if (!simple_positive(p)) { |
166 | spin_unlock(&p->d_lock); | ||
165 | continue; | 167 | continue; |
168 | } | ||
166 | 169 | ||
167 | DPRINTK("dentry %p %.*s", | 170 | DPRINTK("dentry %p %.*s", |
168 | p, (int) p->d_name.len, p->d_name.name); | 171 | p, (int) p->d_name.len, p->d_name.name); |
169 | 172 | ||
170 | p = dget(p); | 173 | p = dget_dlock(p); |
174 | spin_unlock(&p->d_lock); | ||
171 | spin_unlock(&dcache_lock); | 175 | spin_unlock(&dcache_lock); |
172 | 176 | ||
173 | /* | 177 | /* |
@@ -228,14 +232,18 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
228 | 232 | ||
229 | spin_lock(&dcache_lock); | 233 | spin_lock(&dcache_lock); |
230 | for (p = parent; p; p = next_dentry(p, parent)) { | 234 | for (p = parent; p; p = next_dentry(p, parent)) { |
235 | spin_lock(&p->d_lock); | ||
231 | /* Negative dentry - give up */ | 236 | /* Negative dentry - give up */ |
232 | if (!simple_positive(p)) | 237 | if (!simple_positive(p)) { |
238 | spin_unlock(&p->d_lock); | ||
233 | continue; | 239 | continue; |
240 | } | ||
234 | 241 | ||
235 | DPRINTK("dentry %p %.*s", | 242 | DPRINTK("dentry %p %.*s", |
236 | p, (int) p->d_name.len, p->d_name.name); | 243 | p, (int) p->d_name.len, p->d_name.name); |
237 | 244 | ||
238 | p = dget(p); | 245 | p = dget_dlock(p); |
246 | spin_unlock(&p->d_lock); | ||
239 | spin_unlock(&dcache_lock); | 247 | spin_unlock(&dcache_lock); |
240 | 248 | ||
241 | if (d_mountpoint(p)) { | 249 | if (d_mountpoint(p)) { |
@@ -324,12 +332,15 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
324 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | 332 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); |
325 | 333 | ||
326 | /* Negative dentry - give up */ | 334 | /* Negative dentry - give up */ |
335 | spin_lock(&dentry->d_lock); | ||
327 | if (!simple_positive(dentry)) { | 336 | if (!simple_positive(dentry)) { |
328 | next = next->next; | 337 | next = next->next; |
338 | spin_unlock(&dentry->d_lock); | ||
329 | continue; | 339 | continue; |
330 | } | 340 | } |
331 | 341 | ||
332 | dentry = dget(dentry); | 342 | dentry = dget_dlock(dentry); |
343 | spin_unlock(&dentry->d_lock); | ||
333 | spin_unlock(&dcache_lock); | 344 | spin_unlock(&dcache_lock); |
334 | 345 | ||
335 | spin_lock(&sbi->fs_lock); | 346 | spin_lock(&sbi->fs_lock); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 3ecf915a4550..571f270dca0f 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -136,6 +136,7 @@ more: | |||
136 | fi->at_end = 1; | 136 | fi->at_end = 1; |
137 | goto out_unlock; | 137 | goto out_unlock; |
138 | } | 138 | } |
139 | spin_lock(&dentry->d_lock); | ||
139 | if (!d_unhashed(dentry) && dentry->d_inode && | 140 | if (!d_unhashed(dentry) && dentry->d_inode && |
140 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && | 141 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && |
141 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && | 142 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && |
@@ -145,13 +146,13 @@ more: | |||
145 | dentry->d_name.len, dentry->d_name.name, di->offset, | 146 | dentry->d_name.len, dentry->d_name.name, di->offset, |
146 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", | 147 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", |
147 | !dentry->d_inode ? " null" : ""); | 148 | !dentry->d_inode ? " null" : ""); |
149 | spin_unlock(&dentry->d_lock); | ||
148 | p = p->prev; | 150 | p = p->prev; |
149 | dentry = list_entry(p, struct dentry, d_u.d_child); | 151 | dentry = list_entry(p, struct dentry, d_u.d_child); |
150 | di = ceph_dentry(dentry); | 152 | di = ceph_dentry(dentry); |
151 | } | 153 | } |
152 | 154 | ||
153 | spin_lock(&dentry->d_lock); | 155 | dget_dlock(dentry); |
154 | dentry->d_count++; | ||
155 | spin_unlock(&dentry->d_lock); | 156 | spin_unlock(&dentry->d_lock); |
156 | spin_unlock(&dcache_lock); | 157 | spin_unlock(&dcache_lock); |
157 | 158 | ||
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index da6061a6df40..e58b4c30e216 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
@@ -121,6 +121,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry | |||
121 | struct config_item * item = NULL; | 121 | struct config_item * item = NULL; |
122 | 122 | ||
123 | spin_lock(&dcache_lock); | 123 | spin_lock(&dcache_lock); |
124 | spin_lock(&dentry->d_lock); | ||
124 | if (!d_unhashed(dentry)) { | 125 | if (!d_unhashed(dentry)) { |
125 | struct configfs_dirent * sd = dentry->d_fsdata; | 126 | struct configfs_dirent * sd = dentry->d_fsdata; |
126 | if (sd->s_type & CONFIGFS_ITEM_LINK) { | 127 | if (sd->s_type & CONFIGFS_ITEM_LINK) { |
@@ -129,6 +130,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry | |||
129 | } else | 130 | } else |
130 | item = config_item_get(sd->s_element); | 131 | item = config_item_get(sd->s_element); |
131 | } | 132 | } |
133 | spin_unlock(&dentry->d_lock); | ||
132 | spin_unlock(&dcache_lock); | 134 | spin_unlock(&dcache_lock); |
133 | 135 | ||
134 | return item; | 136 | return item; |
diff --git a/fs/dcache.c b/fs/dcache.c index 81e91502b294..ee127f9ab274 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -46,6 +46,7 @@ | |||
46 | * - d_name | 46 | * - d_name |
47 | * - d_lru | 47 | * - d_lru |
48 | * - d_count | 48 | * - d_count |
49 | * - d_unhashed() | ||
49 | * | 50 | * |
50 | * Ordering: | 51 | * Ordering: |
51 | * dcache_lock | 52 | * dcache_lock |
@@ -53,6 +54,13 @@ | |||
53 | * dcache_lru_lock | 54 | * dcache_lru_lock |
54 | * dcache_hash_lock | 55 | * dcache_hash_lock |
55 | * | 56 | * |
57 | * If there is an ancestor relationship: | ||
58 | * dentry->d_parent->...->d_parent->d_lock | ||
59 | * ... | ||
60 | * dentry->d_parent->d_lock | ||
61 | * dentry->d_lock | ||
62 | * | ||
63 | * If no ancestor relationship: | ||
56 | * if (dentry1 < dentry2) | 64 | * if (dentry1 < dentry2) |
57 | * dentry1->d_lock | 65 | * dentry1->d_lock |
58 | * dentry2->d_lock | 66 | * dentry2->d_lock |
@@ -379,7 +387,9 @@ int d_invalidate(struct dentry * dentry) | |||
379 | * If it's already been dropped, return OK. | 387 | * If it's already been dropped, return OK. |
380 | */ | 388 | */ |
381 | spin_lock(&dcache_lock); | 389 | spin_lock(&dcache_lock); |
390 | spin_lock(&dentry->d_lock); | ||
382 | if (d_unhashed(dentry)) { | 391 | if (d_unhashed(dentry)) { |
392 | spin_unlock(&dentry->d_lock); | ||
383 | spin_unlock(&dcache_lock); | 393 | spin_unlock(&dcache_lock); |
384 | return 0; | 394 | return 0; |
385 | } | 395 | } |
@@ -388,9 +398,11 @@ int d_invalidate(struct dentry * dentry) | |||
388 | * to get rid of unused child entries. | 398 | * to get rid of unused child entries. |
389 | */ | 399 | */ |
390 | if (!list_empty(&dentry->d_subdirs)) { | 400 | if (!list_empty(&dentry->d_subdirs)) { |
401 | spin_unlock(&dentry->d_lock); | ||
391 | spin_unlock(&dcache_lock); | 402 | spin_unlock(&dcache_lock); |
392 | shrink_dcache_parent(dentry); | 403 | shrink_dcache_parent(dentry); |
393 | spin_lock(&dcache_lock); | 404 | spin_lock(&dcache_lock); |
405 | spin_lock(&dentry->d_lock); | ||
394 | } | 406 | } |
395 | 407 | ||
396 | /* | 408 | /* |
@@ -403,7 +415,6 @@ int d_invalidate(struct dentry * dentry) | |||
403 | * we might still populate it if it was a | 415 | * we might still populate it if it was a |
404 | * working directory or similar). | 416 | * working directory or similar). |
405 | */ | 417 | */ |
406 | spin_lock(&dentry->d_lock); | ||
407 | if (dentry->d_count > 1) { | 418 | if (dentry->d_count > 1) { |
408 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { | 419 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { |
409 | spin_unlock(&dentry->d_lock); | 420 | spin_unlock(&dentry->d_lock); |
@@ -490,35 +501,44 @@ EXPORT_SYMBOL(dget_parent); | |||
490 | * any other hashed alias over that one unless @want_discon is set, | 501 | * any other hashed alias over that one unless @want_discon is set, |
491 | * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. | 502 | * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. |
492 | */ | 503 | */ |
493 | 504 | static struct dentry *__d_find_alias(struct inode *inode, int want_discon) | |
494 | static struct dentry * __d_find_alias(struct inode *inode, int want_discon) | ||
495 | { | 505 | { |
496 | struct list_head *head, *next, *tmp; | 506 | struct dentry *alias, *discon_alias; |
497 | struct dentry *alias, *discon_alias=NULL; | ||
498 | 507 | ||
499 | head = &inode->i_dentry; | 508 | again: |
500 | next = inode->i_dentry.next; | 509 | discon_alias = NULL; |
501 | while (next != head) { | 510 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
502 | tmp = next; | 511 | spin_lock(&alias->d_lock); |
503 | next = tmp->next; | ||
504 | prefetch(next); | ||
505 | alias = list_entry(tmp, struct dentry, d_alias); | ||
506 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { | 512 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { |
507 | if (IS_ROOT(alias) && | 513 | if (IS_ROOT(alias) && |
508 | (alias->d_flags & DCACHE_DISCONNECTED)) | 514 | (alias->d_flags & DCACHE_DISCONNECTED)) { |
509 | discon_alias = alias; | 515 | discon_alias = alias; |
510 | else if (!want_discon) { | 516 | } else if (!want_discon) { |
511 | __dget_locked(alias); | 517 | __dget_locked_dlock(alias); |
518 | spin_unlock(&alias->d_lock); | ||
519 | return alias; | ||
520 | } | ||
521 | } | ||
522 | spin_unlock(&alias->d_lock); | ||
523 | } | ||
524 | if (discon_alias) { | ||
525 | alias = discon_alias; | ||
526 | spin_lock(&alias->d_lock); | ||
527 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { | ||
528 | if (IS_ROOT(alias) && | ||
529 | (alias->d_flags & DCACHE_DISCONNECTED)) { | ||
530 | __dget_locked_dlock(alias); | ||
531 | spin_unlock(&alias->d_lock); | ||
512 | return alias; | 532 | return alias; |
513 | } | 533 | } |
514 | } | 534 | } |
535 | spin_unlock(&alias->d_lock); | ||
536 | goto again; | ||
515 | } | 537 | } |
516 | if (discon_alias) | 538 | return NULL; |
517 | __dget_locked(discon_alias); | ||
518 | return discon_alias; | ||
519 | } | 539 | } |
520 | 540 | ||
521 | struct dentry * d_find_alias(struct inode *inode) | 541 | struct dentry *d_find_alias(struct inode *inode) |
522 | { | 542 | { |
523 | struct dentry *de = NULL; | 543 | struct dentry *de = NULL; |
524 | 544 | ||
@@ -801,8 +821,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
801 | spin_lock(&dcache_lock); | 821 | spin_lock(&dcache_lock); |
802 | spin_lock(&dentry->d_lock); | 822 | spin_lock(&dentry->d_lock); |
803 | dentry_lru_del(dentry); | 823 | dentry_lru_del(dentry); |
804 | spin_unlock(&dentry->d_lock); | ||
805 | __d_drop(dentry); | 824 | __d_drop(dentry); |
825 | spin_unlock(&dentry->d_lock); | ||
806 | spin_unlock(&dcache_lock); | 826 | spin_unlock(&dcache_lock); |
807 | 827 | ||
808 | for (;;) { | 828 | for (;;) { |
@@ -817,8 +837,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
817 | d_u.d_child) { | 837 | d_u.d_child) { |
818 | spin_lock(&loop->d_lock); | 838 | spin_lock(&loop->d_lock); |
819 | dentry_lru_del(loop); | 839 | dentry_lru_del(loop); |
820 | spin_unlock(&loop->d_lock); | ||
821 | __d_drop(loop); | 840 | __d_drop(loop); |
841 | spin_unlock(&loop->d_lock); | ||
822 | cond_resched_lock(&dcache_lock); | 842 | cond_resched_lock(&dcache_lock); |
823 | } | 843 | } |
824 | spin_unlock(&dcache_lock); | 844 | spin_unlock(&dcache_lock); |
@@ -1863,7 +1883,10 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) | |||
1863 | /* | 1883 | /* |
1864 | * XXXX: do we really need to take target->d_lock? | 1884 | * XXXX: do we really need to take target->d_lock? |
1865 | */ | 1885 | */ |
1866 | if (target < dentry) { | 1886 | if (d_ancestor(dentry, target)) { |
1887 | spin_lock(&dentry->d_lock); | ||
1888 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1889 | } else if (d_ancestor(target, dentry) || target < dentry) { | ||
1867 | spin_lock(&target->d_lock); | 1890 | spin_lock(&target->d_lock); |
1868 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | 1891 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1869 | } else { | 1892 | } else { |
@@ -2542,13 +2565,16 @@ resume: | |||
2542 | struct list_head *tmp = next; | 2565 | struct list_head *tmp = next; |
2543 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 2566 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
2544 | next = tmp->next; | 2567 | next = tmp->next; |
2545 | if (d_unhashed(dentry)||!dentry->d_inode) | 2568 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
2569 | if (d_unhashed(dentry) || !dentry->d_inode) { | ||
2570 | spin_unlock(&dentry->d_lock); | ||
2546 | continue; | 2571 | continue; |
2572 | } | ||
2547 | if (!list_empty(&dentry->d_subdirs)) { | 2573 | if (!list_empty(&dentry->d_subdirs)) { |
2574 | spin_unlock(&dentry->d_lock); | ||
2548 | this_parent = dentry; | 2575 | this_parent = dentry; |
2549 | goto repeat; | 2576 | goto repeat; |
2550 | } | 2577 | } |
2551 | spin_lock(&dentry->d_lock); | ||
2552 | dentry->d_count--; | 2578 | dentry->d_count--; |
2553 | spin_unlock(&dentry->d_lock); | 2579 | spin_unlock(&dentry->d_lock); |
2554 | } | 2580 | } |
diff --git a/fs/libfs.c b/fs/libfs.c index b9d25d83e228..433e7139c23a 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -16,6 +16,11 @@ | |||
16 | 16 | ||
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | ||
19 | static inline int simple_positive(struct dentry *dentry) | ||
20 | { | ||
21 | return dentry->d_inode && !d_unhashed(dentry); | ||
22 | } | ||
23 | |||
19 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, | 24 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, |
20 | struct kstat *stat) | 25 | struct kstat *stat) |
21 | { | 26 | { |
@@ -100,8 +105,10 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
100 | while (n && p != &file->f_path.dentry->d_subdirs) { | 105 | while (n && p != &file->f_path.dentry->d_subdirs) { |
101 | struct dentry *next; | 106 | struct dentry *next; |
102 | next = list_entry(p, struct dentry, d_u.d_child); | 107 | next = list_entry(p, struct dentry, d_u.d_child); |
103 | if (!d_unhashed(next) && next->d_inode) | 108 | spin_lock(&next->d_lock); |
109 | if (simple_positive(next)) | ||
104 | n--; | 110 | n--; |
111 | spin_unlock(&next->d_lock); | ||
105 | p = p->next; | 112 | p = p->next; |
106 | } | 113 | } |
107 | list_add_tail(&cursor->d_u.d_child, p); | 114 | list_add_tail(&cursor->d_u.d_child, p); |
@@ -155,9 +162,13 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
155 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { | 162 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { |
156 | struct dentry *next; | 163 | struct dentry *next; |
157 | next = list_entry(p, struct dentry, d_u.d_child); | 164 | next = list_entry(p, struct dentry, d_u.d_child); |
158 | if (d_unhashed(next) || !next->d_inode) | 165 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
166 | if (!simple_positive(next)) { | ||
167 | spin_unlock(&next->d_lock); | ||
159 | continue; | 168 | continue; |
169 | } | ||
160 | 170 | ||
171 | spin_unlock(&next->d_lock); | ||
161 | spin_unlock(&dcache_lock); | 172 | spin_unlock(&dcache_lock); |
162 | if (filldir(dirent, next->d_name.name, | 173 | if (filldir(dirent, next->d_name.name, |
163 | next->d_name.len, filp->f_pos, | 174 | next->d_name.len, filp->f_pos, |
@@ -259,20 +270,20 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den | |||
259 | return 0; | 270 | return 0; |
260 | } | 271 | } |
261 | 272 | ||
262 | static inline int simple_positive(struct dentry *dentry) | ||
263 | { | ||
264 | return dentry->d_inode && !d_unhashed(dentry); | ||
265 | } | ||
266 | |||
267 | int simple_empty(struct dentry *dentry) | 273 | int simple_empty(struct dentry *dentry) |
268 | { | 274 | { |
269 | struct dentry *child; | 275 | struct dentry *child; |
270 | int ret = 0; | 276 | int ret = 0; |
271 | 277 | ||
272 | spin_lock(&dcache_lock); | 278 | spin_lock(&dcache_lock); |
273 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | 279 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { |
274 | if (simple_positive(child)) | 280 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
281 | if (simple_positive(child)) { | ||
282 | spin_unlock(&child->d_lock); | ||
275 | goto out; | 283 | goto out; |
284 | } | ||
285 | spin_unlock(&child->d_lock); | ||
286 | } | ||
276 | ret = 1; | 287 | ret = 1; |
277 | out: | 288 | out: |
278 | spin_unlock(&dcache_lock); | 289 | spin_unlock(&dcache_lock); |
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 895532ac4d98..35e5f5a9ef59 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c | |||
@@ -174,13 +174,16 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, | |||
174 | list_for_each(p, &inode->i_dentry) { | 174 | list_for_each(p, &inode->i_dentry) { |
175 | dentry = list_entry(p, struct dentry, d_alias); | 175 | dentry = list_entry(p, struct dentry, d_alias); |
176 | 176 | ||
177 | spin_lock(&dentry->d_lock); | ||
177 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { | 178 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { |
178 | mlog(0, "dentry found: %.*s\n", | 179 | mlog(0, "dentry found: %.*s\n", |
179 | dentry->d_name.len, dentry->d_name.name); | 180 | dentry->d_name.len, dentry->d_name.name); |
180 | 181 | ||
181 | dget_locked(dentry); | 182 | dget_locked_dlock(dentry); |
183 | spin_unlock(&dentry->d_lock); | ||
182 | break; | 184 | break; |
183 | } | 185 | } |
186 | spin_unlock(&dentry->d_lock); | ||
184 | 187 | ||
185 | dentry = NULL; | 188 | dentry = NULL; |
186 | } | 189 | } |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 1d0bf8fa1922..d1e05b047715 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <net/sock.h> | 15 | #include <net/sock.h> |
16 | #include "common.h" | 16 | #include "common.h" |
17 | #include "../../fs/internal.h" | ||
17 | 18 | ||
18 | /** | 19 | /** |
19 | * tomoyo_encode: Convert binary string to ascii string. | 20 | * tomoyo_encode: Convert binary string to ascii string. |