Add a new controller named "reclaim" for memory.thp_reclaim_ctrl to trigger thp reclaim immediately: echo "reclaim 1" > memory.thp_reclaim_ctrl echo "reclaim 2" > memory.thp_reclaim_ctrl "reclaim 1" means triggering reclaim only for current memcg. "reclaim 2" means triggering reclaim for current memcg and it's children memcgs. Signed-off-by: Ning Zhang <ningzhang@xxxxxxxxxxxxxxxxx> --- include/linux/huge_mm.h | 1 + mm/huge_memory.c | 29 +++++++++++++++++++++++++++++ mm/memcontrol.c | 27 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 304e3df..f792433 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -190,6 +190,7 @@ unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr, int zsr_get_hpage(struct hpage_reclaim *hr_queue, struct page **reclaim_page, int threshold); unsigned long zsr_reclaim_hpage(struct lruvec *lruvec, struct page *page); +void zsr_reclaim_memcg(struct mem_cgroup *memcg); static inline struct list_head *hpage_reclaim_list(struct page *page) { return &page[3].hpage_reclaim_list; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 40a9879..633fd0f 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3541,4 +3541,33 @@ unsigned long zsr_reclaim_hpage(struct lruvec *lruvec, struct page *page) return reclaimed; } + +void zsr_reclaim_memcg(struct mem_cgroup *memcg) +{ + struct lruvec *lruvec; + struct hpage_reclaim *hr_queue; + int threshold, nid; + + if (get_thp_reclaim_mode(memcg) == THP_RECLAIM_DISABLE) + return; + + threshold = READ_ONCE(memcg->thp_reclaim_threshold); + for_each_online_node(nid) { + lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid)); + hr_queue = &memcg->nodeinfo[nid]->hpage_reclaim_queue; + for ( ; ; ) { + struct page *page = NULL; + + if (zsr_get_hpage(hr_queue, &page, threshold)) + break; + + if (!page) + continue; + + zsr_reclaim_hpage(lruvec, page); + + cond_resched(); + } + } +} #endif diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7ba3c69..a8e3ca1 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4521,6 +4521,8 @@ static int memcg_thp_reclaim_ctrl_show(struct seq_file *m, void *v) return 0; } +#define CTRL_RECLAIM_MEMCG 1 /* only relciam current memcg */ +#define CTRL_RECLAIM_ALL 2 /* reclaim current memcg and all the children memcgs */ static ssize_t memcg_thp_reclaim_ctrl_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) @@ -4548,6 +4550,31 @@ static ssize_t memcg_thp_reclaim_ctrl_write(struct kernfs_open_file *of, return -EINVAL; xchg(&memcg->thp_reclaim_threshold, threshold); + } else if (!strcmp(key, "reclaim")) { + struct mem_cgroup *iter; + int mode; + + value = strsep_s(&buf, " \t\n"); + if (!value) + return -EINVAL; + + ret = kstrtouint(value, 0, &mode); + if (ret) + return ret; + + switch (mode) { + case CTRL_RECLAIM_MEMCG: + zsr_reclaim_memcg(memcg); + break; + case CTRL_RECLAIM_ALL: + iter = mem_cgroup_iter(memcg, NULL, NULL); + do { + zsr_reclaim_memcg(iter); + } while ((iter = mem_cgroup_iter(memcg, iter, NULL))); + break; + default: + return -EINVAL; + } } else return -EINVAL; -- 1.8.3.1