From: Bob Liu <lliubbo@gmail.com>
To: linux-mm@kvack.org
Cc: kamezawa.hiroyu@jp.fujitsu.com, mhocko@suse.cz,
hannes@cmpxchg.org, bsingharora@gmail.com,
Bob Liu <lliubbo@gmail.com>
Subject: [RFC][BUGFIX] memcg: fix memsw uncharged twice in do_swap_page
Date: Tue, 13 Dec 2011 15:55:25 +0800 [thread overview]
Message-ID: <1323762925-14695-1-git-send-email-lliubbo@gmail.com> (raw)
As the document memcg_test.txt said:
In do_swap_page(), following events occur when pte is unchanged.
(1) the page (SwapCache) is looked up.
(2) lock_page()
(3) try_charge_swapin()
(4) reuse_swap_page() (may call delete_swap_cache())
(5) commit_charge_swapin()
(6) swap_free().
And below situation:
(C) The page has been charged before (2) and reuse_swap_page() doesn't
call delete_from_swap_cache().
In this case, __mem_cgroup_commit_charge_swapin() may uncharge memsw twice.
See below two uncharge place:
__mem_cgroup_commit_charge_swapin {
=> __mem_cgroup_commit_charge_lrucare
=> __mem_cgroup_commit_charge() <== PageCgroupUsed
=> __mem_cgroup_cancel_charge()
<== 1.uncharge memsw here
if (do_swap_account && PageSwapCache(page)) {
if (swap_memcg) {
if (!mem_cgroup_is_root(swap_memcg))
res_counter_uncharge(&swap_memcg->memsw,
PAGE_SIZE);
<== 2.uncharged memsw again here
mem_cgroup_swap_statistics(swap_memcg, false);
mem_cgroup_put(swap_memcg);
}
}
}
This patch added a return val for __mem_cgroup_commit_charge(), if canceled then
don't uncharge memsw again.
But i didn't find a definite testcase can confirm this situaction current.
Maybe i missed something. Welcome point.
Signed-off-by: Bob Liu <lliubbo@gmail.com>
---
mm/memcontrol.c | 56 +++++++++++++++++++++++++++++++-----------------------
1 files changed, 32 insertions(+), 24 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index bc396e7..6ead0cd 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2416,7 +2416,10 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
return memcg;
}
-static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
+/*
+ * return -1 if cancel charge else return 0
+ */
+static int __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
struct page *page,
unsigned int nr_pages,
struct page_cgroup *pc,
@@ -2426,7 +2429,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
if (unlikely(PageCgroupUsed(pc))) {
unlock_page_cgroup(pc);
__mem_cgroup_cancel_charge(memcg, nr_pages);
- return;
+ return -1;
}
/*
* we don't need page_cgroup_lock about tail pages, becase they are not
@@ -2463,6 +2466,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
* if they exceeds softlimit.
*/
memcg_check_events(memcg, page);
+ return 0;
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -2690,20 +2694,21 @@ static void
__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
enum charge_type ctype);
-static void
+static int
__mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg,
enum charge_type ctype)
{
struct page_cgroup *pc = lookup_page_cgroup(page);
+ int ret;
/*
* In some case, SwapCache, FUSE(splice_buf->radixtree), the page
* is already on LRU. It means the page may on some other page_cgroup's
* LRU. Take care of it.
*/
mem_cgroup_lru_del_before_commit(page);
- __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
+ ret = __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
mem_cgroup_lru_add_after_commit(page);
- return;
+ return ret;
}
int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
@@ -2792,13 +2797,14 @@ static void
__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
enum charge_type ctype)
{
+ int ret;
if (mem_cgroup_disabled())
return;
if (!memcg)
return;
cgroup_exclude_rmdir(&memcg->css);
- __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
+ ret = __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
/*
* Now swap is on-memory. This means this page may be
* counted both as mem and swap....double count.
@@ -2807,25 +2813,27 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
* may call delete_from_swap_cache() before reach here.
*/
if (do_swap_account && PageSwapCache(page)) {
- swp_entry_t ent = {.val = page_private(page)};
- struct mem_cgroup *swap_memcg;
- unsigned short id;
+ if(!ret) {
+ swp_entry_t ent = {.val = page_private(page)};
+ struct mem_cgroup *swap_memcg;
+ unsigned short id;
- id = swap_cgroup_record(ent, 0);
- rcu_read_lock();
- swap_memcg = mem_cgroup_lookup(id);
- if (swap_memcg) {
- /*
- * This recorded memcg can be obsolete one. So, avoid
- * calling css_tryget
- */
- if (!mem_cgroup_is_root(swap_memcg))
- res_counter_uncharge(&swap_memcg->memsw,
- PAGE_SIZE);
- mem_cgroup_swap_statistics(swap_memcg, false);
- mem_cgroup_put(swap_memcg);
+ id = swap_cgroup_record(ent, 0);
+ rcu_read_lock();
+ swap_memcg = mem_cgroup_lookup(id);
+ if (swap_memcg) {
+ /*
+ * This recorded memcg can be obsolete one. So, avoid
+ * calling css_tryget
+ */
+ if (!mem_cgroup_is_root(swap_memcg))
+ res_counter_uncharge(&swap_memcg->memsw,
+ PAGE_SIZE);
+ mem_cgroup_swap_statistics(swap_memcg, false);
+ mem_cgroup_put(swap_memcg);
+ }
+ rcu_read_unlock();
}
- rcu_read_unlock();
}
/*
* At swapin, we may charge account against cgroup which has no tasks.
--
1.7.0.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next reply other threads:[~2011-12-13 7:48 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-13 7:55 Bob Liu [this message]
2011-12-13 8:02 ` KAMEZAWA Hiroyuki
2011-12-13 8:10 ` Daisuke Nishimura
2011-12-14 2:08 ` Bob Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1323762925-14695-1-git-send-email-lliubbo@gmail.com \
--to=lliubbo@gmail.com \
--cc=bsingharora@gmail.com \
--cc=hannes@cmpxchg.org \
--cc=kamezawa.hiroyu@jp.fujitsu.com \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox