memcg: clean up move charge
This patch cleans up move charge code by: - define functions to handle pte for each types, and make is_target_pte_for_mc() cleaner. - instead of checking the MOVE_CHARGE_TYPE_ANON bit, define a function that checks the bit. Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Balbir Singh <balbir@in.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
3c11ecf448
commit
90254a6583
@ -266,6 +266,12 @@ static struct move_charge_struct {
|
|||||||
.waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq),
|
.waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool move_anon(void)
|
||||||
|
{
|
||||||
|
return test_bit(MOVE_CHARGE_TYPE_ANON,
|
||||||
|
&mc.to->move_charge_at_immigrate);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft
|
* Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft
|
||||||
* limit reclaim to prevent infinite loops, if they ever occur.
|
* limit reclaim to prevent infinite loops, if they ever occur.
|
||||||
@ -4162,6 +4168,50 @@ enum mc_target_type {
|
|||||||
MC_TARGET_SWAP,
|
MC_TARGET_SWAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct page *mc_handle_present_pte(struct vm_area_struct *vma,
|
||||||
|
unsigned long addr, pte_t ptent)
|
||||||
|
{
|
||||||
|
struct page *page = vm_normal_page(vma, addr, ptent);
|
||||||
|
|
||||||
|
if (!page || !page_mapped(page))
|
||||||
|
return NULL;
|
||||||
|
if (PageAnon(page)) {
|
||||||
|
/* we don't move shared anon */
|
||||||
|
if (!move_anon() || page_mapcount(page) > 2)
|
||||||
|
return NULL;
|
||||||
|
} else
|
||||||
|
/*
|
||||||
|
* TODO: We don't move charges of file(including shmem/tmpfs)
|
||||||
|
* pages for now.
|
||||||
|
*/
|
||||||
|
return NULL;
|
||||||
|
if (!get_page_unless_zero(page))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct page *mc_handle_swap_pte(struct vm_area_struct *vma,
|
||||||
|
unsigned long addr, pte_t ptent, swp_entry_t *entry)
|
||||||
|
{
|
||||||
|
int usage_count;
|
||||||
|
struct page *page = NULL;
|
||||||
|
swp_entry_t ent = pte_to_swp_entry(ptent);
|
||||||
|
|
||||||
|
if (!move_anon() || non_swap_entry(ent))
|
||||||
|
return NULL;
|
||||||
|
usage_count = mem_cgroup_count_swap_user(ent, &page);
|
||||||
|
if (usage_count > 1) { /* we don't move shared anon */
|
||||||
|
if (page)
|
||||||
|
put_page(page);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (do_swap_account)
|
||||||
|
entry->val = ent.val;
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
static int is_target_pte_for_mc(struct vm_area_struct *vma,
|
static int is_target_pte_for_mc(struct vm_area_struct *vma,
|
||||||
unsigned long addr, pte_t ptent, union mc_target *target)
|
unsigned long addr, pte_t ptent, union mc_target *target)
|
||||||
{
|
{
|
||||||
@ -4169,43 +4219,15 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
|
|||||||
struct page_cgroup *pc;
|
struct page_cgroup *pc;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
swp_entry_t ent = { .val = 0 };
|
swp_entry_t ent = { .val = 0 };
|
||||||
int usage_count = 0;
|
|
||||||
bool move_anon = test_bit(MOVE_CHARGE_TYPE_ANON,
|
|
||||||
&mc.to->move_charge_at_immigrate);
|
|
||||||
|
|
||||||
if (!pte_present(ptent)) {
|
if (pte_present(ptent))
|
||||||
|
page = mc_handle_present_pte(vma, addr, ptent);
|
||||||
|
else if (is_swap_pte(ptent))
|
||||||
|
page = mc_handle_swap_pte(vma, addr, ptent, &ent);
|
||||||
/* TODO: handle swap of shmes/tmpfs */
|
/* TODO: handle swap of shmes/tmpfs */
|
||||||
if (pte_none(ptent) || pte_file(ptent))
|
|
||||||
|
if (!page && !ent.val)
|
||||||
return 0;
|
return 0;
|
||||||
else if (is_swap_pte(ptent)) {
|
|
||||||
ent = pte_to_swp_entry(ptent);
|
|
||||||
if (!move_anon || non_swap_entry(ent))
|
|
||||||
return 0;
|
|
||||||
usage_count = mem_cgroup_count_swap_user(ent, &page);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
page = vm_normal_page(vma, addr, ptent);
|
|
||||||
if (!page || !page_mapped(page))
|
|
||||||
return 0;
|
|
||||||
/*
|
|
||||||
* TODO: We don't move charges of file(including shmem/tmpfs)
|
|
||||||
* pages for now.
|
|
||||||
*/
|
|
||||||
if (!move_anon || !PageAnon(page))
|
|
||||||
return 0;
|
|
||||||
if (!get_page_unless_zero(page))
|
|
||||||
return 0;
|
|
||||||
usage_count = page_mapcount(page);
|
|
||||||
}
|
|
||||||
if (usage_count > 1) {
|
|
||||||
/*
|
|
||||||
* TODO: We don't move charges of shared(used by multiple
|
|
||||||
* processes) pages for now.
|
|
||||||
*/
|
|
||||||
if (page)
|
|
||||||
put_page(page);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (page) {
|
if (page) {
|
||||||
pc = lookup_page_cgroup(page);
|
pc = lookup_page_cgroup(page);
|
||||||
/*
|
/*
|
||||||
@ -4221,8 +4243,8 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
|
|||||||
if (!ret || !target)
|
if (!ret || !target)
|
||||||
put_page(page);
|
put_page(page);
|
||||||
}
|
}
|
||||||
/* throught */
|
/* There is a swap entry and a page doesn't exist or isn't charged */
|
||||||
if (ent.val && do_swap_account && !ret &&
|
if (ent.val && !ret &&
|
||||||
css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
|
css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
|
||||||
ret = MC_TARGET_SWAP;
|
ret = MC_TARGET_SWAP;
|
||||||
if (target)
|
if (target)
|
||||||
|
Loading…
Reference in New Issue
Block a user