This function tries to move page into other cgroup. Caller must lock page and isolate it from LRU. Signed-off-by: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx> --- include/linux/memcontrol.h | 9 +++++++++ mm/memcontrol.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 2cd4359cb38c..d94950584f60 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -352,6 +352,8 @@ void mem_cgroup_uncharge(struct page *page); void mem_cgroup_uncharge_list(struct list_head *page_list); void mem_cgroup_migrate(struct page *oldpage, struct page *newpage); +int mem_cgroup_try_recharge(struct page *page, struct mm_struct *mm, + gfp_t gfp_mask); static struct mem_cgroup_per_node * mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid) @@ -857,6 +859,13 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new) { } +static inline int mem_cgroup_try_recharge(struct page *page, + struct mm_struct *mm, + gfp_t gfp_mask) +{ + return 0; +} + static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, struct mem_cgroup *memcg) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 40ddc233e973..953a0bbb9f43 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6507,6 +6507,46 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage) local_irq_restore(flags); } +/* + * mem_cgroup_try_recharge - try to recharge page to mm's memcg. + * + * Page must be locked and isolated. + */ +int mem_cgroup_try_recharge(struct page *page, struct mm_struct *mm, + gfp_t gfp_mask) +{ + struct mem_cgroup *from, *to; + int nr_pages; + int err = 0; + + VM_BUG_ON_PAGE(!PageLocked(page), page); + VM_BUG_ON_PAGE(PageLRU(page), page); + + if (mem_cgroup_disabled()) + return 0; + + from = page->mem_cgroup; + to = get_mem_cgroup_from_mm(mm); + + if (likely(from == to) || !from) + goto out; + + nr_pages = hpage_nr_pages(page); + err = try_charge(to, gfp_mask, nr_pages); + if (err) + goto out; + + err = mem_cgroup_move_account(page, nr_pages > 1, from, to); + if (err) + cancel_charge(to, nr_pages); + else + cancel_charge(from, nr_pages); +out: + css_put(&to->css); + + return err; +} + DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key); EXPORT_SYMBOL(memcg_sockets_enabled_key);