[RFC 4/6] mm, thp: introduce a controller to trigger zero subpages reclaim

Ning Zhang
2021-10-28T11:57:05Z

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@linux.alibaba.com>
---
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