diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-22 20:27:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-21 18:31:16 -0400 |
commit | 79893c17b45dec0d3c25bc22d28d9f319b14f573 (patch) | |
tree | 560c5f13193cbb1e2d2bf5dc1fd6f25d49c01165 | |
parent | df40c01a9249873e4ad0625ae5d9fb831962b75c (diff) |
fix prune_dcache()/umount() race
... and get rid of the last __put_super_and_need_restart() caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 17 |
1 files changed, 6 insertions, 11 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 5afc4994bb2..d96047b4a63 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -536,7 +536,7 @@ restart: */ static void prune_dcache(int count) { - struct super_block *sb; + struct super_block *sb, *n; int w_count; int unused = dentry_stat.nr_unused; int prune_ratio; @@ -545,13 +545,12 @@ static void prune_dcache(int count) if (unused == 0 || count == 0) return; spin_lock(&dcache_lock); -restart: if (count >= unused) prune_ratio = 1; else prune_ratio = unused / count; spin_lock(&sb_lock); - list_for_each_entry(sb, &super_blocks, s_list) { + list_for_each_entry_safe(sb, n, &super_blocks, s_list) { if (list_empty(&sb->s_instances)) continue; if (sb->s_nr_dentry_unused == 0) @@ -592,14 +591,10 @@ restart: } spin_lock(&sb_lock); count -= pruned; - /* - * restart only when sb is no longer on the list and - * we have more work to do. - */ - if (__put_super_and_need_restart(sb) && count > 0) { - spin_unlock(&sb_lock); - goto restart; - } + __put_super(sb); + /* more work left to do? */ + if (count <= 0) + break; } spin_unlock(&sb_lock); spin_unlock(&dcache_lock); |