diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 48 |
1 files changed, 24 insertions, 24 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 75590572ff7a..9df8b861e18e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -301,6 +301,27 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
301 | return parent; | 301 | return parent; |
302 | } | 302 | } |
303 | 303 | ||
304 | /* | ||
305 | * Unhash a dentry without inserting an RCU walk barrier or checking that | ||
306 | * dentry->d_lock is locked. The caller must take care of that, if | ||
307 | * appropriate. | ||
308 | */ | ||
309 | static void __d_shrink(struct dentry *dentry) | ||
310 | { | ||
311 | if (!d_unhashed(dentry)) { | ||
312 | struct hlist_bl_head *b; | ||
313 | if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) | ||
314 | b = &dentry->d_sb->s_anon; | ||
315 | else | ||
316 | b = d_hash(dentry->d_parent, dentry->d_name.hash); | ||
317 | |||
318 | hlist_bl_lock(b); | ||
319 | __hlist_bl_del(&dentry->d_hash); | ||
320 | dentry->d_hash.pprev = NULL; | ||
321 | hlist_bl_unlock(b); | ||
322 | } | ||
323 | } | ||
324 | |||
304 | /** | 325 | /** |
305 | * d_drop - drop a dentry | 326 | * d_drop - drop a dentry |
306 | * @dentry: dentry to drop | 327 | * @dentry: dentry to drop |
@@ -319,17 +340,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
319 | void __d_drop(struct dentry *dentry) | 340 | void __d_drop(struct dentry *dentry) |
320 | { | 341 | { |
321 | if (!d_unhashed(dentry)) { | 342 | if (!d_unhashed(dentry)) { |
322 | struct hlist_bl_head *b; | 343 | __d_shrink(dentry); |
323 | if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) | ||
324 | b = &dentry->d_sb->s_anon; | ||
325 | else | ||
326 | b = d_hash(dentry->d_parent, dentry->d_name.hash); | ||
327 | |||
328 | hlist_bl_lock(b); | ||
329 | __hlist_bl_del(&dentry->d_hash); | ||
330 | dentry->d_hash.pprev = NULL; | ||
331 | hlist_bl_unlock(b); | ||
332 | |||
333 | dentry_rcuwalk_barrier(dentry); | 344 | dentry_rcuwalk_barrier(dentry); |
334 | } | 345 | } |
335 | } | 346 | } |
@@ -832,10 +843,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
832 | BUG_ON(!IS_ROOT(dentry)); | 843 | BUG_ON(!IS_ROOT(dentry)); |
833 | 844 | ||
834 | /* detach this root from the system */ | 845 | /* detach this root from the system */ |
835 | spin_lock(&dentry->d_lock); | ||
836 | dentry_lru_del(dentry); | 846 | dentry_lru_del(dentry); |
837 | __d_drop(dentry); | 847 | __d_shrink(dentry); |
838 | spin_unlock(&dentry->d_lock); | ||
839 | 848 | ||
840 | for (;;) { | 849 | for (;;) { |
841 | /* descend to the first leaf in the current subtree */ | 850 | /* descend to the first leaf in the current subtree */ |
@@ -844,16 +853,11 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
844 | 853 | ||
845 | /* this is a branch with children - detach all of them | 854 | /* this is a branch with children - detach all of them |
846 | * from the system in one go */ | 855 | * from the system in one go */ |
847 | spin_lock(&dentry->d_lock); | ||
848 | list_for_each_entry(loop, &dentry->d_subdirs, | 856 | list_for_each_entry(loop, &dentry->d_subdirs, |
849 | d_u.d_child) { | 857 | d_u.d_child) { |
850 | spin_lock_nested(&loop->d_lock, | ||
851 | DENTRY_D_LOCK_NESTED); | ||
852 | dentry_lru_del(loop); | 858 | dentry_lru_del(loop); |
853 | __d_drop(loop); | 859 | __d_shrink(loop); |
854 | spin_unlock(&loop->d_lock); | ||
855 | } | 860 | } |
856 | spin_unlock(&dentry->d_lock); | ||
857 | 861 | ||
858 | /* move to the first child */ | 862 | /* move to the first child */ |
859 | dentry = list_entry(dentry->d_subdirs.next, | 863 | dentry = list_entry(dentry->d_subdirs.next, |
@@ -885,10 +889,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
885 | list_del(&dentry->d_u.d_child); | 889 | list_del(&dentry->d_u.d_child); |
886 | } else { | 890 | } else { |
887 | parent = dentry->d_parent; | 891 | parent = dentry->d_parent; |
888 | spin_lock(&parent->d_lock); | ||
889 | parent->d_count--; | 892 | parent->d_count--; |
890 | list_del(&dentry->d_u.d_child); | 893 | list_del(&dentry->d_u.d_child); |
891 | spin_unlock(&parent->d_lock); | ||
892 | } | 894 | } |
893 | 895 | ||
894 | inode = dentry->d_inode; | 896 | inode = dentry->d_inode; |
@@ -935,9 +937,7 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
935 | 937 | ||
936 | dentry = sb->s_root; | 938 | dentry = sb->s_root; |
937 | sb->s_root = NULL; | 939 | sb->s_root = NULL; |
938 | spin_lock(&dentry->d_lock); | ||
939 | dentry->d_count--; | 940 | dentry->d_count--; |
940 | spin_unlock(&dentry->d_lock); | ||
941 | shrink_dcache_for_umount_subtree(dentry); | 941 | shrink_dcache_for_umount_subtree(dentry); |
942 | 942 | ||
943 | while (!hlist_bl_empty(&sb->s_anon)) { | 943 | while (!hlist_bl_empty(&sb->s_anon)) { |