Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Al Viro 79893c17 df40c01a

+6 -11
+6 -11
fs/dcache.c
··· 536 536 */ 537 537 static void prune_dcache(int count) 538 538 { 539 - struct super_block *sb; 539 + struct super_block *sb, *n; 540 540 int w_count; 541 541 int unused = dentry_stat.nr_unused; 542 542 int prune_ratio; ··· 545 545 if (unused == 0 || count == 0) 546 546 return; 547 547 spin_lock(&dcache_lock); 548 - restart: 549 548 if (count >= unused) 550 549 prune_ratio = 1; 551 550 else 552 551 prune_ratio = unused / count; 553 552 spin_lock(&sb_lock); 554 - list_for_each_entry(sb, &super_blocks, s_list) { 553 + list_for_each_entry_safe(sb, n, &super_blocks, s_list) { 555 554 if (list_empty(&sb->s_instances)) 556 555 continue; 557 556 if (sb->s_nr_dentry_unused == 0) ··· 591 592 } 592 593 spin_lock(&sb_lock); 593 594 count -= pruned; 594 - /* 595 - * restart only when sb is no longer on the list and 596 - * we have more work to do. 597 - */ 598 - if (__put_super_and_need_restart(sb) && count > 0) { 599 - spin_unlock(&sb_lock); 600 - goto restart; 601 - } 595 + __put_super(sb); 596 + /* more work left to do? */ 597 + if (count <= 0) 598 + break; 602 599 } 603 600 spin_unlock(&sb_lock); 604 601 spin_unlock(&dcache_lock);