diff options
author | Christoph Hellwig <hch@lst.de> | 2010-06-08 12:14:58 -0400 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-06-11 06:58:07 -0400 |
commit | d19de7edf59cdd586777b009e0e8fbe5412dd35f (patch) | |
tree | 8b6b56c705d7ed6fc22fe53b4d49b41372874afa | |
parent | cf37e972478ec58a8a54a6b4f951815f0ae28f78 (diff) |
writeback: fix writeback_inodes_wb from writeback_inodes_sb
When we call writeback_inodes_wb from writeback_inodes_sb we always have
s_umount held, which currently makes the whole operation a no-op.
But if we are called to write out inodes for a specific superblock we always
have s_umount held, so replace the incorrect logic checking for WB_SYNC_ALL
which only worked by coincidence with the proper check for an explicit
superblock argument.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
-rw-r--r-- | fs/fs-writeback.c | 61 |
1 files changed, 23 insertions, 38 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 2627f0dfcd9c..68ece4b18916 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -518,39 +518,19 @@ select_queue: | |||
518 | return ret; | 518 | return ret; |
519 | } | 519 | } |
520 | 520 | ||
521 | static void unpin_sb_for_writeback(struct super_block *sb) | ||
522 | { | ||
523 | up_read(&sb->s_umount); | ||
524 | put_super(sb); | ||
525 | } | ||
526 | |||
527 | enum sb_pin_state { | ||
528 | SB_PINNED, | ||
529 | SB_NOT_PINNED, | ||
530 | SB_PIN_FAILED | ||
531 | }; | ||
532 | |||
533 | /* | 521 | /* |
534 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned | 522 | * For background writeback the caller does not have the sb pinned |
535 | * before calling writeback. So make sure that we do pin it, so it doesn't | 523 | * before calling writeback. So make sure that we do pin it, so it doesn't |
536 | * go away while we are writing inodes from it. | 524 | * go away while we are writing inodes from it. |
537 | */ | 525 | */ |
538 | static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, | 526 | static bool pin_sb_for_writeback(struct super_block *sb) |
539 | struct super_block *sb) | ||
540 | { | 527 | { |
541 | /* | ||
542 | * Caller must already hold the ref for this | ||
543 | */ | ||
544 | if (wbc->sync_mode == WB_SYNC_ALL) { | ||
545 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
546 | return SB_NOT_PINNED; | ||
547 | } | ||
548 | spin_lock(&sb_lock); | 528 | spin_lock(&sb_lock); |
549 | sb->s_count++; | 529 | sb->s_count++; |
550 | if (down_read_trylock(&sb->s_umount)) { | 530 | if (down_read_trylock(&sb->s_umount)) { |
551 | if (sb->s_root) { | 531 | if (sb->s_root) { |
552 | spin_unlock(&sb_lock); | 532 | spin_unlock(&sb_lock); |
553 | return SB_PINNED; | 533 | return true; |
554 | } | 534 | } |
555 | /* | 535 | /* |
556 | * umounted, drop rwsem again and fall through to failure | 536 | * umounted, drop rwsem again and fall through to failure |
@@ -559,7 +539,7 @@ static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, | |||
559 | } | 539 | } |
560 | sb->s_count--; | 540 | sb->s_count--; |
561 | spin_unlock(&sb_lock); | 541 | spin_unlock(&sb_lock); |
562 | return SB_PIN_FAILED; | 542 | return false; |
563 | } | 543 | } |
564 | 544 | ||
565 | /* | 545 | /* |
@@ -638,24 +618,29 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
638 | struct inode *inode = list_entry(wb->b_io.prev, | 618 | struct inode *inode = list_entry(wb->b_io.prev, |
639 | struct inode, i_list); | 619 | struct inode, i_list); |
640 | struct super_block *sb = inode->i_sb; | 620 | struct super_block *sb = inode->i_sb; |
641 | enum sb_pin_state state; | ||
642 | 621 | ||
643 | if (wbc->sb && sb != wbc->sb) { | 622 | if (wbc->sb) { |
644 | /* super block given and doesn't | 623 | /* |
645 | match, skip this inode */ | 624 | * We are requested to write out inodes for a specific |
646 | redirty_tail(inode); | 625 | * superblock. This means we already have s_umount |
647 | continue; | 626 | * taken by the caller which also waits for us to |
648 | } | 627 | * complete the writeout. |
649 | state = pin_sb_for_writeback(wbc, sb); | 628 | */ |
629 | if (sb != wbc->sb) { | ||
630 | redirty_tail(inode); | ||
631 | continue; | ||
632 | } | ||
650 | 633 | ||
651 | if (state == SB_PIN_FAILED) { | 634 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
652 | requeue_io(inode); | 635 | |
653 | continue; | 636 | ret = writeback_sb_inodes(sb, wb, wbc); |
637 | } else { | ||
638 | if (!pin_sb_for_writeback(sb)) | ||
639 | continue; | ||
640 | ret = writeback_sb_inodes(sb, wb, wbc); | ||
641 | drop_super(sb); | ||
654 | } | 642 | } |
655 | ret = writeback_sb_inodes(sb, wb, wbc); | ||
656 | 643 | ||
657 | if (state == SB_PINNED) | ||
658 | unpin_sb_for_writeback(sb); | ||
659 | if (ret) | 644 | if (ret) |
660 | break; | 645 | break; |
661 | } | 646 | } |