The inodes to be synced will be dirty throttled regardless of the dirty threshold. This stops sync() livelock by some fast dirtier. CC: Jan Kara Signed-off-by: Wu Fengguang --- fs/fs-writeback.c | 4 ++++ include/linux/backing-dev.h | 1 + mm/page-writeback.c | 13 +++++++++++++ 3 files changed, 18 insertions(+) --- linux.orig/mm/page-writeback.c 2009-10-07 10:47:09.000000000 +0800 +++ linux/mm/page-writeback.c 2009-10-07 14:32:43.000000000 +0800 @@ -478,6 +478,18 @@ static void balance_dirty_pages(struct a global_dirty_thresh(&background_thresh, &dirty_thresh); /* + * If sync() is in progress, curb the to-be-synced inodes regardless + * of dirty limits, so that a fast dirtier won't livelock the sync. + */ + if (unlikely(bdi->sync_time && + S_ISREG(mapping->host->i_mode) && + time_after_eq(bdi->sync_time, + mapping->host->dirtied_when))) { + write_chunk *= 2; + goto throttle; + } + + /* * Throttle it only when the background writeback cannot * catch-up. This skips the ramp up phase of bdi limits. */ @@ -510,6 +522,7 @@ static void balance_dirty_pages(struct a if (!dirty_exceeded) goto out; +throttle: if (!bdi->dirty_exceeded) bdi->dirty_exceeded = 1; --- linux.orig/fs/fs-writeback.c 2009-10-07 10:47:09.000000000 +0800 +++ linux/fs/fs-writeback.c 2009-10-07 14:31:47.000000000 +0800 @@ -796,6 +796,7 @@ static long wb_writeback(struct bdi_writ if (wbc.for_sync) { wbc.older_than_this = &oldest_jif; oldest_jif = jiffies; + wbc.bdi->sync_time = oldest_jif | 1; } if (wbc.for_kupdate || wbc.for_background) { wbc.older_than_this = &oldest_jif; @@ -873,6 +874,9 @@ static long wb_writeback(struct bdi_writ spin_unlock(&inode_lock); } + if (args->for_sync) + wb->bdi->sync_time = 0; + if (args->for_background) while (bdi_writeback_wakeup(wb->bdi)) ; /* unthrottle all tasks */ --- linux.orig/include/linux/backing-dev.h 2009-10-07 10:47:09.000000000 +0800 +++ linux/include/linux/backing-dev.h 2009-10-07 14:31:53.000000000 +0800 @@ -89,6 +89,7 @@ struct backing_dev_info { * to prevent livelocking the sync works */ unsigned int sync_works; + unsigned long sync_time; struct list_head work_list; -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/