hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S9BY CVE: NA
--------------------------------
With new interface "dhugetlb.nr_pages", the user can create a dpool in memcg.
To enable dpool, "dynamic_hugetlb=on" should be added to kernel parameters.
Signed-off-by: Liu Shixin liushixin2@huawei.com --- include/linux/dynamic_pool.h | 16 +++++++ kernel/cgroup/cgroup.c | 2 + mm/dynamic_pool.c | 91 ++++++++++++++++++++++++++++++++++++ mm/memcontrol.c | 47 +++++++++++++++++++ 4 files changed, 156 insertions(+)
diff --git a/include/linux/dynamic_pool.h b/include/linux/dynamic_pool.h index 56f65b617357..8307eecccfdb 100644 --- a/include/linux/dynamic_pool.h +++ b/include/linux/dynamic_pool.h @@ -30,11 +30,20 @@ struct dynamic_pool {
spinlock_t lock; struct pages_pool pool[PAGES_POOL_MAX]; + + /* Used for dynamic hugetlb */ + int nid; + unsigned long total_pages; };
void dynamic_pool_inherit(struct mem_cgroup *parent, struct mem_cgroup *memcg); int dynamic_pool_destroy(struct cgroup *cgrp, bool *clear_css_online);
+bool dynamic_pool_hide_files(struct cftype *cft); +int dynamic_pool_add_memory(struct mem_cgroup *memcg, int nid, + unsigned long size); +void dynamic_pool_show(struct mem_cgroup *memcg, struct seq_file *m); + #else struct dynamic_pool {};
@@ -48,5 +57,12 @@ static inline int dynamic_pool_destroy(struct cgroup *cgrp, { return 0; } + +#ifdef CONFIG_CGROUPS +static inline bool dynamic_pool_hide_files(struct cftype *cft) +{ + return false; +} +#endif #endif /* CONFIG_DYNAMIC_POOL */ #endif /* __LINUX_DYNAMIC_POOL_H */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index d411f1b77f74..e342774b9215 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4330,6 +4330,8 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css, continue; if ((cft->flags & CFTYPE_DEBUG) && !cgroup_debug) continue; + if (dynamic_pool_hide_files(cft)) + continue; if (is_add) { ret = cgroup_add_file(css, cgrp, cft); if (ret) { diff --git a/mm/dynamic_pool.c b/mm/dynamic_pool.c index 296d019c20ac..47e5deefbaf1 100644 --- a/mm/dynamic_pool.c +++ b/mm/dynamic_pool.c @@ -9,6 +9,8 @@
#include <linux/dynamic_pool.h>
+static bool enable_dhugetlb; + /* Indicate the enabled of dynamic pool */ DEFINE_STATIC_KEY_FALSE(dynamic_pool_key);
@@ -155,9 +157,98 @@ int dynamic_pool_destroy(struct cgroup *cgrp, bool *clear_css_online)
static int __init dynamic_pool_init(void) { + if (!enable_dhugetlb) + return 0; + static_branch_enable(&dynamic_pool_key); pr_info("enabled\n");
return 0; } subsys_initcall(dynamic_pool_init); + +/* === Dynamic hugetlb interface ====================================== */ + +static int __init dynamic_hugetlb_setup(char *buf) +{ + return kstrtobool(buf, &enable_dhugetlb); +} +early_param("dynamic_hugetlb", dynamic_hugetlb_setup); + +/* If dynamic pool is disabled, hide the interface */ +bool dynamic_pool_hide_files(struct cftype *cft) +{ + if (dpool_enabled && enable_dhugetlb) + return false; + + return !!strstr(cft->name, "dhugetlb"); +} + +int dynamic_pool_add_memory(struct mem_cgroup *memcg, int nid, + unsigned long size) +{ + struct dynamic_pool *dpool; + int ret = -EINVAL; + + if (!dpool_enabled) + return -EINVAL; + + mutex_lock(&dpool_mutex); + + if (!(memcg->css.cgroup->self.flags & CSS_ONLINE)) { + pr_err("add memory failed, memcg is going offline\n"); + goto unlock; + } + + dpool = memcg->dpool; + if (!dpool) { + dpool = dpool_create(memcg); + if (!dpool) + goto unlock; + + dpool->nid = nid; + } else if (dpool->memcg != memcg) { + pr_err("add memory failed, not parent memcg\n"); + goto unlock; + } else if (dpool->nid != nid) { + pr_err("add memory failed, not target nid(%d)\n", + dpool->nid); + goto unlock; + } + ret = 0; + +unlock: + mutex_unlock(&dpool_mutex); + + return ret; +} + +void dynamic_pool_show(struct mem_cgroup *memcg, struct seq_file *m) +{ + struct dynamic_pool *dpool; + + if (!dpool_enabled || !memcg) + return; + + dpool = dpool_get_from_memcg(memcg); + if (!dpool) { + seq_puts(m, "Current hierarchial have not memory pool.\n"); + return; + } + + spin_lock(&dpool->lock); + + seq_printf(m, "nid %d\n", dpool->nid); + seq_printf(m, "dhugetlb_total_pages %lu\n", dpool->total_pages); + seq_printf(m, "1G_free_unreserved_pages %lu\n", + dpool->pool[PAGES_POOL_1G].free_pages); + seq_printf(m, "2M_free_unreserved_pages %lu\n", + dpool->pool[PAGES_POOL_2M].free_pages); + seq_printf(m, "4K_free_pages %lu\n", + dpool->pool[PAGES_POOL_4K].free_pages); + seq_printf(m, "4K_used_pages %lu\n", + dpool->pool[PAGES_POOL_4K].used_pages); + + spin_unlock(&dpool->lock); + dpool_put(dpool); +} diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3e903a6d6860..dce2f2e0df21 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5749,6 +5749,45 @@ static ssize_t memory_ksm_write(struct kernfs_open_file *of, char *buf, } #endif /* CONFIG_KSM */
+#ifdef CONFIG_DYNAMIC_POOL +static ssize_t mem_cgroup_dpool_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); + unsigned long size; + int nid; + char *endp; + int ret = -EINVAL; + + buf = strstrip(buf); + nid = memparse(buf, &endp); + if (*endp != ' ') + goto out; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)) + goto out; + + buf = endp + 1; + size = memparse(buf, &endp); + if (*endp != '\0' || size == 0) + goto out; + + ret = dynamic_pool_add_memory(memcg, nid, size); + +out: + return ret ? : nbytes; +} + +static int mem_cgroup_dpool_read(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + + dynamic_pool_show(memcg, m); + + return 0; +} +#endif + static int memory_stat_show(struct seq_file *m, void *v);
#ifdef CONFIG_MEMCG_V1_RECLAIM @@ -6109,6 +6148,14 @@ static struct cftype mem_cgroup_legacy_files[] = { .write = memcg_swapfile_write, .seq_show = memcg_swapfile_read, }, +#endif +#ifdef CONFIG_DYNAMIC_POOL + { + .name = "dhugetlb.nr_pages", + .write = mem_cgroup_dpool_write, + .seq_show = mem_cgroup_dpool_read, + .flags = CFTYPE_NO_PREFIX | CFTYPE_WORLD_WRITABLE | CFTYPE_NOT_ON_ROOT, + }, #endif { }, /* terminate */ };