diff options
| -rw-r--r-- | fs/fs-writeback.c | 82 | ||||
| -rw-r--r-- | include/linux/writeback.h | 2 |
2 files changed, 46 insertions, 38 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 94a602e98bb5..8cc06d5432b5 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -554,29 +554,41 @@ static bool pin_sb_for_writeback(struct super_block *sb) | |||
| 554 | 554 | ||
| 555 | /* | 555 | /* |
| 556 | * Write a portion of b_io inodes which belong to @sb. | 556 | * Write a portion of b_io inodes which belong to @sb. |
| 557 | * If @wbc->sb != NULL, then find and write all such | 557 | * |
| 558 | * If @only_this_sb is true, then find and write all such | ||
| 558 | * inodes. Otherwise write only ones which go sequentially | 559 | * inodes. Otherwise write only ones which go sequentially |
| 559 | * in reverse order. | 560 | * in reverse order. |
| 561 | * | ||
| 560 | * Return 1, if the caller writeback routine should be | 562 | * Return 1, if the caller writeback routine should be |
| 561 | * interrupted. Otherwise return 0. | 563 | * interrupted. Otherwise return 0. |
| 562 | */ | 564 | */ |
| 563 | static int writeback_sb_inodes(struct super_block *sb, | 565 | static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, |
| 564 | struct bdi_writeback *wb, | 566 | struct writeback_control *wbc, bool only_this_sb) |
| 565 | struct writeback_control *wbc) | ||
| 566 | { | 567 | { |
| 567 | while (!list_empty(&wb->b_io)) { | 568 | while (!list_empty(&wb->b_io)) { |
| 568 | long pages_skipped; | 569 | long pages_skipped; |
| 569 | struct inode *inode = list_entry(wb->b_io.prev, | 570 | struct inode *inode = list_entry(wb->b_io.prev, |
| 570 | struct inode, i_list); | 571 | struct inode, i_list); |
| 571 | if (wbc->sb && sb != inode->i_sb) { | 572 | |
| 572 | /* super block given and doesn't | 573 | if (inode->i_sb != sb) { |
| 573 | match, skip this inode */ | 574 | if (only_this_sb) { |
| 574 | redirty_tail(inode); | 575 | /* |
| 575 | continue; | 576 | * We only want to write back data for this |
| 576 | } | 577 | * superblock, move all inodes not belonging |
| 577 | if (sb != inode->i_sb) | 578 | * to it back onto the dirty list. |
| 578 | /* finish with this superblock */ | 579 | */ |
| 580 | redirty_tail(inode); | ||
| 581 | continue; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * The inode belongs to a different superblock. | ||
| 586 | * Bounce back to the caller to unpin this and | ||
| 587 | * pin the next superblock. | ||
| 588 | */ | ||
| 579 | return 0; | 589 | return 0; |
| 590 | } | ||
| 591 | |||
| 580 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { | 592 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { |
| 581 | requeue_io(inode); | 593 | requeue_io(inode); |
| 582 | continue; | 594 | continue; |
| @@ -629,29 +641,12 @@ void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 629 | struct inode, i_list); | 641 | struct inode, i_list); |
| 630 | struct super_block *sb = inode->i_sb; | 642 | struct super_block *sb = inode->i_sb; |
| 631 | 643 | ||
| 632 | if (wbc->sb) { | 644 | if (!pin_sb_for_writeback(sb)) { |
| 633 | /* | 645 | requeue_io(inode); |
| 634 | * We are requested to write out inodes for a specific | 646 | continue; |
| 635 | * superblock. This means we already have s_umount | ||
| 636 | * taken by the caller which also waits for us to | ||
| 637 | * complete the writeout. | ||
| 638 | */ | ||
| 639 | if (sb != wbc->sb) { | ||
| 640 | redirty_tail(inode); | ||
| 641 | continue; | ||
| 642 | } | ||
| 643 | |||
| 644 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
| 645 | |||
| 646 | ret = writeback_sb_inodes(sb, wb, wbc); | ||
| 647 | } else { | ||
| 648 | if (!pin_sb_for_writeback(sb)) { | ||
| 649 | requeue_io(inode); | ||
| 650 | continue; | ||
| 651 | } | ||
| 652 | ret = writeback_sb_inodes(sb, wb, wbc); | ||
| 653 | drop_super(sb); | ||
| 654 | } | 647 | } |
| 648 | ret = writeback_sb_inodes(sb, wb, wbc, false); | ||
| 649 | drop_super(sb); | ||
| 655 | 650 | ||
| 656 | if (ret) | 651 | if (ret) |
| 657 | break; | 652 | break; |
| @@ -660,6 +655,19 @@ void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 660 | /* Leave any unwritten inodes on b_io */ | 655 | /* Leave any unwritten inodes on b_io */ |
| 661 | } | 656 | } |
| 662 | 657 | ||
| 658 | static void __writeback_inodes_sb(struct super_block *sb, | ||
| 659 | struct bdi_writeback *wb, struct writeback_control *wbc) | ||
| 660 | { | ||
| 661 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
| 662 | |||
| 663 | wbc->wb_start = jiffies; /* livelock avoidance */ | ||
| 664 | spin_lock(&inode_lock); | ||
| 665 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | ||
| 666 | queue_io(wb, wbc->older_than_this); | ||
| 667 | writeback_sb_inodes(sb, wb, wbc, true); | ||
| 668 | spin_unlock(&inode_lock); | ||
| 669 | } | ||
| 670 | |||
| 663 | /* | 671 | /* |
| 664 | * The maximum number of pages to writeout in a single bdi flush/kupdate | 672 | * The maximum number of pages to writeout in a single bdi flush/kupdate |
| 665 | * operation. We do this so we don't hold I_SYNC against an inode for | 673 | * operation. We do this so we don't hold I_SYNC against an inode for |
| @@ -698,7 +706,6 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
| 698 | struct wb_writeback_args *args) | 706 | struct wb_writeback_args *args) |
| 699 | { | 707 | { |
| 700 | struct writeback_control wbc = { | 708 | struct writeback_control wbc = { |
| 701 | .sb = args->sb, | ||
| 702 | .sync_mode = args->sync_mode, | 709 | .sync_mode = args->sync_mode, |
| 703 | .older_than_this = NULL, | 710 | .older_than_this = NULL, |
| 704 | .for_kupdate = args->for_kupdate, | 711 | .for_kupdate = args->for_kupdate, |
| @@ -736,7 +743,10 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
| 736 | wbc.more_io = 0; | 743 | wbc.more_io = 0; |
| 737 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; | 744 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; |
| 738 | wbc.pages_skipped = 0; | 745 | wbc.pages_skipped = 0; |
| 739 | writeback_inodes_wb(wb, &wbc); | 746 | if (args->sb) |
| 747 | __writeback_inodes_sb(args->sb, wb, &wbc); | ||
| 748 | else | ||
| 749 | writeback_inodes_wb(wb, &wbc); | ||
| 740 | args->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; | 750 | args->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; |
| 741 | wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; | 751 | wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; |
| 742 | 752 | ||
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index f6756f6a610c..c24eca71e80c 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
| @@ -27,8 +27,6 @@ enum writeback_sync_modes { | |||
| 27 | * in a manner such that unspecified fields are set to zero. | 27 | * in a manner such that unspecified fields are set to zero. |
| 28 | */ | 28 | */ |
| 29 | struct writeback_control { | 29 | struct writeback_control { |
| 30 | struct super_block *sb; /* if !NULL, only write inodes from | ||
| 31 | this super_block */ | ||
| 32 | enum writeback_sync_modes sync_mode; | 30 | enum writeback_sync_modes sync_mode; |
| 33 | unsigned long *older_than_this; /* If !NULL, only write back inodes | 31 | unsigned long *older_than_this; /* If !NULL, only write back inodes |
| 34 | older than this */ | 32 | older than this */ |
