brintos

brintos / linux-shallow public Read only

0
0
Text · 24.6 KiB · b4213bc Raw
1149 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * DAMON Debugfs Interface4 *5 * Author: SeongJae Park <sj@kernel.org>6 */7 8#define pr_fmt(fmt) "damon-dbgfs: " fmt9 10#include <linux/damon.h>11#include <linux/debugfs.h>12#include <linux/file.h>13#include <linux/mm.h>14#include <linux/module.h>15#include <linux/page_idle.h>16#include <linux/slab.h>17 18#define DAMON_DBGFS_DEPRECATION_NOTICE					\19	"DAMON debugfs interface is deprecated, so users should move "	\20	"to DAMON_SYSFS. If you cannot, please report your usecase to "	\21	"damon@lists.linux.dev and linux-mm@kvack.org.\n"22 23static struct damon_ctx **dbgfs_ctxs;24static int dbgfs_nr_ctxs;25static struct dentry **dbgfs_dirs;26static DEFINE_MUTEX(damon_dbgfs_lock);27 28static void damon_dbgfs_warn_deprecation(void)29{30	pr_warn_once(DAMON_DBGFS_DEPRECATION_NOTICE);31}32 33/*34 * Returns non-empty string on success, negative error code otherwise.35 */36static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos)37{38	char *kbuf;39	ssize_t ret;40 41	/* We do not accept continuous write */42	if (*ppos)43		return ERR_PTR(-EINVAL);44 45	kbuf = kmalloc(count + 1, GFP_KERNEL | __GFP_NOWARN);46	if (!kbuf)47		return ERR_PTR(-ENOMEM);48 49	ret = simple_write_to_buffer(kbuf, count + 1, ppos, buf, count);50	if (ret != count) {51		kfree(kbuf);52		return ERR_PTR(-EIO);53	}54	kbuf[ret] = '\0';55 56	return kbuf;57}58 59static ssize_t dbgfs_attrs_read(struct file *file,60		char __user *buf, size_t count, loff_t *ppos)61{62	struct damon_ctx *ctx = file->private_data;63	char kbuf[128];64	int ret;65 66	mutex_lock(&ctx->kdamond_lock);67	ret = scnprintf(kbuf, ARRAY_SIZE(kbuf), "%lu %lu %lu %lu %lu\n",68			ctx->attrs.sample_interval, ctx->attrs.aggr_interval,69			ctx->attrs.ops_update_interval,70			ctx->attrs.min_nr_regions, ctx->attrs.max_nr_regions);71	mutex_unlock(&ctx->kdamond_lock);72 73	return simple_read_from_buffer(buf, count, ppos, kbuf, ret);74}75 76static ssize_t dbgfs_attrs_write(struct file *file,77		const char __user *buf, size_t count, loff_t *ppos)78{79	struct damon_ctx *ctx = file->private_data;80	struct damon_attrs attrs;81	char *kbuf;82	ssize_t ret;83 84	kbuf = user_input_str(buf, count, ppos);85	if (IS_ERR(kbuf))86		return PTR_ERR(kbuf);87 88	if (sscanf(kbuf, "%lu %lu %lu %lu %lu",89				&attrs.sample_interval, &attrs.aggr_interval,90				&attrs.ops_update_interval,91				&attrs.min_nr_regions,92				&attrs.max_nr_regions) != 5) {93		ret = -EINVAL;94		goto out;95	}96 97	mutex_lock(&ctx->kdamond_lock);98	if (ctx->kdamond) {99		ret = -EBUSY;100		goto unlock_out;101	}102 103	ret = damon_set_attrs(ctx, &attrs);104	if (!ret)105		ret = count;106unlock_out:107	mutex_unlock(&ctx->kdamond_lock);108out:109	kfree(kbuf);110	return ret;111}112 113/*114 * Return corresponding dbgfs' scheme action value (int) for the given115 * damos_action if the given damos_action value is valid and supported by116 * dbgfs, negative error code otherwise.117 */118static int damos_action_to_dbgfs_scheme_action(enum damos_action action)119{120	switch (action) {121	case DAMOS_WILLNEED:122		return 0;123	case DAMOS_COLD:124		return 1;125	case DAMOS_PAGEOUT:126		return 2;127	case DAMOS_HUGEPAGE:128		return 3;129	case DAMOS_NOHUGEPAGE:130		return 4;131	case DAMOS_STAT:132		return 5;133	default:134		return -EINVAL;135	}136}137 138static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len)139{140	struct damos *s;141	int written = 0;142	int rc;143 144	damon_for_each_scheme(s, c) {145		rc = scnprintf(&buf[written], len - written,146				"%lu %lu %u %u %u %u %d %lu %lu %lu %u %u %u %d %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",147				s->pattern.min_sz_region,148				s->pattern.max_sz_region,149				s->pattern.min_nr_accesses,150				s->pattern.max_nr_accesses,151				s->pattern.min_age_region,152				s->pattern.max_age_region,153				damos_action_to_dbgfs_scheme_action(s->action),154				s->quota.ms, s->quota.sz,155				s->quota.reset_interval,156				s->quota.weight_sz,157				s->quota.weight_nr_accesses,158				s->quota.weight_age,159				s->wmarks.metric, s->wmarks.interval,160				s->wmarks.high, s->wmarks.mid, s->wmarks.low,161				s->stat.nr_tried, s->stat.sz_tried,162				s->stat.nr_applied, s->stat.sz_applied,163				s->stat.qt_exceeds);164		if (!rc)165			return -ENOMEM;166 167		written += rc;168	}169	return written;170}171 172static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf,173		size_t count, loff_t *ppos)174{175	struct damon_ctx *ctx = file->private_data;176	char *kbuf;177	ssize_t len;178 179	kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);180	if (!kbuf)181		return -ENOMEM;182 183	mutex_lock(&ctx->kdamond_lock);184	len = sprint_schemes(ctx, kbuf, count);185	mutex_unlock(&ctx->kdamond_lock);186	if (len < 0)187		goto out;188	len = simple_read_from_buffer(buf, count, ppos, kbuf, len);189 190out:191	kfree(kbuf);192	return len;193}194 195static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes)196{197	ssize_t i;198 199	for (i = 0; i < nr_schemes; i++)200		kfree(schemes[i]);201	kfree(schemes);202}203 204/*205 * Return corresponding damos_action for the given dbgfs input for a scheme206 * action if the input is valid, negative error code otherwise.207 */208static enum damos_action dbgfs_scheme_action_to_damos_action(int dbgfs_action)209{210	switch (dbgfs_action) {211	case 0:212		return DAMOS_WILLNEED;213	case 1:214		return DAMOS_COLD;215	case 2:216		return DAMOS_PAGEOUT;217	case 3:218		return DAMOS_HUGEPAGE;219	case 4:220		return DAMOS_NOHUGEPAGE;221	case 5:222		return DAMOS_STAT;223	default:224		return -EINVAL;225	}226}227 228/*229 * Converts a string into an array of struct damos pointers230 *231 * Returns an array of struct damos pointers that converted if the conversion232 * success, or NULL otherwise.233 */234static struct damos **str_to_schemes(const char *str, ssize_t len,235				ssize_t *nr_schemes)236{237	struct damos *scheme, **schemes;238	const int max_nr_schemes = 256;239	int pos = 0, parsed, ret;240	unsigned int action_input;241	enum damos_action action;242 243	schemes = kmalloc_array(max_nr_schemes, sizeof(scheme),244			GFP_KERNEL);245	if (!schemes)246		return NULL;247 248	*nr_schemes = 0;249	while (pos < len && *nr_schemes < max_nr_schemes) {250		struct damos_access_pattern pattern = {};251		struct damos_quota quota = {};252		struct damos_watermarks wmarks;253 254		ret = sscanf(&str[pos],255				"%lu %lu %u %u %u %u %u %lu %lu %lu %u %u %u %u %lu %lu %lu %lu%n",256				&pattern.min_sz_region, &pattern.max_sz_region,257				&pattern.min_nr_accesses,258				&pattern.max_nr_accesses,259				&pattern.min_age_region,260				&pattern.max_age_region,261				&action_input, &quota.ms,262				&quota.sz, &quota.reset_interval,263				&quota.weight_sz, &quota.weight_nr_accesses,264				&quota.weight_age, &wmarks.metric,265				&wmarks.interval, &wmarks.high, &wmarks.mid,266				&wmarks.low, &parsed);267		if (ret != 18)268			break;269		action = dbgfs_scheme_action_to_damos_action(action_input);270		if ((int)action < 0)271			goto fail;272 273		if (pattern.min_sz_region > pattern.max_sz_region ||274		    pattern.min_nr_accesses > pattern.max_nr_accesses ||275		    pattern.min_age_region > pattern.max_age_region)276			goto fail;277 278		if (wmarks.high < wmarks.mid || wmarks.high < wmarks.low ||279		    wmarks.mid <  wmarks.low)280			goto fail;281 282		pos += parsed;283		scheme = damon_new_scheme(&pattern, action, 0, &quota,284				&wmarks, NUMA_NO_NODE);285		if (!scheme)286			goto fail;287 288		schemes[*nr_schemes] = scheme;289		*nr_schemes += 1;290	}291	return schemes;292fail:293	free_schemes_arr(schemes, *nr_schemes);294	return NULL;295}296 297static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf,298		size_t count, loff_t *ppos)299{300	struct damon_ctx *ctx = file->private_data;301	char *kbuf;302	struct damos **schemes;303	ssize_t nr_schemes = 0, ret;304 305	kbuf = user_input_str(buf, count, ppos);306	if (IS_ERR(kbuf))307		return PTR_ERR(kbuf);308 309	schemes = str_to_schemes(kbuf, count, &nr_schemes);310	if (!schemes) {311		ret = -EINVAL;312		goto out;313	}314 315	mutex_lock(&ctx->kdamond_lock);316	if (ctx->kdamond) {317		ret = -EBUSY;318		goto unlock_out;319	}320 321	damon_set_schemes(ctx, schemes, nr_schemes);322	ret = count;323	nr_schemes = 0;324 325unlock_out:326	mutex_unlock(&ctx->kdamond_lock);327	free_schemes_arr(schemes, nr_schemes);328out:329	kfree(kbuf);330	return ret;331}332 333static ssize_t sprint_target_ids(struct damon_ctx *ctx, char *buf, ssize_t len)334{335	struct damon_target *t;336	int id;337	int written = 0;338	int rc;339 340	damon_for_each_target(t, ctx) {341		if (damon_target_has_pid(ctx))342			/* Show pid numbers to debugfs users */343			id = pid_vnr(t->pid);344		else345			/* Show 42 for physical address space, just for fun */346			id = 42;347 348		rc = scnprintf(&buf[written], len - written, "%d ", id);349		if (!rc)350			return -ENOMEM;351		written += rc;352	}353	if (written)354		written -= 1;355	written += scnprintf(&buf[written], len - written, "\n");356	return written;357}358 359static ssize_t dbgfs_target_ids_read(struct file *file,360		char __user *buf, size_t count, loff_t *ppos)361{362	struct damon_ctx *ctx = file->private_data;363	ssize_t len;364	char ids_buf[320];365 366	mutex_lock(&ctx->kdamond_lock);367	len = sprint_target_ids(ctx, ids_buf, 320);368	mutex_unlock(&ctx->kdamond_lock);369	if (len < 0)370		return len;371 372	return simple_read_from_buffer(buf, count, ppos, ids_buf, len);373}374 375/*376 * Converts a string into an integers array377 *378 * Returns an array of integers array if the conversion success, or NULL379 * otherwise.380 */381static int *str_to_ints(const char *str, ssize_t len, ssize_t *nr_ints)382{383	int *array;384	const int max_nr_ints = 32;385	int nr;386	int pos = 0, parsed, ret;387 388	*nr_ints = 0;389	array = kmalloc_array(max_nr_ints, sizeof(*array), GFP_KERNEL);390	if (!array)391		return NULL;392	while (*nr_ints < max_nr_ints && pos < len) {393		ret = sscanf(&str[pos], "%d%n", &nr, &parsed);394		pos += parsed;395		if (ret != 1)396			break;397		array[*nr_ints] = nr;398		*nr_ints += 1;399	}400 401	return array;402}403 404static void dbgfs_put_pids(struct pid **pids, int nr_pids)405{406	int i;407 408	for (i = 0; i < nr_pids; i++)409		put_pid(pids[i]);410}411 412/*413 * Converts a string into an struct pid pointers array414 *415 * Returns an array of struct pid pointers if the conversion success, or NULL416 * otherwise.417 */418static struct pid **str_to_pids(const char *str, ssize_t len, ssize_t *nr_pids)419{420	int *ints;421	ssize_t nr_ints;422	struct pid **pids;423 424	*nr_pids = 0;425 426	ints = str_to_ints(str, len, &nr_ints);427	if (!ints)428		return NULL;429 430	pids = kmalloc_array(nr_ints, sizeof(*pids), GFP_KERNEL);431	if (!pids)432		goto out;433 434	for (; *nr_pids < nr_ints; (*nr_pids)++) {435		pids[*nr_pids] = find_get_pid(ints[*nr_pids]);436		if (!pids[*nr_pids]) {437			dbgfs_put_pids(pids, *nr_pids);438			kfree(ints);439			kfree(pids);440			return NULL;441		}442	}443 444out:445	kfree(ints);446	return pids;447}448 449/*450 * dbgfs_set_targets() - Set monitoring targets.451 * @ctx:	monitoring context452 * @nr_targets:	number of targets453 * @pids:	array of target pids (size is same to @nr_targets)454 *455 * This function should not be called while the kdamond is running.  @pids is456 * ignored if the context is not configured to have pid in each target.  On457 * failure, reference counts of all pids in @pids are decremented.458 *459 * Return: 0 on success, negative error code otherwise.460 */461static int dbgfs_set_targets(struct damon_ctx *ctx, ssize_t nr_targets,462		struct pid **pids)463{464	ssize_t i;465	struct damon_target *t, *next;466 467	damon_for_each_target_safe(t, next, ctx) {468		if (damon_target_has_pid(ctx))469			put_pid(t->pid);470		damon_destroy_target(t);471	}472 473	for (i = 0; i < nr_targets; i++) {474		t = damon_new_target();475		if (!t) {476			damon_for_each_target_safe(t, next, ctx)477				damon_destroy_target(t);478			if (damon_target_has_pid(ctx))479				dbgfs_put_pids(pids, nr_targets);480			return -ENOMEM;481		}482		if (damon_target_has_pid(ctx))483			t->pid = pids[i];484		damon_add_target(ctx, t);485	}486 487	return 0;488}489 490static ssize_t dbgfs_target_ids_write(struct file *file,491		const char __user *buf, size_t count, loff_t *ppos)492{493	struct damon_ctx *ctx = file->private_data;494	bool id_is_pid = true;495	char *kbuf;496	struct pid **target_pids = NULL;497	ssize_t nr_targets;498	ssize_t ret;499 500	kbuf = user_input_str(buf, count, ppos);501	if (IS_ERR(kbuf))502		return PTR_ERR(kbuf);503 504	if (!strncmp(kbuf, "paddr\n", count)) {505		id_is_pid = false;506		nr_targets = 1;507	}508 509	if (id_is_pid) {510		target_pids = str_to_pids(kbuf, count, &nr_targets);511		if (!target_pids) {512			ret = -ENOMEM;513			goto out;514		}515	}516 517	mutex_lock(&ctx->kdamond_lock);518	if (ctx->kdamond) {519		if (id_is_pid)520			dbgfs_put_pids(target_pids, nr_targets);521		ret = -EBUSY;522		goto unlock_out;523	}524 525	/* remove previously set targets */526	dbgfs_set_targets(ctx, 0, NULL);527	if (!nr_targets) {528		ret = count;529		goto unlock_out;530	}531 532	/* Configure the context for the address space type */533	if (id_is_pid)534		ret = damon_select_ops(ctx, DAMON_OPS_VADDR);535	else536		ret = damon_select_ops(ctx, DAMON_OPS_PADDR);537	if (ret)538		goto unlock_out;539 540	ret = dbgfs_set_targets(ctx, nr_targets, target_pids);541	if (!ret)542		ret = count;543 544unlock_out:545	mutex_unlock(&ctx->kdamond_lock);546	kfree(target_pids);547out:548	kfree(kbuf);549	return ret;550}551 552static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len)553{554	struct damon_target *t;555	struct damon_region *r;556	int target_idx = 0;557	int written = 0;558	int rc;559 560	damon_for_each_target(t, c) {561		damon_for_each_region(r, t) {562			rc = scnprintf(&buf[written], len - written,563					"%d %lu %lu\n",564					target_idx, r->ar.start, r->ar.end);565			if (!rc)566				return -ENOMEM;567			written += rc;568		}569		target_idx++;570	}571	return written;572}573 574static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf,575		size_t count, loff_t *ppos)576{577	struct damon_ctx *ctx = file->private_data;578	char *kbuf;579	ssize_t len;580 581	kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);582	if (!kbuf)583		return -ENOMEM;584 585	mutex_lock(&ctx->kdamond_lock);586	if (ctx->kdamond) {587		mutex_unlock(&ctx->kdamond_lock);588		len = -EBUSY;589		goto out;590	}591 592	len = sprint_init_regions(ctx, kbuf, count);593	mutex_unlock(&ctx->kdamond_lock);594	if (len < 0)595		goto out;596	len = simple_read_from_buffer(buf, count, ppos, kbuf, len);597 598out:599	kfree(kbuf);600	return len;601}602 603static int add_init_region(struct damon_ctx *c, int target_idx,604		struct damon_addr_range *ar)605{606	struct damon_target *t;607	struct damon_region *r, *prev;608	unsigned long idx = 0;609	int rc = -EINVAL;610 611	if (ar->start >= ar->end)612		return -EINVAL;613 614	damon_for_each_target(t, c) {615		if (idx++ == target_idx) {616			r = damon_new_region(ar->start, ar->end);617			if (!r)618				return -ENOMEM;619			damon_add_region(r, t);620			if (damon_nr_regions(t) > 1) {621				prev = damon_prev_region(r);622				if (prev->ar.end > r->ar.start) {623					damon_destroy_region(r, t);624					return -EINVAL;625				}626			}627			rc = 0;628		}629	}630	return rc;631}632 633static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len)634{635	struct damon_target *t;636	struct damon_region *r, *next;637	int pos = 0, parsed, ret;638	int target_idx;639	struct damon_addr_range ar;640	int err;641 642	damon_for_each_target(t, c) {643		damon_for_each_region_safe(r, next, t)644			damon_destroy_region(r, t);645	}646 647	while (pos < len) {648		ret = sscanf(&str[pos], "%d %lu %lu%n",649				&target_idx, &ar.start, &ar.end, &parsed);650		if (ret != 3)651			break;652		err = add_init_region(c, target_idx, &ar);653		if (err)654			goto fail;655		pos += parsed;656	}657 658	return 0;659 660fail:661	damon_for_each_target(t, c) {662		damon_for_each_region_safe(r, next, t)663			damon_destroy_region(r, t);664	}665	return err;666}667 668static ssize_t dbgfs_init_regions_write(struct file *file,669					  const char __user *buf, size_t count,670					  loff_t *ppos)671{672	struct damon_ctx *ctx = file->private_data;673	char *kbuf;674	ssize_t ret = count;675	int err;676 677	kbuf = user_input_str(buf, count, ppos);678	if (IS_ERR(kbuf))679		return PTR_ERR(kbuf);680 681	mutex_lock(&ctx->kdamond_lock);682	if (ctx->kdamond) {683		ret = -EBUSY;684		goto unlock_out;685	}686 687	err = set_init_regions(ctx, kbuf, ret);688	if (err)689		ret = err;690 691unlock_out:692	mutex_unlock(&ctx->kdamond_lock);693	kfree(kbuf);694	return ret;695}696 697static ssize_t dbgfs_kdamond_pid_read(struct file *file,698		char __user *buf, size_t count, loff_t *ppos)699{700	struct damon_ctx *ctx = file->private_data;701	char *kbuf;702	ssize_t len;703 704	kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);705	if (!kbuf)706		return -ENOMEM;707 708	mutex_lock(&ctx->kdamond_lock);709	if (ctx->kdamond)710		len = scnprintf(kbuf, count, "%d\n", ctx->kdamond->pid);711	else712		len = scnprintf(kbuf, count, "none\n");713	mutex_unlock(&ctx->kdamond_lock);714	if (!len)715		goto out;716	len = simple_read_from_buffer(buf, count, ppos, kbuf, len);717 718out:719	kfree(kbuf);720	return len;721}722 723static int damon_dbgfs_open(struct inode *inode, struct file *file)724{725	damon_dbgfs_warn_deprecation();726 727	file->private_data = inode->i_private;728 729	return nonseekable_open(inode, file);730}731 732static const struct file_operations attrs_fops = {733	.open = damon_dbgfs_open,734	.read = dbgfs_attrs_read,735	.write = dbgfs_attrs_write,736};737 738static const struct file_operations schemes_fops = {739	.open = damon_dbgfs_open,740	.read = dbgfs_schemes_read,741	.write = dbgfs_schemes_write,742};743 744static const struct file_operations target_ids_fops = {745	.open = damon_dbgfs_open,746	.read = dbgfs_target_ids_read,747	.write = dbgfs_target_ids_write,748};749 750static const struct file_operations init_regions_fops = {751	.open = damon_dbgfs_open,752	.read = dbgfs_init_regions_read,753	.write = dbgfs_init_regions_write,754};755 756static const struct file_operations kdamond_pid_fops = {757	.open = damon_dbgfs_open,758	.read = dbgfs_kdamond_pid_read,759};760 761static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx)762{763	const char * const file_names[] = {"attrs", "schemes", "target_ids",764		"init_regions", "kdamond_pid"};765	const struct file_operations *fops[] = {&attrs_fops, &schemes_fops,766		&target_ids_fops, &init_regions_fops, &kdamond_pid_fops};767	int i;768 769	for (i = 0; i < ARRAY_SIZE(file_names); i++)770		debugfs_create_file(file_names[i], 0600, dir, ctx, fops[i]);771}772 773static void dbgfs_before_terminate(struct damon_ctx *ctx)774{775	struct damon_target *t, *next;776 777	if (!damon_target_has_pid(ctx))778		return;779 780	mutex_lock(&ctx->kdamond_lock);781	damon_for_each_target_safe(t, next, ctx) {782		put_pid(t->pid);783		damon_destroy_target(t);784	}785	mutex_unlock(&ctx->kdamond_lock);786}787 788static struct damon_ctx *dbgfs_new_ctx(void)789{790	struct damon_ctx *ctx;791 792	ctx = damon_new_ctx();793	if (!ctx)794		return NULL;795 796	if (damon_select_ops(ctx, DAMON_OPS_VADDR) &&797			damon_select_ops(ctx, DAMON_OPS_PADDR)) {798		damon_destroy_ctx(ctx);799		return NULL;800	}801	ctx->callback.before_terminate = dbgfs_before_terminate;802	return ctx;803}804 805static void dbgfs_destroy_ctx(struct damon_ctx *ctx)806{807	damon_destroy_ctx(ctx);808}809 810static ssize_t damon_dbgfs_deprecated_read(struct file *file,811		char __user *buf, size_t count, loff_t *ppos)812{813	static const char kbuf[512] = DAMON_DBGFS_DEPRECATION_NOTICE;814 815	return simple_read_from_buffer(buf, count, ppos, kbuf, strlen(kbuf));816}817 818/*819 * Make a context of @name and create a debugfs directory for it.820 *821 * This function should be called while holding damon_dbgfs_lock.822 *823 * Returns 0 on success, negative error code otherwise.824 */825static int dbgfs_mk_context(char *name)826{827	struct dentry *root, **new_dirs, *new_dir;828	struct damon_ctx **new_ctxs, *new_ctx;829 830	if (damon_nr_running_ctxs())831		return -EBUSY;832 833	new_ctxs = krealloc(dbgfs_ctxs, sizeof(*dbgfs_ctxs) *834			(dbgfs_nr_ctxs + 1), GFP_KERNEL);835	if (!new_ctxs)836		return -ENOMEM;837	dbgfs_ctxs = new_ctxs;838 839	new_dirs = krealloc(dbgfs_dirs, sizeof(*dbgfs_dirs) *840			(dbgfs_nr_ctxs + 1), GFP_KERNEL);841	if (!new_dirs)842		return -ENOMEM;843	dbgfs_dirs = new_dirs;844 845	root = dbgfs_dirs[0];846	if (!root)847		return -ENOENT;848 849	new_dir = debugfs_create_dir(name, root);850	/* Below check is required for a potential duplicated name case */851	if (IS_ERR(new_dir))852		return PTR_ERR(new_dir);853	dbgfs_dirs[dbgfs_nr_ctxs] = new_dir;854 855	new_ctx = dbgfs_new_ctx();856	if (!new_ctx) {857		debugfs_remove(new_dir);858		dbgfs_dirs[dbgfs_nr_ctxs] = NULL;859		return -ENOMEM;860	}861 862	dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx;863	dbgfs_fill_ctx_dir(dbgfs_dirs[dbgfs_nr_ctxs],864			dbgfs_ctxs[dbgfs_nr_ctxs]);865	dbgfs_nr_ctxs++;866 867	return 0;868}869 870static ssize_t dbgfs_mk_context_write(struct file *file,871		const char __user *buf, size_t count, loff_t *ppos)872{873	char *kbuf;874	char *ctx_name;875	ssize_t ret;876 877	kbuf = user_input_str(buf, count, ppos);878	if (IS_ERR(kbuf))879		return PTR_ERR(kbuf);880	ctx_name = kmalloc(count + 1, GFP_KERNEL);881	if (!ctx_name) {882		kfree(kbuf);883		return -ENOMEM;884	}885 886	/* Trim white space */887	if (sscanf(kbuf, "%s", ctx_name) != 1) {888		ret = -EINVAL;889		goto out;890	}891 892	mutex_lock(&damon_dbgfs_lock);893	ret = dbgfs_mk_context(ctx_name);894	if (!ret)895		ret = count;896	mutex_unlock(&damon_dbgfs_lock);897 898out:899	kfree(kbuf);900	kfree(ctx_name);901	return ret;902}903 904/*905 * Remove a context of @name and its debugfs directory.906 *907 * This function should be called while holding damon_dbgfs_lock.908 *909 * Return 0 on success, negative error code otherwise.910 */911static int dbgfs_rm_context(char *name)912{913	struct dentry *root, *dir, **new_dirs;914	struct inode *inode;915	struct damon_ctx **new_ctxs;916	int i, j;917	int ret = 0;918 919	if (damon_nr_running_ctxs())920		return -EBUSY;921 922	root = dbgfs_dirs[0];923	if (!root)924		return -ENOENT;925 926	dir = debugfs_lookup(name, root);927	if (!dir)928		return -ENOENT;929 930	inode = d_inode(dir);931	if (!S_ISDIR(inode->i_mode)) {932		ret = -EINVAL;933		goto out_dput;934	}935 936	new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs),937			GFP_KERNEL);938	if (!new_dirs) {939		ret = -ENOMEM;940		goto out_dput;941	}942 943	new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs),944			GFP_KERNEL);945	if (!new_ctxs) {946		ret = -ENOMEM;947		goto out_new_dirs;948	}949 950	for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) {951		if (dbgfs_dirs[i] == dir) {952			debugfs_remove(dbgfs_dirs[i]);953			dbgfs_destroy_ctx(dbgfs_ctxs[i]);954			continue;955		}956		new_dirs[j] = dbgfs_dirs[i];957		new_ctxs[j++] = dbgfs_ctxs[i];958	}959 960	kfree(dbgfs_dirs);961	kfree(dbgfs_ctxs);962 963	dbgfs_dirs = new_dirs;964	dbgfs_ctxs = new_ctxs;965	dbgfs_nr_ctxs--;966 967	goto out_dput;968 969out_new_dirs:970	kfree(new_dirs);971out_dput:972	dput(dir);973	return ret;974}975 976static ssize_t dbgfs_rm_context_write(struct file *file,977		const char __user *buf, size_t count, loff_t *ppos)978{979	char *kbuf;980	ssize_t ret;981	char *ctx_name;982 983	kbuf = user_input_str(buf, count, ppos);984	if (IS_ERR(kbuf))985		return PTR_ERR(kbuf);986	ctx_name = kmalloc(count + 1, GFP_KERNEL);987	if (!ctx_name) {988		kfree(kbuf);989		return -ENOMEM;990	}991 992	/* Trim white space */993	if (sscanf(kbuf, "%s", ctx_name) != 1) {994		ret = -EINVAL;995		goto out;996	}997 998	mutex_lock(&damon_dbgfs_lock);999	ret = dbgfs_rm_context(ctx_name);1000	if (!ret)1001		ret = count;1002	mutex_unlock(&damon_dbgfs_lock);1003 1004out:1005	kfree(kbuf);1006	kfree(ctx_name);1007	return ret;1008}1009 1010static ssize_t dbgfs_monitor_on_read(struct file *file,1011		char __user *buf, size_t count, loff_t *ppos)1012{1013	char monitor_on_buf[5];1014	bool monitor_on = damon_nr_running_ctxs() != 0;1015	int len;1016 1017	len = scnprintf(monitor_on_buf, 5, monitor_on ? "on\n" : "off\n");1018 1019	return simple_read_from_buffer(buf, count, ppos, monitor_on_buf, len);1020}1021 1022static ssize_t dbgfs_monitor_on_write(struct file *file,1023		const char __user *buf, size_t count, loff_t *ppos)1024{1025	ssize_t ret;1026	char *kbuf;1027 1028	kbuf = user_input_str(buf, count, ppos);1029	if (IS_ERR(kbuf))1030		return PTR_ERR(kbuf);1031 1032	/* Remove white space */1033	if (sscanf(kbuf, "%s", kbuf) != 1) {1034		kfree(kbuf);1035		return -EINVAL;1036	}1037 1038	mutex_lock(&damon_dbgfs_lock);1039	if (!strncmp(kbuf, "on", count)) {1040		int i;1041 1042		for (i = 0; i < dbgfs_nr_ctxs; i++) {1043			if (damon_targets_empty(dbgfs_ctxs[i])) {1044				kfree(kbuf);1045				mutex_unlock(&damon_dbgfs_lock);1046				return -EINVAL;1047			}1048		}1049		ret = damon_start(dbgfs_ctxs, dbgfs_nr_ctxs, true);1050	} else if (!strncmp(kbuf, "off", count)) {1051		ret = damon_stop(dbgfs_ctxs, dbgfs_nr_ctxs);1052	} else {1053		ret = -EINVAL;1054	}1055	mutex_unlock(&damon_dbgfs_lock);1056 1057	if (!ret)1058		ret = count;1059	kfree(kbuf);1060	return ret;1061}1062 1063static int damon_dbgfs_static_file_open(struct inode *inode, struct file *file)1064{1065	damon_dbgfs_warn_deprecation();1066	return nonseekable_open(inode, file);1067}1068 1069static const struct file_operations deprecated_fops = {1070	.read = damon_dbgfs_deprecated_read,1071};1072 1073static const struct file_operations mk_contexts_fops = {1074	.open = damon_dbgfs_static_file_open,1075	.write = dbgfs_mk_context_write,1076};1077 1078static const struct file_operations rm_contexts_fops = {1079	.open = damon_dbgfs_static_file_open,1080	.write = dbgfs_rm_context_write,1081};1082 1083static const struct file_operations monitor_on_fops = {1084	.open = damon_dbgfs_static_file_open,1085	.read = dbgfs_monitor_on_read,1086	.write = dbgfs_monitor_on_write,1087};1088 1089static int __init __damon_dbgfs_init(void)1090{1091	struct dentry *dbgfs_root;1092	const char * const file_names[] = {"mk_contexts", "rm_contexts",1093		"monitor_on_DEPRECATED", "DEPRECATED"};1094	const struct file_operations *fops[] = {&mk_contexts_fops,1095		&rm_contexts_fops, &monitor_on_fops, &deprecated_fops};1096	int i;1097 1098	dbgfs_root = debugfs_create_dir("damon", NULL);1099 1100	for (i = 0; i < ARRAY_SIZE(file_names); i++)1101		debugfs_create_file(file_names[i], 0600, dbgfs_root, NULL,1102				fops[i]);1103	dbgfs_fill_ctx_dir(dbgfs_root, dbgfs_ctxs[0]);1104 1105	dbgfs_dirs = kmalloc(sizeof(dbgfs_root), GFP_KERNEL);1106	if (!dbgfs_dirs) {1107		debugfs_remove(dbgfs_root);1108		return -ENOMEM;1109	}1110	dbgfs_dirs[0] = dbgfs_root;1111 1112	return 0;1113}1114 1115/*1116 * Functions for the initialization1117 */1118 1119static int __init damon_dbgfs_init(void)1120{1121	int rc = -ENOMEM;1122 1123	mutex_lock(&damon_dbgfs_lock);1124	dbgfs_ctxs = kmalloc(sizeof(*dbgfs_ctxs), GFP_KERNEL);1125	if (!dbgfs_ctxs)1126		goto out;1127	dbgfs_ctxs[0] = dbgfs_new_ctx();1128	if (!dbgfs_ctxs[0]) {1129		kfree(dbgfs_ctxs);1130		goto out;1131	}1132	dbgfs_nr_ctxs = 1;1133 1134	rc = __damon_dbgfs_init();1135	if (rc) {1136		kfree(dbgfs_ctxs[0]);1137		kfree(dbgfs_ctxs);1138		pr_err("%s: dbgfs init failed\n", __func__);1139	}1140 1141out:1142	mutex_unlock(&damon_dbgfs_lock);1143	return rc;1144}1145 1146module_init(damon_dbgfs_init);1147 1148#include "tests/dbgfs-kunit.h"1149