aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page-writeback.c
diff options
context:
space:
mode:
authorSha Zhengju <handai.szj@taobao.com>2013-09-12 18:13:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 18:38:02 -0400
commit3ea67d06e4679a16f69f66f43a8d6ee4778985fc (patch)
tree0ec35a312de85ce91bf0bf6e4c5b88440f3d0f1d /mm/page-writeback.c
parent658b72c5a7a033f0dde61b15dff86bf423ce425e (diff)
memcg: add per cgroup writeback pages accounting
Add memcg routines to count writeback pages, later dirty pages will also be accounted. After Kame's commit 89c06bd52fb9 ("memcg: use new logic for page stat accounting"), we can use 'struct page' flag to test page state instead of per page_cgroup flag. But memcg has a feature to move a page from a cgroup to another one and may have race between "move" and "page stat accounting". So in order to avoid the race we have designed a new lock: mem_cgroup_begin_update_page_stat() modify page information -->(a) mem_cgroup_update_page_stat() -->(b) mem_cgroup_end_update_page_stat() It requires both (a) and (b)(writeback pages accounting) to be pretected in mem_cgroup_{begin/end}_update_page_stat(). It's full no-op for !CONFIG_MEMCG, almost no-op if memcg is disabled (but compiled in), rcu read lock in the most cases (no task is moving), and spin_lock_irqsave on top in the slow path. There're two writeback interfaces to modify: test_{clear/set}_page_writeback(). And the lock order is: --> memcg->move_lock --> mapping->tree_lock Signed-off-by: Sha Zhengju <handai.szj@taobao.com> Acked-by: Michal Hocko <mhocko@suse.cz> Reviewed-by: Greg Thelen <gthelen@google.com> Cc: Fengguang Wu <fengguang.wu@intel.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page-writeback.c')
-rw-r--r--mm/page-writeback.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 6c7b0187be8e..f5236f804aa6 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2143,11 +2143,17 @@ EXPORT_SYMBOL(account_page_dirtied);
2143 2143
2144/* 2144/*
2145 * Helper function for set_page_writeback family. 2145 * Helper function for set_page_writeback family.
2146 *
2147 * The caller must hold mem_cgroup_begin/end_update_page_stat() lock
2148 * while calling this function.
2149 * See test_set_page_writeback for example.
2150 *
2146 * NOTE: Unlike account_page_dirtied this does not rely on being atomic 2151 * NOTE: Unlike account_page_dirtied this does not rely on being atomic
2147 * wrt interrupts. 2152 * wrt interrupts.
2148 */ 2153 */
2149void account_page_writeback(struct page *page) 2154void account_page_writeback(struct page *page)
2150{ 2155{
2156 mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
2151 inc_zone_page_state(page, NR_WRITEBACK); 2157 inc_zone_page_state(page, NR_WRITEBACK);
2152} 2158}
2153EXPORT_SYMBOL(account_page_writeback); 2159EXPORT_SYMBOL(account_page_writeback);
@@ -2364,7 +2370,10 @@ int test_clear_page_writeback(struct page *page)
2364{ 2370{
2365 struct address_space *mapping = page_mapping(page); 2371 struct address_space *mapping = page_mapping(page);
2366 int ret; 2372 int ret;
2373 bool locked;
2374 unsigned long memcg_flags;
2367 2375
2376 mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
2368 if (mapping) { 2377 if (mapping) {
2369 struct backing_dev_info *bdi = mapping->backing_dev_info; 2378 struct backing_dev_info *bdi = mapping->backing_dev_info;
2370 unsigned long flags; 2379 unsigned long flags;
@@ -2385,9 +2394,11 @@ int test_clear_page_writeback(struct page *page)
2385 ret = TestClearPageWriteback(page); 2394 ret = TestClearPageWriteback(page);
2386 } 2395 }
2387 if (ret) { 2396 if (ret) {
2397 mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
2388 dec_zone_page_state(page, NR_WRITEBACK); 2398 dec_zone_page_state(page, NR_WRITEBACK);
2389 inc_zone_page_state(page, NR_WRITTEN); 2399 inc_zone_page_state(page, NR_WRITTEN);
2390 } 2400 }
2401 mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
2391 return ret; 2402 return ret;
2392} 2403}
2393 2404
@@ -2395,7 +2406,10 @@ int test_set_page_writeback(struct page *page)
2395{ 2406{
2396 struct address_space *mapping = page_mapping(page); 2407 struct address_space *mapping = page_mapping(page);
2397 int ret; 2408 int ret;
2409 bool locked;
2410 unsigned long memcg_flags;
2398 2411
2412 mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
2399 if (mapping) { 2413 if (mapping) {
2400 struct backing_dev_info *bdi = mapping->backing_dev_info; 2414 struct backing_dev_info *bdi = mapping->backing_dev_info;
2401 unsigned long flags; 2415 unsigned long flags;
@@ -2422,6 +2436,7 @@ int test_set_page_writeback(struct page *page)
2422 } 2436 }
2423 if (!ret) 2437 if (!ret)
2424 account_page_writeback(page); 2438 account_page_writeback(page);
2439 mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
2425 return ret; 2440 return ret;
2426 2441
2427} 2442}