From: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
To: Bob Liu <lliubbo@gmail.com>
Cc: linux-mm@kvack.org, kamezawa.hiroyu@jp.fujitsu.com,
mhocko@suse.cz, hannes@cmpxchg.org, bsingharora@gmail.com,
Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Subject: Re: [RFC][BUGFIX] memcg: fix memsw uncharged twice in do_swap_page
Date: Tue, 13 Dec 2011 17:10:16 +0900 [thread overview]
Message-ID: <20111213171016.2590def8.nishimura@mxp.nes.nec.co.jp> (raw)
In-Reply-To: <1323762925-14695-1-git-send-email-lliubbo@gmail.com>
Hi,
On Tue, 13 Dec 2011 15:55:25 +0800
Bob Liu <lliubbo@gmail.com> wrote:
> 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) {
IIRC, if the page(swapcache) has been already charged as memory, swap_cgroup_record(ent, 0)
returns 0, so swap_memcg is NULL.
Thanks,
Daisuke Nishimura.
> 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>
--
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 prev parent reply other threads:[~2011-12-13 8:17 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-13 7:55 Bob Liu
2011-12-13 8:02 ` KAMEZAWA Hiroyuki
2011-12-13 8:10 ` Daisuke Nishimura [this message]
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=20111213171016.2590def8.nishimura@mxp.nes.nec.co.jp \
--to=nishimura@mxp.nes.nec.co.jp \
--cc=bsingharora@gmail.com \
--cc=hannes@cmpxchg.org \
--cc=kamezawa.hiroyu@jp.fujitsu.com \
--cc=linux-mm@kvack.org \
--cc=lliubbo@gmail.com \
--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