writeback: split writeback_inodes_wb
Subsystems (2)
PATCH 2/2 writeback: split writeback_inodes_wb
The case where we have a superblock doesn't require a loop here as we scan over all inodes in writeback_sb_inodes. Split it out into a separate helper to make the code simpler. This also allows to get rid of the sb member in struct writeback_control, which was rather out of place there.
Also update the comments in writeback_sb_inodes that explain the handling of inodes from wrong superblocks.
Signed-off-by Christoph Hellwig <[email protected]>
fs/fs-writeback.c +46 -36
@@ -554,29 +554,41 @@ static bool pin_sb_for_writeback(struct/* * Write a portion of b_io inodes which belong to @sb. -* If @wbc->sb != NULL, then find and write all such +* +* If @only_this_sb is true, then find and write all such * inodes. Otherwise write only ones which go sequentially * in reverse order. +* * Return 1, if the caller writeback routine should be * interrupted. Otherwise return 0. */ -static int writeback_sb_inodes (struct super_block *sb, -struct bdi_writeback *wb, -struct writeback_control *wbc) +static int writeback_sb_inodes (struct super_block *sb,struct bdi_writeback *wb, +struct writeback_control *wbc,bool only_this_sb) {while (!list_empty (&wb->b_io)) {long pages_skipped;struct inode *inode =list_entry (wb->b_io.prev, struct inode, i_list); -if (wbc->sb && sb != inode->i_sb) { -/* super block given and doesn't -match, skip this inode */ -redirty_tail (inode); -continue ; - } -if (sb != inode->i_sb) -/* finish with this superblock */ + +if (inode->i_sb != sb) { +if (only_this_sb) { +/* +* We only want to write back data for this +* superblock, move all inodes not belonging +* to it back onto the dirty list. +*/ +redirty_tail (inode); +continue ; + } + +/* +* The inode belongs to a different superblock. +* Bounce back to the caller to unpin this and +* pin the next superblock. +*/ return 0 ; + } +if (inode->i_state & (I_NEW |I_WILL_FREE )) {requeue_io (inode);continue ;
@@ -629,29 +641,12 @@ void writeback_inodes_wb(struct bdi_writ struct inode, i_list);struct super_block *sb = inode->i_sb; -if (wbc->sb) { -/* -* We are requested to write out inodes for a specific -* superblock. This means we already have s_umount -* taken by the caller which also waits for us to -* complete the writeout. -*/ -if (sb != wbc->sb) { -redirty_tail (inode); -continue ; - } - -WARN_ON (!rwsem_is_locked (&sb->s_umount)); - - ret =writeback_sb_inodes (sb, wb, wbc); - }else { -if (!pin_sb_for_writeback (sb)) { -requeue_io (inode); -continue ; - } - ret =writeback_sb_inodes (sb, wb, wbc); -drop_super (sb); +if (!pin_sb_for_writeback (sb)) { +requeue_io (inode); +continue ; } + ret =writeback_sb_inodes (sb, wb, wbc, false); +drop_super (sb);if (ret)break ;
@@ -660,6 +655,19 @@ void writeback_inodes_wb(struct bdi_writ/* Leave any unwritten inodes on b_io */ } +static void __writeback_inodes_sb (struct super_block *sb, +struct bdi_writeback *wb,struct writeback_control *wbc) +{ +WARN_ON (!rwsem_is_locked (&sb->s_umount)); + + wbc->wb_start = jiffies;/* livelock avoidance */ +spin_lock (&inode_lock); +if (!wbc->for_kupdate ||list_empty (&wb->b_io)) +queue_io (wb, wbc->older_than_this); +writeback_sb_inodes (sb, wb, wbc, true); +spin_unlock (&inode_lock); +} +/* * The maximum number of pages to writeout in a single bdi flush/kupdate * 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_writ struct wb_writeback_args *args) {struct writeback_control wbc = { - .sb = args->sb, .sync_mode = args->sync_mode, .older_than_this =NULL , .for_kupdate = args->for_kupdate,
@@ -736,7 +743,10 @@ static long wb_writeback(struct bdi_writ wbc.more_io =0 ; wbc.nr_to_write =MAX_WRITEBACK_PAGES ; wbc.pages_skipped =0 ; -writeback_inodes_wb (wb, &wbc); +if (args->sb) +__writeback_inodes_sb (args->sb, wb, &wbc); +else +writeback_inodes_wb (wb, &wbc); args->nr_pages -=MAX_WRITEBACK_PAGES - wbc.nr_to_write; wrote +=MAX_WRITEBACK_PAGES - wbc.nr_to_write;
include/linux/writeback.h +0 -2
@@ -27,8 +27,6 @@ enum writeback_sync_modes {* in a manner such that unspecified fields are set to zero. */ struct writeback_control { -struct super_block *sb;/* if !NULL, only write inodes from -this super_block */ enum writeback_sync_modes sync_mode;unsigned long *older_than_this;/* If !NULL, only write back inodes older than this */