write_cache_pages() is used to implement generic do_writepages(). Up until now, the function targeted all dirty pages; however, for cgroup writeback, it needs to be more restrained. As writeback for each wb cgroup (bdi_writeback) will be executed separately, do_writepages() needs to write out only the pages dirtied against the wb being serviced. This patch introduces wbc_skip_page() which is used by write_cache_pages() to determine whether a page should be skipped because it is dirtied against a different wb. wbc->iwbl_mismatch is also added to keep track of whether pages were skipped, which will be used later. Filesystems which don't use write_cache_pages() for its address_space_operation->writepages() should update its ->writepages() to use wbc_skip_page() directly to support cgroup writeback. Signed-off-by: Tejun Heo <tj@xxxxxxxxxx> Cc: Jens Axboe <axboe@xxxxxxxxx> Cc: Jan Kara <jack@xxxxxxx> --- include/linux/backing-dev.h | 27 +++++++++++++++++++++++++++ include/linux/writeback.h | 1 + mm/page-writeback.c | 3 +++ 3 files changed, 31 insertions(+) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 5d919bc..173d218 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -648,6 +648,27 @@ wbc_blkcg_css(struct writeback_control *wbc) return wbc->iwbl ? iwbl_to_wb(wbc->iwbl)->blkcg_css : NULL; } +/** + * wbc_skip_page - determine whether to skip a page during writeback + * @wbc: writeback_control in effect + * @page: page being considered + * + * Determine whether @page should be written back during a writeback + * controlled by @wbc. This function also accounts the number of skipped + * pages in @wbc and should only be called once per page. + */ +static inline bool wbc_skip_page(struct writeback_control *wbc, + struct page *page) +{ + struct cgroup_subsys_state *blkcg_css = wbc_blkcg_css(wbc); + + if (blkcg_css && blkcg_css != page_blkcg_dirty(page)) { + wbc->iwbl_mismatch = 1; + return true; + } + return false; +} + #else /* CONFIG_CGROUP_WRITEBACK */ static inline bool mapping_cgwb_enabled(struct address_space *mapping) @@ -760,6 +781,12 @@ wbc_blkcg_css(struct writeback_control *wbc) return NULL; } +static inline bool wbc_skip_page(struct writeback_control *wbc, + struct page *page) +{ + return false; +} + #endif /* CONFIG_CGROUP_WRITEBACK */ static inline int mapping_read_congested(struct address_space *mapping, diff --git a/include/linux/writeback.h b/include/linux/writeback.h index dad1953..a225a33 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -85,6 +85,7 @@ struct writeback_control { unsigned range_cyclic:1; /* range_start is cyclic */ unsigned for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ #ifdef CONFIG_CGROUP_WRITEBACK + unsigned iwbl_mismatch:1; /* pages skipped due to iwbl mismatch */ struct inode_wb_link *iwbl; /* iwbl this writeback is for */ #endif }; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index dd15bb3..0edf749 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1977,6 +1977,9 @@ retry: done_index = page->index; + if (wbc_skip_page(wbc, page)) + continue; + lock_page(page); /* -- 2.1.0 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>