[PATCH] O(1) sb list traversing on syncs

This patch removes O(n^2) super block loops in sync_inodes(),
sync_filesystems() etc.  in favour of using __put_super_and_need_restart()
which I introduced earlier.  We faced a noticably long freezes on sb
syncing when there are thousands of super blocks in the system.

Signed-Off-By: Kirill Korotaev <dev@sw.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Kirill Korotaev 2005-06-23 00:09:54 -07:00 committed by Linus Torvalds
parent 4fea2838aa
commit 618f06362a
3 changed files with 96 additions and 111 deletions

View file

@ -485,32 +485,6 @@ static void set_sb_syncing(int val)
spin_unlock(&sb_lock);
}
/*
* Find a superblock with inodes that need to be synced
*/
static struct super_block *get_super_to_sync(void)
{
struct super_block *sb;
restart:
spin_lock(&sb_lock);
sb = sb_entry(super_blocks.prev);
for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
if (sb->s_syncing)
continue;
sb->s_syncing = 1;
sb->s_count++;
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (!sb->s_root) {
drop_super(sb);
goto restart;
}
return sb;
}
spin_unlock(&sb_lock);
return NULL;
}
/**
* sync_inodes - writes all inodes to disk
* @wait: wait for completion
@ -530,23 +504,39 @@ restart:
* outstanding dirty inodes, the writeback goes block-at-a-time within the
* filesystem's write_inode(). This is extremely slow.
*/
void sync_inodes(int wait)
static void __sync_inodes(int wait)
{
struct super_block *sb;
set_sb_syncing(0);
while ((sb = get_super_to_sync()) != NULL) {
sync_inodes_sb(sb, 0);
sync_blockdev(sb->s_bdev);
drop_super(sb);
spin_lock(&sb_lock);
restart:
list_for_each_entry(sb, &super_blocks, s_list) {
if (sb->s_syncing)
continue;
sb->s_syncing = 1;
sb->s_count++;
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (sb->s_root) {
sync_inodes_sb(sb, wait);
sync_blockdev(sb->s_bdev);
}
up_read(&sb->s_umount);
spin_lock(&sb_lock);
if (__put_super_and_need_restart(sb))
goto restart;
}
spin_unlock(&sb_lock);
}
void sync_inodes(int wait)
{
set_sb_syncing(0);
__sync_inodes(0);
if (wait) {
set_sb_syncing(0);
while ((sb = get_super_to_sync()) != NULL) {
sync_inodes_sb(sb, 1);
sync_blockdev(sb->s_bdev);
drop_super(sb);
}
__sync_inodes(1);
}
}