Commit 9878268b authored by Ze Zuo's avatar Ze Zuo
Browse files

mm/mem_sampling.c: Add controlling interface for mem_sampling

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: default avatarZe Zuo <zuoze1@huawei.com>
Signed-off-by: default avatarTong Tiangen <tongtiangen@huawei.com>
Signed-off-by: default avatarShuang Yan <yanshuang7@huawei.com>
parent 0695e18b
Loading
Loading
Loading
Loading
+98 −2
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@

struct mem_sampling_ops_struct mem_sampling_ops;

#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;
@@ -61,8 +65,12 @@ void mem_sampling_record_cb_unregister(mem_sampling_record_cb_type cb)
	}
}

DEFINE_STATIC_KEY_FALSE(mem_sampling_access_hints);

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;

@@ -88,7 +96,11 @@ static void mem_sampling_process(struct mem_sampling_record *record_base, int nr
		}
	}
out:
	/* 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)
@@ -100,14 +112,93 @@ static inline enum mem_sampling_type_enum mem_sampling_get_type(void)
#endif
}

static 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);
}

static 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
static 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;
@@ -118,8 +209,13 @@ 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))
		return -ENOMEM;

	return 0;
}