diff options
author | Kirill Korotaev <dev@sw.ru> | 2005-06-23 03:09:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-23 12:45:27 -0400 |
commit | 618f06362ae3f60f95d7b0e666de25ee6ae35679 (patch) | |
tree | 4415b4e590913e16535704168ea74c6af5a93c48 /fs/fs-writeback.c | |
parent | 4fea2838aa00b9e59efde974dcdb455608192811 (diff) |
[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>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 64 |
1 files changed, 27 insertions, 37 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 8e050fa58218..e94ab398b717 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -485,32 +485,6 @@ static void set_sb_syncing(int val) | |||
485 | spin_unlock(&sb_lock); | 485 | spin_unlock(&sb_lock); |
486 | } | 486 | } |
487 | 487 | ||
488 | /* | ||
489 | * Find a superblock with inodes that need to be synced | ||
490 | */ | ||
491 | static struct super_block *get_super_to_sync(void) | ||
492 | { | ||
493 | struct super_block *sb; | ||
494 | restart: | ||
495 | spin_lock(&sb_lock); | ||
496 | sb = sb_entry(super_blocks.prev); | ||
497 | for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { | ||
498 | if (sb->s_syncing) | ||
499 | continue; | ||
500 | sb->s_syncing = 1; | ||
501 | sb->s_count++; | ||
502 | spin_unlock(&sb_lock); | ||
503 | down_read(&sb->s_umount); | ||
504 | if (!sb->s_root) { | ||
505 | drop_super(sb); | ||
506 | goto restart; | ||
507 | } | ||
508 | return sb; | ||
509 | } | ||
510 | spin_unlock(&sb_lock); | ||
511 | return NULL; | ||
512 | } | ||
513 | |||
514 | /** | 488 | /** |
515 | * sync_inodes - writes all inodes to disk | 489 | * sync_inodes - writes all inodes to disk |
516 | * @wait: wait for completion | 490 | * @wait: wait for completion |
@@ -530,23 +504,39 @@ restart: | |||
530 | * outstanding dirty inodes, the writeback goes block-at-a-time within the | 504 | * outstanding dirty inodes, the writeback goes block-at-a-time within the |
531 | * filesystem's write_inode(). This is extremely slow. | 505 | * filesystem's write_inode(). This is extremely slow. |
532 | */ | 506 | */ |
533 | void sync_inodes(int wait) | 507 | static void __sync_inodes(int wait) |
534 | { | 508 | { |
535 | struct super_block *sb; | 509 | struct super_block *sb; |
536 | 510 | ||
537 | set_sb_syncing(0); | 511 | spin_lock(&sb_lock); |
538 | while ((sb = get_super_to_sync()) != NULL) { | 512 | restart: |
539 | sync_inodes_sb(sb, 0); | 513 | list_for_each_entry(sb, &super_blocks, s_list) { |
540 | sync_blockdev(sb->s_bdev); | 514 | if (sb->s_syncing) |
541 | drop_super(sb); | 515 | continue; |
516 | sb->s_syncing = 1; | ||
517 | sb->s_count++; | ||
518 | spin_unlock(&sb_lock); | ||
519 | down_read(&sb->s_umount); | ||
520 | if (sb->s_root) { | ||
521 | sync_inodes_sb(sb, wait); | ||
522 | sync_blockdev(sb->s_bdev); | ||
523 | } | ||
524 | up_read(&sb->s_umount); | ||
525 | spin_lock(&sb_lock); | ||
526 | if (__put_super_and_need_restart(sb)) | ||
527 | goto restart; | ||
542 | } | 528 | } |
529 | spin_unlock(&sb_lock); | ||
530 | } | ||
531 | |||
532 | void sync_inodes(int wait) | ||
533 | { | ||
534 | set_sb_syncing(0); | ||
535 | __sync_inodes(0); | ||
536 | |||
543 | if (wait) { | 537 | if (wait) { |
544 | set_sb_syncing(0); | 538 | set_sb_syncing(0); |
545 | while ((sb = get_super_to_sync()) != NULL) { | 539 | __sync_inodes(1); |
546 | sync_inodes_sb(sb, 1); | ||
547 | sync_blockdev(sb->s_bdev); | ||
548 | drop_super(sb); | ||
549 | } | ||
550 | } | 540 | } |
551 | } | 541 | } |
552 | 542 | ||