@@ -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)
{
@@ -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);
This function tries to move page into other cgroup. Caller must lock page and isolate it from LRU. Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru> --- include/linux/memcontrol.h | 9 +++++++++ mm/memcontrol.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+)