hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9GZAQ CVE: NA
--------------------------------
Add sysctl to enable or disable mem_sampling actions.
A static key controlled by sysctl is added. When this is set to false, mem_sampling disable new sampling requests and stop hardware pmu in interrupts, otherwise permit the sampling requests, and automatically continue sampling in interrupts.
Signed-off-by: Ze Zuo zuoze1@huawei.com Signed-off-by: Tong Tiangen tongtiangen@huawei.com Signed-off-by: Shuang Yan yanshuang7@huawei.com --- mm/mem_sampling.c | 105 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 3 deletions(-)
diff --git a/mm/mem_sampling.c b/mm/mem_sampling.c index 38e99b080bb0..ad2cd61768c6 100644 --- a/mm/mem_sampling.c +++ b/mm/mem_sampling.c @@ -12,7 +12,6 @@
#define pr_fmt(fmt) "mem_sampling: " fmt
- #include <linux/slab.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -22,6 +21,12 @@
struct mem_sampling_ops_struct mem_sampling_ops;
+struct static_key_false mem_sampling_access_hints; + +#define MEM_SAMPLING_DISABLED 0x0 +#define MEM_SAMPLING_NORMAL 0x1 + +static int mem_sampling_override __initdata; struct mem_sampling_record_cb_list_entry { struct list_head list; mem_sampling_record_cb_type cb; @@ -65,6 +70,8 @@ void mem_sampling_record_cb_unregister(mem_sampling_record_cb_type cb)
void mem_sampling_sched_in(struct task_struct *prev, struct task_struct *curr) { + if (!static_branch_unlikely(&mem_sampling_access_hints)) + return;
if (!mem_sampling_ops.sampling_start) return; @@ -96,7 +103,11 @@ void mem_sampling_process(struct mem_sampling_record *record_base, int nr_record } } out: - mem_sampling_ops.sampling_continue(); + /* if mem_sampling_access_hints is set to false, stop sampling */ + if (static_branch_unlikely(&mem_sampling_access_hints)) + mem_sampling_ops.sampling_continue(); + else + mem_sampling_ops.sampling_stop(); }
static inline enum mem_sampling_type_enum mem_sampling_get_type(void) @@ -108,14 +119,95 @@ static inline enum mem_sampling_type_enum mem_sampling_get_type(void) #endif }
+DEFINE_STATIC_KEY_FALSE(mem_sampling_access_hints); + +int sysctl_mem_sampling_mode; + +static void __set_mem_sampling_state(bool enabled) +{ + if (enabled) + static_branch_enable(&mem_sampling_access_hints); + else + static_branch_disable(&mem_sampling_access_hints); +} + +void set_mem_sampling_state(bool enabled) +{ + if (!mem_sampling_ops.sampling_start) + return; + if (enabled) + sysctl_mem_sampling_mode = MEM_SAMPLING_NORMAL; + else + sysctl_mem_sampling_mode = MEM_SAMPLING_DISABLED; + __set_mem_sampling_state(enabled); +} + +#ifdef CONFIG_PROC_SYSCTL +int sysctl_mem_sampling_enable(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + int err; + int state = sysctl_mem_sampling_mode; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + t = *table; + t.data = &state; + err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); + if (err < 0) + return err; + if (write) + set_mem_sampling_state(state); + return err; +} +#endif + +static struct ctl_table ctl_table[] = { + { + .procname = "mem_sampling_enable", + .data = NULL, /* filled in by handler */ + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sysctl_mem_sampling_enable, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + {} +}; + +static struct ctl_table mem_sampling_dir_table[] = { + { + .procname = "kernel", + .maxlen = 0, + .mode = 0555, + .child = ctl_table, + }, + {} +}; + +static void __init check_mem_sampling_enable(void) +{ + bool mem_sampling_default = false; + + /* Parsed by setup_mem_sampling. override == 1 enables, -1 disables */ + if (mem_sampling_override) + set_mem_sampling_state(mem_sampling_override == 1); + else + set_mem_sampling_state(mem_sampling_default); +} + static int __init mem_sampling_init(void) { enum mem_sampling_type_enum mem_sampling_type = mem_sampling_get_type();
switch (mem_sampling_type) { case MEM_SAMPLING_ARM_SPE: - if (!arm_spe_enabled()) + if (!arm_spe_enabled()) { + set_mem_sampling_state(false); return -ENODEV; + } mem_sampling_ops.sampling_start = arm_spe_start, mem_sampling_ops.sampling_stop = arm_spe_stop, mem_sampling_ops.sampling_continue = arm_spe_continue, @@ -126,8 +218,15 @@ static int __init mem_sampling_init(void) default: pr_info("unsupport hardware pmu type(%d), disable access hint!\n", mem_sampling_type); + set_mem_sampling_state(false); return -ENODEV; } + check_mem_sampling_enable(); + + if (!register_sysctl_table(mem_sampling_dir_table)) { + pr_err("register page cache limit sysctl failed."); + return -ENOMEM; + }
pr_info("mem_sampling layer access profiling setup for NUMA Balancing and DAMON etc.\n"); return 0;