aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fs-writeback.c82
-rw-r--r--include/linux/writeback.h2
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 */
563static int writeback_sb_inodes(struct super_block *sb, 565static 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
658static 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 */
29struct writeback_control { 29struct 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 */