[PATCH 40/45] writeback: make write_cache_pages() cgroup writeback aware

From: Tejun Heo
Date: Tue Jan 06 2015 - 16:27:55 EST


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 from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/