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 | } |
