File Index
Files and directories
Sign in
FILE

sysfs.c

File preview with syntax highlighting.

linux-6.19.14/mm/damon/sysfs.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * DAMON sysfs Interface
   4 *
   5 * Copyright (c) 2022 SeongJae Park <sj@kernel.org>
   6 */
   7
   8#include <linux/pid.h>
   9#include <linux/sched.h>
  10#include <linux/slab.h>
  11
  12#include "sysfs-common.h"
  13
  14/*
  15 * init region directory
  16 */
  17
  18struct damon_sysfs_region {
  19	struct kobject kobj;
  20	struct damon_addr_range ar;
  21};
  22
  23static struct damon_sysfs_region *damon_sysfs_region_alloc(void)
  24{
  25	return kzalloc(sizeof(struct damon_sysfs_region), GFP_KERNEL);
  26}
  27
  28static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
  29		char *buf)
  30{
  31	struct damon_sysfs_region *region = container_of(kobj,
  32			struct damon_sysfs_region, kobj);
  33
  34	return sysfs_emit(buf, "%lu\n", region->ar.start);
  35}
  36
  37static ssize_t start_store(struct kobject *kobj, struct kobj_attribute *attr,
  38		const char *buf, size_t count)
  39{
  40	struct damon_sysfs_region *region = container_of(kobj,
  41			struct damon_sysfs_region, kobj);
  42	int err = kstrtoul(buf, 0, &region->ar.start);
  43
  44	return err ? err : count;
  45}
  46
  47static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
  48		char *buf)
  49{
  50	struct damon_sysfs_region *region = container_of(kobj,
  51			struct damon_sysfs_region, kobj);
  52
  53	return sysfs_emit(buf, "%lu\n", region->ar.end);
  54}
  55
  56static ssize_t end_store(struct kobject *kobj, struct kobj_attribute *attr,
  57		const char *buf, size_t count)
  58{
  59	struct damon_sysfs_region *region = container_of(kobj,
  60			struct damon_sysfs_region, kobj);
  61	int err = kstrtoul(buf, 0, &region->ar.end);
  62
  63	return err ? err : count;
  64}
  65
  66static void damon_sysfs_region_release(struct kobject *kobj)
  67{
  68	kfree(container_of(kobj, struct damon_sysfs_region, kobj));
  69}
  70
  71static struct kobj_attribute damon_sysfs_region_start_attr =
  72		__ATTR_RW_MODE(start, 0600);
  73
  74static struct kobj_attribute damon_sysfs_region_end_attr =
  75		__ATTR_RW_MODE(end, 0600);
  76
  77static struct attribute *damon_sysfs_region_attrs[] = {
  78	&damon_sysfs_region_start_attr.attr,
  79	&damon_sysfs_region_end_attr.attr,
  80	NULL,
  81};
  82ATTRIBUTE_GROUPS(damon_sysfs_region);
  83
  84static const struct kobj_type damon_sysfs_region_ktype = {
  85	.release = damon_sysfs_region_release,
  86	.sysfs_ops = &kobj_sysfs_ops,
  87	.default_groups = damon_sysfs_region_groups,
  88};
  89
  90/*
  91 * init_regions directory
  92 */
  93
  94struct damon_sysfs_regions {
  95	struct kobject kobj;
  96	struct damon_sysfs_region **regions_arr;
  97	int nr;
  98};
  99
 100static struct damon_sysfs_regions *damon_sysfs_regions_alloc(void)
 101{
 102	return kzalloc(sizeof(struct damon_sysfs_regions), GFP_KERNEL);
 103}
 104
 105static void damon_sysfs_regions_rm_dirs(struct damon_sysfs_regions *regions)
 106{
 107	struct damon_sysfs_region **regions_arr = regions->regions_arr;
 108	int i;
 109
 110	for (i = 0; i < regions->nr; i++)
 111		kobject_put(&regions_arr[i]->kobj);
 112	regions->nr = 0;
 113	kfree(regions_arr);
 114	regions->regions_arr = NULL;
 115}
 116
 117static int damon_sysfs_regions_add_dirs(struct damon_sysfs_regions *regions,
 118		int nr_regions)
 119{
 120	struct damon_sysfs_region **regions_arr, *region;
 121	int err, i;
 122
 123	damon_sysfs_regions_rm_dirs(regions);
 124	if (!nr_regions)
 125		return 0;
 126
 127	regions_arr = kmalloc_array(nr_regions, sizeof(*regions_arr),
 128			GFP_KERNEL | __GFP_NOWARN);
 129	if (!regions_arr)
 130		return -ENOMEM;
 131	regions->regions_arr = regions_arr;
 132
 133	for (i = 0; i < nr_regions; i++) {
 134		region = damon_sysfs_region_alloc();
 135		if (!region) {
 136			damon_sysfs_regions_rm_dirs(regions);
 137			return -ENOMEM;
 138		}
 139
 140		err = kobject_init_and_add(&region->kobj,
 141				&damon_sysfs_region_ktype, &regions->kobj,
 142				"%d", i);
 143		if (err) {
 144			kobject_put(&region->kobj);
 145			damon_sysfs_regions_rm_dirs(regions);
 146			return err;
 147		}
 148
 149		regions_arr[i] = region;
 150		regions->nr++;
 151	}
 152	return 0;
 153}
 154
 155static ssize_t nr_regions_show(struct kobject *kobj,
 156		struct kobj_attribute *attr, char *buf)
 157{
 158	struct damon_sysfs_regions *regions = container_of(kobj,
 159			struct damon_sysfs_regions, kobj);
 160
 161	return sysfs_emit(buf, "%d\n", regions->nr);
 162}
 163
 164static ssize_t nr_regions_store(struct kobject *kobj,
 165		struct kobj_attribute *attr, const char *buf, size_t count)
 166{
 167	struct damon_sysfs_regions *regions;
 168	int nr, err = kstrtoint(buf, 0, &nr);
 169
 170	if (err)
 171		return err;
 172	if (nr < 0)
 173		return -EINVAL;
 174
 175	regions = container_of(kobj, struct damon_sysfs_regions, kobj);
 176
 177	if (!mutex_trylock(&damon_sysfs_lock))
 178		return -EBUSY;
 179	err = damon_sysfs_regions_add_dirs(regions, nr);
 180	mutex_unlock(&damon_sysfs_lock);
 181	if (err)
 182		return err;
 183
 184	return count;
 185}
 186
 187static void damon_sysfs_regions_release(struct kobject *kobj)
 188{
 189	kfree(container_of(kobj, struct damon_sysfs_regions, kobj));
 190}
 191
 192static struct kobj_attribute damon_sysfs_regions_nr_attr =
 193		__ATTR_RW_MODE(nr_regions, 0600);
 194
 195static struct attribute *damon_sysfs_regions_attrs[] = {
 196	&damon_sysfs_regions_nr_attr.attr,
 197	NULL,
 198};
 199ATTRIBUTE_GROUPS(damon_sysfs_regions);
 200
 201static const struct kobj_type damon_sysfs_regions_ktype = {
 202	.release = damon_sysfs_regions_release,
 203	.sysfs_ops = &kobj_sysfs_ops,
 204	.default_groups = damon_sysfs_regions_groups,
 205};
 206
 207/*
 208 * target directory
 209 */
 210
 211struct damon_sysfs_target {
 212	struct kobject kobj;
 213	struct damon_sysfs_regions *regions;
 214	int pid;
 215	bool obsolete;
 216};
 217
 218static struct damon_sysfs_target *damon_sysfs_target_alloc(void)
 219{
 220	return kzalloc(sizeof(struct damon_sysfs_target), GFP_KERNEL);
 221}
 222
 223static int damon_sysfs_target_add_dirs(struct damon_sysfs_target *target)
 224{
 225	struct damon_sysfs_regions *regions = damon_sysfs_regions_alloc();
 226	int err;
 227
 228	if (!regions)
 229		return -ENOMEM;
 230
 231	err = kobject_init_and_add(&regions->kobj, &damon_sysfs_regions_ktype,
 232			&target->kobj, "regions");
 233	if (err)
 234		kobject_put(&regions->kobj);
 235	else
 236		target->regions = regions;
 237	return err;
 238}
 239
 240static void damon_sysfs_target_rm_dirs(struct damon_sysfs_target *target)
 241{
 242	damon_sysfs_regions_rm_dirs(target->regions);
 243	kobject_put(&target->regions->kobj);
 244}
 245
 246static ssize_t pid_target_show(struct kobject *kobj,
 247		struct kobj_attribute *attr, char *buf)
 248{
 249	struct damon_sysfs_target *target = container_of(kobj,
 250			struct damon_sysfs_target, kobj);
 251
 252	return sysfs_emit(buf, "%d\n", target->pid);
 253}
 254
 255static ssize_t pid_target_store(struct kobject *kobj,
 256		struct kobj_attribute *attr, const char *buf, size_t count)
 257{
 258	struct damon_sysfs_target *target = container_of(kobj,
 259			struct damon_sysfs_target, kobj);
 260	int err = kstrtoint(buf, 0, &target->pid);
 261
 262	if (err)
 263		return -EINVAL;
 264	return count;
 265}
 266
 267static ssize_t obsolete_target_show(struct kobject *kobj,
 268		struct kobj_attribute *attr, char *buf)
 269{
 270	struct damon_sysfs_target *target = container_of(kobj,
 271			struct damon_sysfs_target, kobj);
 272
 273	return sysfs_emit(buf, "%c\n", target->obsolete ? 'Y' : 'N');
 274}
 275
 276static ssize_t obsolete_target_store(struct kobject *kobj,
 277		struct kobj_attribute *attr, const char *buf, size_t count)
 278{
 279	struct damon_sysfs_target *target = container_of(kobj,
 280			struct damon_sysfs_target, kobj);
 281	bool obsolete;
 282	int err = kstrtobool(buf, &obsolete);
 283
 284	if (err)
 285		return err;
 286	target->obsolete = obsolete;
 287	return count;
 288}
 289
 290static void damon_sysfs_target_release(struct kobject *kobj)
 291{
 292	kfree(container_of(kobj, struct damon_sysfs_target, kobj));
 293}
 294
 295static struct kobj_attribute damon_sysfs_target_pid_attr =
 296		__ATTR_RW_MODE(pid_target, 0600);
 297
 298static struct kobj_attribute damon_sysfs_target_obsolete_attr =
 299		__ATTR_RW_MODE(obsolete_target, 0600);
 300
 301static struct attribute *damon_sysfs_target_attrs[] = {
 302	&damon_sysfs_target_pid_attr.attr,
 303	&damon_sysfs_target_obsolete_attr.attr,
 304	NULL,
 305};
 306ATTRIBUTE_GROUPS(damon_sysfs_target);
 307
 308static const struct kobj_type damon_sysfs_target_ktype = {
 309	.release = damon_sysfs_target_release,
 310	.sysfs_ops = &kobj_sysfs_ops,
 311	.default_groups = damon_sysfs_target_groups,
 312};
 313
 314/*
 315 * targets directory
 316 */
 317
 318struct damon_sysfs_targets {
 319	struct kobject kobj;
 320	struct damon_sysfs_target **targets_arr;
 321	int nr;
 322};
 323
 324static struct damon_sysfs_targets *damon_sysfs_targets_alloc(void)
 325{
 326	return kzalloc(sizeof(struct damon_sysfs_targets), GFP_KERNEL);
 327}
 328
 329static void damon_sysfs_targets_rm_dirs(struct damon_sysfs_targets *targets)
 330{
 331	struct damon_sysfs_target **targets_arr = targets->targets_arr;
 332	int i;
 333
 334	for (i = 0; i < targets->nr; i++) {
 335		damon_sysfs_target_rm_dirs(targets_arr[i]);
 336		kobject_put(&targets_arr[i]->kobj);
 337	}
 338	targets->nr = 0;
 339	kfree(targets_arr);
 340	targets->targets_arr = NULL;
 341}
 342
 343static int damon_sysfs_targets_add_dirs(struct damon_sysfs_targets *targets,
 344		int nr_targets)
 345{
 346	struct damon_sysfs_target **targets_arr, *target;
 347	int err, i;
 348
 349	damon_sysfs_targets_rm_dirs(targets);
 350	if (!nr_targets)
 351		return 0;
 352
 353	targets_arr = kmalloc_array(nr_targets, sizeof(*targets_arr),
 354			GFP_KERNEL | __GFP_NOWARN);
 355	if (!targets_arr)
 356		return -ENOMEM;
 357	targets->targets_arr = targets_arr;
 358
 359	for (i = 0; i < nr_targets; i++) {
 360		target = damon_sysfs_target_alloc();
 361		if (!target) {
 362			damon_sysfs_targets_rm_dirs(targets);
 363			return -ENOMEM;
 364		}
 365
 366		err = kobject_init_and_add(&target->kobj,
 367				&damon_sysfs_target_ktype, &targets->kobj,
 368				"%d", i);
 369		if (err)
 370			goto out;
 371
 372		err = damon_sysfs_target_add_dirs(target);
 373		if (err)
 374			goto out;
 375
 376		targets_arr[i] = target;
 377		targets->nr++;
 378	}
 379	return 0;
 380
 381out:
 382	damon_sysfs_targets_rm_dirs(targets);
 383	kobject_put(&target->kobj);
 384	return err;
 385}
 386
 387static ssize_t nr_targets_show(struct kobject *kobj,
 388		struct kobj_attribute *attr, char *buf)
 389{
 390	struct damon_sysfs_targets *targets = container_of(kobj,
 391			struct damon_sysfs_targets, kobj);
 392
 393	return sysfs_emit(buf, "%d\n", targets->nr);
 394}
 395
 396static ssize_t nr_targets_store(struct kobject *kobj,
 397		struct kobj_attribute *attr, const char *buf, size_t count)
 398{
 399	struct damon_sysfs_targets *targets;
 400	int nr, err = kstrtoint(buf, 0, &nr);
 401
 402	if (err)
 403		return err;
 404	if (nr < 0)
 405		return -EINVAL;
 406
 407	targets = container_of(kobj, struct damon_sysfs_targets, kobj);
 408
 409	if (!mutex_trylock(&damon_sysfs_lock))
 410		return -EBUSY;
 411	err = damon_sysfs_targets_add_dirs(targets, nr);
 412	mutex_unlock(&damon_sysfs_lock);
 413	if (err)
 414		return err;
 415
 416	return count;
 417}
 418
 419static void damon_sysfs_targets_release(struct kobject *kobj)
 420{
 421	kfree(container_of(kobj, struct damon_sysfs_targets, kobj));
 422}
 423
 424static struct kobj_attribute damon_sysfs_targets_nr_attr =
 425		__ATTR_RW_MODE(nr_targets, 0600);
 426
 427static struct attribute *damon_sysfs_targets_attrs[] = {
 428	&damon_sysfs_targets_nr_attr.attr,
 429	NULL,
 430};
 431ATTRIBUTE_GROUPS(damon_sysfs_targets);
 432
 433static const struct kobj_type damon_sysfs_targets_ktype = {
 434	.release = damon_sysfs_targets_release,
 435	.sysfs_ops = &kobj_sysfs_ops,
 436	.default_groups = damon_sysfs_targets_groups,
 437};
 438
 439/*
 440 * intervals goal directory
 441 */
 442
 443struct damon_sysfs_intervals_goal {
 444	struct kobject kobj;
 445	unsigned long access_bp;
 446	unsigned long aggrs;
 447	unsigned long min_sample_us;
 448	unsigned long max_sample_us;
 449};
 450
 451static struct damon_sysfs_intervals_goal *damon_sysfs_intervals_goal_alloc(
 452		unsigned long access_bp, unsigned long aggrs,
 453		unsigned long min_sample_us, unsigned long max_sample_us)
 454{
 455	struct damon_sysfs_intervals_goal *goal = kmalloc(sizeof(*goal),
 456			GFP_KERNEL);
 457
 458	if (!goal)
 459		return NULL;
 460
 461	goal->kobj = (struct kobject){};
 462	goal->access_bp = access_bp;
 463	goal->aggrs = aggrs;
 464	goal->min_sample_us = min_sample_us;
 465	goal->max_sample_us = max_sample_us;
 466	return goal;
 467}
 468
 469static ssize_t access_bp_show(struct kobject *kobj,
 470		struct kobj_attribute *attr, char *buf)
 471{
 472	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 473			struct damon_sysfs_intervals_goal, kobj);
 474
 475	return sysfs_emit(buf, "%lu\n", goal->access_bp);
 476}
 477
 478static ssize_t access_bp_store(struct kobject *kobj,
 479		struct kobj_attribute *attr, const char *buf, size_t count)
 480{
 481	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 482			struct damon_sysfs_intervals_goal, kobj);
 483	unsigned long nr;
 484	int err = kstrtoul(buf, 0, &nr);
 485
 486	if (err)
 487		return err;
 488
 489	goal->access_bp = nr;
 490	return count;
 491}
 492
 493static ssize_t aggrs_show(struct kobject *kobj,
 494		struct kobj_attribute *attr, char *buf)
 495{
 496	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 497			struct damon_sysfs_intervals_goal, kobj);
 498
 499	return sysfs_emit(buf, "%lu\n", goal->aggrs);
 500}
 501
 502static ssize_t aggrs_store(struct kobject *kobj,
 503		struct kobj_attribute *attr, const char *buf, size_t count)
 504{
 505	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 506			struct damon_sysfs_intervals_goal, kobj);
 507	unsigned long nr;
 508	int err = kstrtoul(buf, 0, &nr);
 509
 510	if (err)
 511		return err;
 512
 513	goal->aggrs = nr;
 514	return count;
 515}
 516
 517static ssize_t min_sample_us_show(struct kobject *kobj,
 518		struct kobj_attribute *attr, char *buf)
 519{
 520	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 521			struct damon_sysfs_intervals_goal, kobj);
 522
 523	return sysfs_emit(buf, "%lu\n", goal->min_sample_us);
 524}
 525
 526static ssize_t min_sample_us_store(struct kobject *kobj,
 527		struct kobj_attribute *attr, const char *buf, size_t count)
 528{
 529	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 530			struct damon_sysfs_intervals_goal, kobj);
 531	unsigned long nr;
 532	int err = kstrtoul(buf, 0, &nr);
 533
 534	if (err)
 535		return err;
 536
 537	goal->min_sample_us = nr;
 538	return count;
 539}
 540
 541static ssize_t max_sample_us_show(struct kobject *kobj,
 542		struct kobj_attribute *attr, char *buf)
 543{
 544	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 545			struct damon_sysfs_intervals_goal, kobj);
 546
 547	return sysfs_emit(buf, "%lu\n", goal->max_sample_us);
 548}
 549
 550static ssize_t max_sample_us_store(struct kobject *kobj,
 551		struct kobj_attribute *attr, const char *buf, size_t count)
 552{
 553	struct damon_sysfs_intervals_goal *goal = container_of(kobj,
 554			struct damon_sysfs_intervals_goal, kobj);
 555	unsigned long nr;
 556	int err = kstrtoul(buf, 0, &nr);
 557
 558	if (err)
 559		return err;
 560
 561	goal->max_sample_us = nr;
 562	return count;
 563}
 564
 565static void damon_sysfs_intervals_goal_release(struct kobject *kobj)
 566{
 567	kfree(container_of(kobj, struct damon_sysfs_intervals_goal, kobj));
 568}
 569
 570static struct kobj_attribute damon_sysfs_intervals_goal_access_bp_attr =
 571		__ATTR_RW_MODE(access_bp, 0600);
 572
 573static struct kobj_attribute damon_sysfs_intervals_goal_aggrs_attr =
 574		__ATTR_RW_MODE(aggrs, 0600);
 575
 576static struct kobj_attribute damon_sysfs_intervals_goal_min_sample_us_attr =
 577		__ATTR_RW_MODE(min_sample_us, 0600);
 578
 579static struct kobj_attribute damon_sysfs_intervals_goal_max_sample_us_attr =
 580		__ATTR_RW_MODE(max_sample_us, 0600);
 581
 582static struct attribute *damon_sysfs_intervals_goal_attrs[] = {
 583	&damon_sysfs_intervals_goal_access_bp_attr.attr,
 584	&damon_sysfs_intervals_goal_aggrs_attr.attr,
 585	&damon_sysfs_intervals_goal_min_sample_us_attr.attr,
 586	&damon_sysfs_intervals_goal_max_sample_us_attr.attr,
 587	NULL,
 588};
 589ATTRIBUTE_GROUPS(damon_sysfs_intervals_goal);
 590
 591static const struct kobj_type damon_sysfs_intervals_goal_ktype = {
 592	.release = damon_sysfs_intervals_goal_release,
 593	.sysfs_ops = &kobj_sysfs_ops,
 594	.default_groups = damon_sysfs_intervals_goal_groups,
 595};
 596
 597/*
 598 * intervals directory
 599 */
 600
 601struct damon_sysfs_intervals {
 602	struct kobject kobj;
 603	unsigned long sample_us;
 604	unsigned long aggr_us;
 605	unsigned long update_us;
 606	struct damon_sysfs_intervals_goal *intervals_goal;
 607};
 608
 609static struct damon_sysfs_intervals *damon_sysfs_intervals_alloc(
 610		unsigned long sample_us, unsigned long aggr_us,
 611		unsigned long update_us)
 612{
 613	struct damon_sysfs_intervals *intervals = kmalloc(sizeof(*intervals),
 614			GFP_KERNEL);
 615
 616	if (!intervals)
 617		return NULL;
 618
 619	intervals->kobj = (struct kobject){};
 620	intervals->sample_us = sample_us;
 621	intervals->aggr_us = aggr_us;
 622	intervals->update_us = update_us;
 623	return intervals;
 624}
 625
 626static int damon_sysfs_intervals_add_dirs(struct damon_sysfs_intervals *intervals)
 627{
 628	struct damon_sysfs_intervals_goal *goal;
 629	int err;
 630
 631	goal = damon_sysfs_intervals_goal_alloc(0, 0, 0, 0);
 632	if (!goal)
 633		return -ENOMEM;
 634
 635	err = kobject_init_and_add(&goal->kobj,
 636			&damon_sysfs_intervals_goal_ktype, &intervals->kobj,
 637			"intervals_goal");
 638	if (err) {
 639		kobject_put(&goal->kobj);
 640		intervals->intervals_goal = NULL;
 641		return err;
 642	}
 643	intervals->intervals_goal = goal;
 644	return 0;
 645}
 646
 647static void damon_sysfs_intervals_rm_dirs(struct damon_sysfs_intervals *intervals)
 648{
 649	kobject_put(&intervals->intervals_goal->kobj);
 650}
 651
 652static ssize_t sample_us_show(struct kobject *kobj,
 653		struct kobj_attribute *attr, char *buf)
 654{
 655	struct damon_sysfs_intervals *intervals = container_of(kobj,
 656			struct damon_sysfs_intervals, kobj);
 657
 658	return sysfs_emit(buf, "%lu\n", intervals->sample_us);
 659}
 660
 661static ssize_t sample_us_store(struct kobject *kobj,
 662		struct kobj_attribute *attr, const char *buf, size_t count)
 663{
 664	struct damon_sysfs_intervals *intervals = container_of(kobj,
 665			struct damon_sysfs_intervals, kobj);
 666	unsigned long us;
 667	int err = kstrtoul(buf, 0, &us);
 668
 669	if (err)
 670		return err;
 671
 672	intervals->sample_us = us;
 673	return count;
 674}
 675
 676static ssize_t aggr_us_show(struct kobject *kobj, struct kobj_attribute *attr,
 677		char *buf)
 678{
 679	struct damon_sysfs_intervals *intervals = container_of(kobj,
 680			struct damon_sysfs_intervals, kobj);
 681
 682	return sysfs_emit(buf, "%lu\n", intervals->aggr_us);
 683}
 684
 685static ssize_t aggr_us_store(struct kobject *kobj, struct kobj_attribute *attr,
 686		const char *buf, size_t count)
 687{
 688	struct damon_sysfs_intervals *intervals = container_of(kobj,
 689			struct damon_sysfs_intervals, kobj);
 690	unsigned long us;
 691	int err = kstrtoul(buf, 0, &us);
 692
 693	if (err)
 694		return err;
 695
 696	intervals->aggr_us = us;
 697	return count;
 698}
 699
 700static ssize_t update_us_show(struct kobject *kobj,
 701		struct kobj_attribute *attr, char *buf)
 702{
 703	struct damon_sysfs_intervals *intervals = container_of(kobj,
 704			struct damon_sysfs_intervals, kobj);
 705
 706	return sysfs_emit(buf, "%lu\n", intervals->update_us);
 707}
 708
 709static ssize_t update_us_store(struct kobject *kobj,
 710		struct kobj_attribute *attr, const char *buf, size_t count)
 711{
 712	struct damon_sysfs_intervals *intervals = container_of(kobj,
 713			struct damon_sysfs_intervals, kobj);
 714	unsigned long us;
 715	int err = kstrtoul(buf, 0, &us);
 716
 717	if (err)
 718		return err;
 719
 720	intervals->update_us = us;
 721	return count;
 722}
 723
 724static void damon_sysfs_intervals_release(struct kobject *kobj)
 725{
 726	kfree(container_of(kobj, struct damon_sysfs_intervals, kobj));
 727}
 728
 729static struct kobj_attribute damon_sysfs_intervals_sample_us_attr =
 730		__ATTR_RW_MODE(sample_us, 0600);
 731
 732static struct kobj_attribute damon_sysfs_intervals_aggr_us_attr =
 733		__ATTR_RW_MODE(aggr_us, 0600);
 734
 735static struct kobj_attribute damon_sysfs_intervals_update_us_attr =
 736		__ATTR_RW_MODE(update_us, 0600);
 737
 738static struct attribute *damon_sysfs_intervals_attrs[] = {
 739	&damon_sysfs_intervals_sample_us_attr.attr,
 740	&damon_sysfs_intervals_aggr_us_attr.attr,
 741	&damon_sysfs_intervals_update_us_attr.attr,
 742	NULL,
 743};
 744ATTRIBUTE_GROUPS(damon_sysfs_intervals);
 745
 746static const struct kobj_type damon_sysfs_intervals_ktype = {
 747	.release = damon_sysfs_intervals_release,
 748	.sysfs_ops = &kobj_sysfs_ops,
 749	.default_groups = damon_sysfs_intervals_groups,
 750};
 751
 752/*
 753 * monitoring_attrs directory
 754 */
 755
 756struct damon_sysfs_attrs {
 757	struct kobject kobj;
 758	struct damon_sysfs_intervals *intervals;
 759	struct damon_sysfs_ul_range *nr_regions_range;
 760};
 761
 762static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
 763{
 764	struct damon_sysfs_attrs *attrs = kmalloc(sizeof(*attrs), GFP_KERNEL);
 765
 766	if (!attrs)
 767		return NULL;
 768	attrs->kobj = (struct kobject){};
 769	return attrs;
 770}
 771
 772static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
 773{
 774	struct damon_sysfs_intervals *intervals;
 775	struct damon_sysfs_ul_range *nr_regions_range;
 776	int err;
 777
 778	intervals = damon_sysfs_intervals_alloc(5000, 100000, 60000000);
 779	if (!intervals)
 780		return -ENOMEM;
 781
 782	err = kobject_init_and_add(&intervals->kobj,
 783			&damon_sysfs_intervals_ktype, &attrs->kobj,
 784			"intervals");
 785	if (err)
 786		goto put_intervals_out;
 787	err = damon_sysfs_intervals_add_dirs(intervals);
 788	if (err)
 789		goto put_intervals_out;
 790	attrs->intervals = intervals;
 791
 792	nr_regions_range = damon_sysfs_ul_range_alloc(10, 1000);
 793	if (!nr_regions_range) {
 794		err = -ENOMEM;
 795		goto rmdir_put_intervals_out;
 796	}
 797
 798	err = kobject_init_and_add(&nr_regions_range->kobj,
 799			&damon_sysfs_ul_range_ktype, &attrs->kobj,
 800			"nr_regions");
 801	if (err)
 802		goto put_nr_regions_intervals_out;
 803	attrs->nr_regions_range = nr_regions_range;
 804	return 0;
 805
 806put_nr_regions_intervals_out:
 807	kobject_put(&nr_regions_range->kobj);
 808	attrs->nr_regions_range = NULL;
 809rmdir_put_intervals_out:
 810	damon_sysfs_intervals_rm_dirs(intervals);
 811put_intervals_out:
 812	kobject_put(&intervals->kobj);
 813	attrs->intervals = NULL;
 814	return err;
 815}
 816
 817static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
 818{
 819	kobject_put(&attrs->nr_regions_range->kobj);
 820	damon_sysfs_intervals_rm_dirs(attrs->intervals);
 821	kobject_put(&attrs->intervals->kobj);
 822}
 823
 824static void damon_sysfs_attrs_release(struct kobject *kobj)
 825{
 826	kfree(container_of(kobj, struct damon_sysfs_attrs, kobj));
 827}
 828
 829static struct attribute *damon_sysfs_attrs_attrs[] = {
 830	NULL,
 831};
 832ATTRIBUTE_GROUPS(damon_sysfs_attrs);
 833
 834static const struct kobj_type damon_sysfs_attrs_ktype = {
 835	.release = damon_sysfs_attrs_release,
 836	.sysfs_ops = &kobj_sysfs_ops,
 837	.default_groups = damon_sysfs_attrs_groups,
 838};
 839
 840/*
 841 * context directory
 842 */
 843
 844struct damon_sysfs_ops_name {
 845	enum damon_ops_id ops_id;
 846	char *name;
 847};
 848
 849static const struct damon_sysfs_ops_name damon_sysfs_ops_names[] = {
 850	{
 851		.ops_id = DAMON_OPS_VADDR,
 852		.name = "vaddr",
 853	},
 854	{
 855		.ops_id = DAMON_OPS_FVADDR,
 856		.name = "fvaddr",
 857	},
 858	{
 859		.ops_id = DAMON_OPS_PADDR,
 860		.name = "paddr",
 861	},
 862};
 863
 864struct damon_sysfs_context {
 865	struct kobject kobj;
 866	enum damon_ops_id ops_id;
 867	unsigned long addr_unit;
 868	struct damon_sysfs_attrs *attrs;
 869	struct damon_sysfs_targets *targets;
 870	struct damon_sysfs_schemes *schemes;
 871};
 872
 873static struct damon_sysfs_context *damon_sysfs_context_alloc(
 874		enum damon_ops_id ops_id)
 875{
 876	struct damon_sysfs_context *context = kmalloc(sizeof(*context),
 877				GFP_KERNEL);
 878
 879	if (!context)
 880		return NULL;
 881	context->kobj = (struct kobject){};
 882	context->ops_id = ops_id;
 883	context->addr_unit = 1;
 884	return context;
 885}
 886
 887static int damon_sysfs_context_set_attrs(struct damon_sysfs_context *context)
 888{
 889	struct damon_sysfs_attrs *attrs = damon_sysfs_attrs_alloc();
 890	int err;
 891
 892	if (!attrs)
 893		return -ENOMEM;
 894	err = kobject_init_and_add(&attrs->kobj, &damon_sysfs_attrs_ktype,
 895			&context->kobj, "monitoring_attrs");
 896	if (err)
 897		goto out;
 898	err = damon_sysfs_attrs_add_dirs(attrs);
 899	if (err)
 900		goto out;
 901	context->attrs = attrs;
 902	return 0;
 903
 904out:
 905	kobject_put(&attrs->kobj);
 906	return err;
 907}
 908
 909static int damon_sysfs_context_set_targets(struct damon_sysfs_context *context)
 910{
 911	struct damon_sysfs_targets *targets = damon_sysfs_targets_alloc();
 912	int err;
 913
 914	if (!targets)
 915		return -ENOMEM;
 916	err = kobject_init_and_add(&targets->kobj, &damon_sysfs_targets_ktype,
 917			&context->kobj, "targets");
 918	if (err) {
 919		kobject_put(&targets->kobj);
 920		return err;
 921	}
 922	context->targets = targets;
 923	return 0;
 924}
 925
 926static int damon_sysfs_context_set_schemes(struct damon_sysfs_context *context)
 927{
 928	struct damon_sysfs_schemes *schemes = damon_sysfs_schemes_alloc();
 929	int err;
 930
 931	if (!schemes)
 932		return -ENOMEM;
 933	err = kobject_init_and_add(&schemes->kobj, &damon_sysfs_schemes_ktype,
 934			&context->kobj, "schemes");
 935	if (err) {
 936		kobject_put(&schemes->kobj);
 937		return err;
 938	}
 939	context->schemes = schemes;
 940	return 0;
 941}
 942
 943static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
 944{
 945	int err;
 946
 947	err = damon_sysfs_context_set_attrs(context);
 948	if (err)
 949		return err;
 950
 951	err = damon_sysfs_context_set_targets(context);
 952	if (err)
 953		goto rmdir_put_attrs_out;
 954
 955	err = damon_sysfs_context_set_schemes(context);
 956	if (err)
 957		goto put_targets_attrs_out;
 958	return 0;
 959
 960put_targets_attrs_out:
 961	kobject_put(&context->targets->kobj);
 962	context->targets = NULL;
 963rmdir_put_attrs_out:
 964	damon_sysfs_attrs_rm_dirs(context->attrs);
 965	kobject_put(&context->attrs->kobj);
 966	context->attrs = NULL;
 967	return err;
 968}
 969
 970static void damon_sysfs_context_rm_dirs(struct damon_sysfs_context *context)
 971{
 972	damon_sysfs_attrs_rm_dirs(context->attrs);
 973	kobject_put(&context->attrs->kobj);
 974	damon_sysfs_targets_rm_dirs(context->targets);
 975	kobject_put(&context->targets->kobj);
 976	damon_sysfs_schemes_rm_dirs(context->schemes);
 977	kobject_put(&context->schemes->kobj);
 978}
 979
 980static ssize_t avail_operations_show(struct kobject *kobj,
 981		struct kobj_attribute *attr, char *buf)
 982{
 983	int len = 0;
 984	int i;
 985
 986	for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
 987		const struct damon_sysfs_ops_name *ops_name;
 988
 989		ops_name = &damon_sysfs_ops_names[i];
 990		if (!damon_is_registered_ops(ops_name->ops_id))
 991			continue;
 992		len += sysfs_emit_at(buf, len, "%s\n", ops_name->name);
 993	}
 994	return len;
 995}
 996
 997static ssize_t operations_show(struct kobject *kobj,
 998		struct kobj_attribute *attr, char *buf)
 999{
1000	struct damon_sysfs_context *context = container_of(kobj,
1001			struct damon_sysfs_context, kobj);
1002	int i;
1003
1004	for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
1005		const struct damon_sysfs_ops_name *ops_name;
1006
1007		ops_name = &damon_sysfs_ops_names[i];
1008		if (ops_name->ops_id == context->ops_id)
1009			return sysfs_emit(buf, "%s\n", ops_name->name);
1010	}
1011	return -EINVAL;
1012}
1013
1014static ssize_t operations_store(struct kobject *kobj,
1015		struct kobj_attribute *attr, const char *buf, size_t count)
1016{
1017	struct damon_sysfs_context *context = container_of(kobj,
1018			struct damon_sysfs_context, kobj);
1019	int i;
1020
1021	for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
1022		const struct damon_sysfs_ops_name *ops_name;
1023
1024		ops_name = &damon_sysfs_ops_names[i];
1025		if (sysfs_streq(buf, ops_name->name)) {
1026			context->ops_id = ops_name->ops_id;
1027			return count;
1028		}
1029	}
1030	return -EINVAL;
1031}
1032
1033static ssize_t addr_unit_show(struct kobject *kobj,
1034		struct kobj_attribute *attr, char *buf)
1035{
1036	struct damon_sysfs_context *context = container_of(kobj,
1037			struct damon_sysfs_context, kobj);
1038
1039	return sysfs_emit(buf, "%lu\n", context->addr_unit);
1040}
1041
1042static ssize_t addr_unit_store(struct kobject *kobj,
1043		struct kobj_attribute *attr, const char *buf, size_t count)
1044{
1045	struct damon_sysfs_context *context = container_of(kobj,
1046			struct damon_sysfs_context, kobj);
1047	unsigned long input_addr_unit;
1048	int err = kstrtoul(buf, 0, &input_addr_unit);
1049
1050	if (err)
1051		return err;
1052	if (!input_addr_unit)
1053		return -EINVAL;
1054
1055	context->addr_unit = input_addr_unit;
1056	return count;
1057}
1058
1059static void damon_sysfs_context_release(struct kobject *kobj)
1060{
1061	kfree(container_of(kobj, struct damon_sysfs_context, kobj));
1062}
1063
1064static struct kobj_attribute damon_sysfs_context_avail_operations_attr =
1065		__ATTR_RO_MODE(avail_operations, 0400);
1066
1067static struct kobj_attribute damon_sysfs_context_operations_attr =
1068		__ATTR_RW_MODE(operations, 0600);
1069
1070static struct kobj_attribute damon_sysfs_context_addr_unit_attr =
1071		__ATTR_RW_MODE(addr_unit, 0600);
1072
1073static struct attribute *damon_sysfs_context_attrs[] = {
1074	&damon_sysfs_context_avail_operations_attr.attr,
1075	&damon_sysfs_context_operations_attr.attr,
1076	&damon_sysfs_context_addr_unit_attr.attr,
1077	NULL,
1078};
1079ATTRIBUTE_GROUPS(damon_sysfs_context);
1080
1081static const struct kobj_type damon_sysfs_context_ktype = {
1082	.release = damon_sysfs_context_release,
1083	.sysfs_ops = &kobj_sysfs_ops,
1084	.default_groups = damon_sysfs_context_groups,
1085};
1086
1087/*
1088 * contexts directory
1089 */
1090
1091struct damon_sysfs_contexts {
1092	struct kobject kobj;
1093	struct damon_sysfs_context **contexts_arr;
1094	int nr;
1095};
1096
1097static struct damon_sysfs_contexts *damon_sysfs_contexts_alloc(void)
1098{
1099	return kzalloc(sizeof(struct damon_sysfs_contexts), GFP_KERNEL);
1100}
1101
1102static void damon_sysfs_contexts_rm_dirs(struct damon_sysfs_contexts *contexts)
1103{
1104	struct damon_sysfs_context **contexts_arr = contexts->contexts_arr;
1105	int i;
1106
1107	for (i = 0; i < contexts->nr; i++) {
1108		damon_sysfs_context_rm_dirs(contexts_arr[i]);
1109		kobject_put(&contexts_arr[i]->kobj);
1110	}
1111	contexts->nr = 0;
1112	kfree(contexts_arr);
1113	contexts->contexts_arr = NULL;
1114}
1115
1116static int damon_sysfs_contexts_add_dirs(struct damon_sysfs_contexts *contexts,
1117		int nr_contexts)
1118{
1119	struct damon_sysfs_context **contexts_arr, *context;
1120	int err, i;
1121
1122	damon_sysfs_contexts_rm_dirs(contexts);
1123	if (!nr_contexts)
1124		return 0;
1125
1126	contexts_arr = kmalloc_array(nr_contexts, sizeof(*contexts_arr),
1127			GFP_KERNEL | __GFP_NOWARN);
1128	if (!contexts_arr)
1129		return -ENOMEM;
1130	contexts->contexts_arr = contexts_arr;
1131
1132	for (i = 0; i < nr_contexts; i++) {
1133		context = damon_sysfs_context_alloc(DAMON_OPS_VADDR);
1134		if (!context) {
1135			damon_sysfs_contexts_rm_dirs(contexts);
1136			return -ENOMEM;
1137		}
1138
1139		err = kobject_init_and_add(&context->kobj,
1140				&damon_sysfs_context_ktype, &contexts->kobj,
1141				"%d", i);
1142		if (err)
1143			goto out;
1144
1145		err = damon_sysfs_context_add_dirs(context);
1146		if (err)
1147			goto out;
1148
1149		contexts_arr[i] = context;
1150		contexts->nr++;
1151	}
1152	return 0;
1153
1154out:
1155	damon_sysfs_contexts_rm_dirs(contexts);
1156	kobject_put(&context->kobj);
1157	return err;
1158}
1159
1160static ssize_t nr_contexts_show(struct kobject *kobj,
1161		struct kobj_attribute *attr, char *buf)
1162{
1163	struct damon_sysfs_contexts *contexts = container_of(kobj,
1164			struct damon_sysfs_contexts, kobj);
1165
1166	return sysfs_emit(buf, "%d\n", contexts->nr);
1167}
1168
1169static ssize_t nr_contexts_store(struct kobject *kobj,
1170		struct kobj_attribute *attr, const char *buf, size_t count)
1171{
1172	struct damon_sysfs_contexts *contexts;
1173	int nr, err;
1174
1175	err = kstrtoint(buf, 0, &nr);
1176	if (err)
1177		return err;
1178	/* TODO: support multiple contexts per kdamond */
1179	if (nr < 0 || 1 < nr)
1180		return -EINVAL;
1181
1182	contexts = container_of(kobj, struct damon_sysfs_contexts, kobj);
1183	if (!mutex_trylock(&damon_sysfs_lock))
1184		return -EBUSY;
1185	err = damon_sysfs_contexts_add_dirs(contexts, nr);
1186	mutex_unlock(&damon_sysfs_lock);
1187	if (err)
1188		return err;
1189
1190	return count;
1191}
1192
1193static void damon_sysfs_contexts_release(struct kobject *kobj)
1194{
1195	kfree(container_of(kobj, struct damon_sysfs_contexts, kobj));
1196}
1197
1198static struct kobj_attribute damon_sysfs_contexts_nr_attr
1199		= __ATTR_RW_MODE(nr_contexts, 0600);
1200
1201static struct attribute *damon_sysfs_contexts_attrs[] = {
1202	&damon_sysfs_contexts_nr_attr.attr,
1203	NULL,
1204};
1205ATTRIBUTE_GROUPS(damon_sysfs_contexts);
1206
1207static const struct kobj_type damon_sysfs_contexts_ktype = {
1208	.release = damon_sysfs_contexts_release,
1209	.sysfs_ops = &kobj_sysfs_ops,
1210	.default_groups = damon_sysfs_contexts_groups,
1211};
1212
1213/*
1214 * kdamond directory
1215 */
1216
1217struct damon_sysfs_kdamond {
1218	struct kobject kobj;
1219	struct damon_sysfs_contexts *contexts;
1220	struct damon_ctx *damon_ctx;
1221	unsigned int refresh_ms;
1222};
1223
1224static struct damon_sysfs_kdamond *damon_sysfs_kdamond_alloc(void)
1225{
1226	return kzalloc(sizeof(struct damon_sysfs_kdamond), GFP_KERNEL);
1227}
1228
1229static int damon_sysfs_kdamond_add_dirs(struct damon_sysfs_kdamond *kdamond)
1230{
1231	struct damon_sysfs_contexts *contexts;
1232	int err;
1233
1234	contexts = damon_sysfs_contexts_alloc();
1235	if (!contexts)
1236		return -ENOMEM;
1237
1238	err = kobject_init_and_add(&contexts->kobj,
1239			&damon_sysfs_contexts_ktype, &kdamond->kobj,
1240			"contexts");
1241	if (err) {
1242		kobject_put(&contexts->kobj);
1243		return err;
1244	}
1245	kdamond->contexts = contexts;
1246
1247	return err;
1248}
1249
1250static void damon_sysfs_kdamond_rm_dirs(struct damon_sysfs_kdamond *kdamond)
1251{
1252	damon_sysfs_contexts_rm_dirs(kdamond->contexts);
1253	kobject_put(&kdamond->contexts->kobj);
1254}
1255
1256/*
1257 * enum damon_sysfs_cmd - Commands for a specific kdamond.
1258 */
1259enum damon_sysfs_cmd {
1260	/* @DAMON_SYSFS_CMD_ON: Turn the kdamond on. */
1261	DAMON_SYSFS_CMD_ON,
1262	/* @DAMON_SYSFS_CMD_OFF: Turn the kdamond off. */
1263	DAMON_SYSFS_CMD_OFF,
1264	/* @DAMON_SYSFS_CMD_COMMIT: Update kdamond inputs. */
1265	DAMON_SYSFS_CMD_COMMIT,
1266	/*
1267	 * @DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS: Commit the quota goals
1268	 * to DAMON.
1269	 */
1270	DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS,
1271	/*
1272	 * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS: Update scheme stats sysfs
1273	 * files.
1274	 */
1275	DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS,
1276	/*
1277	 * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES: Update
1278	 * tried_regions/total_bytes sysfs files for each scheme.
1279	 */
1280	DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES,
1281	/*
1282	 * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS: Update schemes tried
1283	 * regions
1284	 */
1285	DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS,
1286	/*
1287	 * @DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS: Clear schemes tried
1288	 * regions
1289	 */
1290	DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS,
1291	/*
1292	 * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS: Update the
1293	 * effective size quota of the scheme in bytes.
1294	 */
1295	DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS,
1296	/*
1297	 * @DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS: Update the tuned monitoring
1298	 * intervals.
1299	 */
1300	DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS,
1301	/*
1302	 * @NR_DAMON_SYSFS_CMDS: Total number of DAMON sysfs commands.
1303	 */
1304	NR_DAMON_SYSFS_CMDS,
1305};
1306
1307/* Should match with enum damon_sysfs_cmd */
1308static const char * const damon_sysfs_cmd_strs[] = {
1309	"on",
1310	"off",
1311	"commit",
1312	"commit_schemes_quota_goals",
1313	"update_schemes_stats",
1314	"update_schemes_tried_bytes",
1315	"update_schemes_tried_regions",
1316	"clear_schemes_tried_regions",
1317	"update_schemes_effective_quotas",
1318	"update_tuned_intervals",
1319};
1320
1321static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
1322		char *buf)
1323{
1324	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1325			struct damon_sysfs_kdamond, kobj);
1326	struct damon_ctx *ctx;
1327	bool running = false;
1328
1329	if (!mutex_trylock(&damon_sysfs_lock))
1330		return -EBUSY;
1331
1332	ctx = kdamond->damon_ctx;
1333	if (ctx)
1334		running = damon_is_running(ctx);
1335
1336	mutex_unlock(&damon_sysfs_lock);
1337
1338	return sysfs_emit(buf, "%s\n", running ?
1339			damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_ON] :
1340			damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_OFF]);
1341}
1342
1343static int damon_sysfs_set_attrs(struct damon_ctx *ctx,
1344		struct damon_sysfs_attrs *sys_attrs)
1345{
1346	struct damon_sysfs_intervals *sys_intervals = sys_attrs->intervals;
1347	struct damon_sysfs_intervals_goal *sys_goal =
1348		sys_intervals->intervals_goal;
1349	struct damon_sysfs_ul_range *sys_nr_regions =
1350		sys_attrs->nr_regions_range;
1351	struct damon_attrs attrs = {
1352		.sample_interval = sys_intervals->sample_us,
1353		.aggr_interval = sys_intervals->aggr_us,
1354		.intervals_goal = {
1355			.access_bp = sys_goal->access_bp,
1356			.aggrs = sys_goal->aggrs,
1357			.min_sample_us = sys_goal->min_sample_us,
1358			.max_sample_us = sys_goal->max_sample_us},
1359		.ops_update_interval = sys_intervals->update_us,
1360		.min_nr_regions = sys_nr_regions->min,
1361		.max_nr_regions = sys_nr_regions->max,
1362	};
1363	return damon_set_attrs(ctx, &attrs);
1364}
1365
1366static int damon_sysfs_set_regions(struct damon_target *t,
1367		struct damon_sysfs_regions *sysfs_regions,
1368		unsigned long min_region_sz)
1369{
1370	struct damon_addr_range *ranges = kmalloc_array(sysfs_regions->nr,
1371			sizeof(*ranges), GFP_KERNEL | __GFP_NOWARN);
1372	int i, err = -EINVAL;
1373
1374	if (!ranges)
1375		return -ENOMEM;
1376	for (i = 0; i < sysfs_regions->nr; i++) {
1377		struct damon_sysfs_region *sys_region =
1378			sysfs_regions->regions_arr[i];
1379
1380		if (sys_region->ar.start > sys_region->ar.end)
1381			goto out;
1382
1383		ranges[i].start = sys_region->ar.start;
1384		ranges[i].end = sys_region->ar.end;
1385		if (i == 0)
1386			continue;
1387		if (ranges[i - 1].end > ranges[i].start)
1388			goto out;
1389	}
1390	err = damon_set_regions(t, ranges, sysfs_regions->nr, min_region_sz);
1391out:
1392	kfree(ranges);
1393	return err;
1394
1395}
1396
1397static int damon_sysfs_add_target(struct damon_sysfs_target *sys_target,
1398		struct damon_ctx *ctx)
1399{
1400	struct damon_target *t = damon_new_target();
1401
1402	if (!t)
1403		return -ENOMEM;
1404	damon_add_target(ctx, t);
1405	if (damon_target_has_pid(ctx)) {
1406		t->pid = find_get_pid(sys_target->pid);
1407		if (!t->pid)
1408			/* caller will destroy targets */
1409			return -EINVAL;
1410	}
1411	t->obsolete = sys_target->obsolete;
1412	return damon_sysfs_set_regions(t, sys_target->regions,
1413			ctx->min_region_sz);
1414}
1415
1416static int damon_sysfs_add_targets(struct damon_ctx *ctx,
1417		struct damon_sysfs_targets *sysfs_targets)
1418{
1419	int i, err;
1420
1421	/* Multiple physical address space monitoring targets makes no sense */
1422	if (ctx->ops.id == DAMON_OPS_PADDR && sysfs_targets->nr > 1)
1423		return -EINVAL;
1424
1425	for (i = 0; i < sysfs_targets->nr; i++) {
1426		struct damon_sysfs_target *st = sysfs_targets->targets_arr[i];
1427
1428		err = damon_sysfs_add_target(st, ctx);
1429		if (err)
1430			return err;
1431	}
1432	return 0;
1433}
1434
1435/*
1436 * damon_sysfs_upd_schemes_stats() - Update schemes stats sysfs files.
1437 * @data:	The kobject wrapper that associated to the kdamond thread.
1438 *
1439 * This function reads the schemes stats of specific kdamond and update the
1440 * related values for sysfs files.  This function should be called from DAMON
1441 * worker thread,to safely access the DAMON contexts-internal data.  Caller
1442 * should also ensure holding ``damon_syfs_lock``, and ->damon_ctx of @data is
1443 * not NULL but a valid pointer, to safely access DAMON sysfs variables.
1444 */
1445static int damon_sysfs_upd_schemes_stats(void *data)
1446{
1447	struct damon_sysfs_kdamond *kdamond = data;
1448	struct damon_ctx *ctx = kdamond->damon_ctx;
1449
1450	damon_sysfs_schemes_update_stats(
1451			kdamond->contexts->contexts_arr[0]->schemes, ctx);
1452	return 0;
1453}
1454
1455static inline bool damon_sysfs_kdamond_running(
1456		struct damon_sysfs_kdamond *kdamond)
1457{
1458	return kdamond->damon_ctx &&
1459		damon_is_running(kdamond->damon_ctx);
1460}
1461
1462static int damon_sysfs_apply_inputs(struct damon_ctx *ctx,
1463		struct damon_sysfs_context *sys_ctx)
1464{
1465	int err;
1466
1467	err = damon_select_ops(ctx, sys_ctx->ops_id);
1468	if (err)
1469		return err;
1470	ctx->addr_unit = sys_ctx->addr_unit;
1471	/* addr_unit is respected by only DAMON_OPS_PADDR */
1472	if (sys_ctx->ops_id == DAMON_OPS_PADDR)
1473		ctx->min_region_sz = max(
1474				DAMON_MIN_REGION_SZ / sys_ctx->addr_unit, 1);
1475	err = damon_sysfs_set_attrs(ctx, sys_ctx->attrs);
1476	if (err)
1477		return err;
1478	err = damon_sysfs_add_targets(ctx, sys_ctx->targets);
1479	if (err)
1480		return err;
1481	return damon_sysfs_add_schemes(ctx, sys_ctx->schemes);
1482}
1483
1484static struct damon_ctx *damon_sysfs_build_ctx(
1485		struct damon_sysfs_context *sys_ctx);
1486
1487/*
1488 * Return a new damon_ctx for testing new parameters to commit.
1489 */
1490static struct damon_ctx *damon_sysfs_new_test_ctx(
1491		struct damon_ctx *running_ctx)
1492{
1493	struct damon_ctx *test_ctx;
1494	int err;
1495
1496	test_ctx = damon_new_ctx();
1497	if (!test_ctx)
1498		return NULL;
1499	err = damon_commit_ctx(test_ctx, running_ctx);
1500	if (err) {
1501		damon_destroy_ctx(test_ctx);
1502		return NULL;
1503	}
1504	return test_ctx;
1505}
1506
1507/*
1508 * damon_sysfs_commit_input() - Commit user inputs to a running kdamond.
1509 * @kdamond:	The kobject wrapper for the associated kdamond.
1510 *
1511 * Returns error if the sysfs input is wrong.
1512 */
1513static int damon_sysfs_commit_input(void *data)
1514{
1515	struct damon_sysfs_kdamond *kdamond = data;
1516	struct damon_ctx *param_ctx, *test_ctx;
1517	int err;
1518
1519	if (!damon_sysfs_kdamond_running(kdamond))
1520		return -EINVAL;
1521	/* TODO: Support multiple contexts per kdamond */
1522	if (kdamond->contexts->nr != 1)
1523		return -EINVAL;
1524
1525	param_ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
1526	if (IS_ERR(param_ctx))
1527		return PTR_ERR(param_ctx);
1528	test_ctx = damon_sysfs_new_test_ctx(kdamond->damon_ctx);
1529	if (!test_ctx) {
1530		damon_destroy_ctx(param_ctx);
1531		return -ENOMEM;
1532	}
1533	err = damon_commit_ctx(test_ctx, param_ctx);
1534	if (err)
1535		goto out;
1536	err = damon_commit_ctx(kdamond->damon_ctx, param_ctx);
1537out:
1538	damon_destroy_ctx(test_ctx);
1539	damon_destroy_ctx(param_ctx);
1540	return err;
1541}
1542
1543static int damon_sysfs_commit_schemes_quota_goals(void *data)
1544{
1545	struct damon_sysfs_kdamond *sysfs_kdamond = data;
1546	struct damon_ctx *ctx;
1547	struct damon_sysfs_context *sysfs_ctx;
1548
1549	if (!damon_sysfs_kdamond_running(sysfs_kdamond))
1550		return -EINVAL;
1551	/* TODO: Support multiple contexts per kdamond */
1552	if (sysfs_kdamond->contexts->nr != 1)
1553		return -EINVAL;
1554
1555	ctx = sysfs_kdamond->damon_ctx;
1556	sysfs_ctx = sysfs_kdamond->contexts->contexts_arr[0];
1557	return damos_sysfs_set_quota_scores(sysfs_ctx->schemes, ctx);
1558}
1559
1560/*
1561 * damon_sysfs_upd_schemes_effective_quotas() - Update schemes effective quotas
1562 * sysfs files.
1563 * @data:	The kobject wrapper that associated to the kdamond thread.
1564 *
1565 * This function reads the schemes' effective quotas of specific kdamond and
1566 * update the related values for sysfs files.  This function should be called
1567 * from DAMON callbacks while holding ``damon_syfs_lock``, to safely access the
1568 * DAMON contexts-internal data and DAMON sysfs variables.
1569 */
1570static int damon_sysfs_upd_schemes_effective_quotas(void *data)
1571{
1572	struct damon_sysfs_kdamond *kdamond = data;
1573	struct damon_ctx *ctx = kdamond->damon_ctx;
1574
1575	damos_sysfs_update_effective_quotas(
1576			kdamond->contexts->contexts_arr[0]->schemes, ctx);
1577	return 0;
1578}
1579
1580static int damon_sysfs_upd_tuned_intervals(void *data)
1581{
1582	struct damon_sysfs_kdamond *kdamond = data;
1583	struct damon_ctx *ctx = kdamond->damon_ctx;
1584
1585	kdamond->contexts->contexts_arr[0]->attrs->intervals->sample_us =
1586		ctx->attrs.sample_interval;
1587	kdamond->contexts->contexts_arr[0]->attrs->intervals->aggr_us =
1588		ctx->attrs.aggr_interval;
1589	return 0;
1590}
1591
1592static struct damon_ctx *damon_sysfs_build_ctx(
1593		struct damon_sysfs_context *sys_ctx)
1594{
1595	struct damon_ctx *ctx = damon_new_ctx();
1596	int err;
1597
1598	if (!ctx)
1599		return ERR_PTR(-ENOMEM);
1600
1601	err = damon_sysfs_apply_inputs(ctx, sys_ctx);
1602	if (err) {
1603		damon_destroy_ctx(ctx);
1604		return ERR_PTR(err);
1605	}
1606
1607	return ctx;
1608}
1609
1610static unsigned long damon_sysfs_next_update_jiffies;
1611
1612static int damon_sysfs_repeat_call_fn(void *data)
1613{
1614	struct damon_sysfs_kdamond *sysfs_kdamond = data;
1615
1616	if (!sysfs_kdamond->refresh_ms)
1617		return 0;
1618	if (time_before(jiffies, damon_sysfs_next_update_jiffies))
1619		return 0;
1620	damon_sysfs_next_update_jiffies = jiffies +
1621		msecs_to_jiffies(sysfs_kdamond->refresh_ms);
1622
1623	if (!mutex_trylock(&damon_sysfs_lock))
1624		return 0;
1625	if (sysfs_kdamond->contexts->nr != 1)
1626		goto out;
1627	damon_sysfs_upd_tuned_intervals(sysfs_kdamond);
1628	damon_sysfs_upd_schemes_stats(sysfs_kdamond);
1629	damon_sysfs_upd_schemes_effective_quotas(sysfs_kdamond);
1630out:
1631	mutex_unlock(&damon_sysfs_lock);
1632	return 0;
1633}
1634
1635static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
1636{
1637	struct damon_ctx *ctx;
1638	struct damon_call_control *repeat_call_control;
1639	int err;
1640
1641	if (damon_sysfs_kdamond_running(kdamond))
1642		return -EBUSY;
1643	/* TODO: support multiple contexts per kdamond */
1644	if (kdamond->contexts->nr != 1)
1645		return -EINVAL;
1646
1647	if (kdamond->damon_ctx)
1648		damon_destroy_ctx(kdamond->damon_ctx);
1649	kdamond->damon_ctx = NULL;
1650
1651	repeat_call_control = kmalloc(sizeof(*repeat_call_control),
1652			GFP_KERNEL);
1653	if (!repeat_call_control)
1654		return -ENOMEM;
1655
1656	ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
1657	if (IS_ERR(ctx)) {
1658		kfree(repeat_call_control);
1659		return PTR_ERR(ctx);
1660	}
1661	err = damon_start(&ctx, 1, false);
1662	if (err) {
1663		kfree(repeat_call_control);
1664		damon_destroy_ctx(ctx);
1665		return err;
1666	}
1667	kdamond->damon_ctx = ctx;
1668
1669	damon_sysfs_next_update_jiffies =
1670		jiffies + msecs_to_jiffies(kdamond->refresh_ms);
1671
1672	repeat_call_control->fn = damon_sysfs_repeat_call_fn;
1673	repeat_call_control->data = kdamond;
1674	repeat_call_control->repeat = true;
1675	repeat_call_control->dealloc_on_cancel = true;
1676	if (damon_call(ctx, repeat_call_control))
1677		kfree(repeat_call_control);
1678	return err;
1679}
1680
1681static int damon_sysfs_turn_damon_off(struct damon_sysfs_kdamond *kdamond)
1682{
1683	if (!kdamond->damon_ctx)
1684		return -EINVAL;
1685	return damon_stop(&kdamond->damon_ctx, 1);
1686	/*
1687	 * To allow users show final monitoring results of already turned-off
1688	 * DAMON, we free kdamond->damon_ctx in next
1689	 * damon_sysfs_turn_damon_on(), or kdamonds_nr_store()
1690	 */
1691}
1692
1693static int damon_sysfs_damon_call(int (*fn)(void *data),
1694		struct damon_sysfs_kdamond *kdamond)
1695{
1696	struct damon_call_control call_control = {};
1697	int err;
1698
1699	if (!kdamond->damon_ctx)
1700		return -EINVAL;
1701	call_control.fn = fn;
1702	call_control.data = kdamond;
1703	err = damon_call(kdamond->damon_ctx, &call_control);
1704	return err ? err : call_control.return_code;
1705}
1706
1707struct damon_sysfs_schemes_walk_data {
1708	struct damon_sysfs_kdamond *sysfs_kdamond;
1709	bool total_bytes_only;
1710};
1711
1712/* populate the region directory */
1713static void damon_sysfs_schemes_tried_regions_upd_one(void *data, struct damon_ctx *ctx,
1714		struct damon_target *t, struct damon_region *r,
1715		struct damos *s, unsigned long sz_filter_passed)
1716{
1717	struct damon_sysfs_schemes_walk_data *walk_data = data;
1718	struct damon_sysfs_kdamond *sysfs_kdamond = walk_data->sysfs_kdamond;
1719
1720	damos_sysfs_populate_region_dir(
1721			sysfs_kdamond->contexts->contexts_arr[0]->schemes,
1722			ctx, t, r, s, walk_data->total_bytes_only,
1723			sz_filter_passed);
1724}
1725
1726static int damon_sysfs_update_schemes_tried_regions(
1727		struct damon_sysfs_kdamond *sysfs_kdamond, bool total_bytes_only)
1728{
1729	struct damon_sysfs_schemes_walk_data walk_data = {
1730		.sysfs_kdamond = sysfs_kdamond,
1731		.total_bytes_only = total_bytes_only,
1732	};
1733	struct damos_walk_control control = {
1734		.walk_fn = damon_sysfs_schemes_tried_regions_upd_one,
1735		.data = &walk_data,
1736	};
1737	struct damon_ctx *ctx = sysfs_kdamond->damon_ctx;
1738
1739	if (!ctx)
1740		return -EINVAL;
1741
1742	damon_sysfs_schemes_clear_regions(
1743			sysfs_kdamond->contexts->contexts_arr[0]->schemes);
1744	return damos_walk(ctx, &control);
1745}
1746
1747/*
1748 * damon_sysfs_handle_cmd() - Handle a command for a specific kdamond.
1749 * @cmd:	The command to handle.
1750 * @kdamond:	The kobject wrapper for the associated kdamond.
1751 *
1752 * This function handles a DAMON sysfs command for a kdamond.
1753 *
1754 * Return: 0 on success, negative error code otherwise.
1755 */
1756static int damon_sysfs_handle_cmd(enum damon_sysfs_cmd cmd,
1757		struct damon_sysfs_kdamond *kdamond)
1758{
1759	if (cmd != DAMON_SYSFS_CMD_OFF && kdamond->contexts->nr != 1)
1760		return -EINVAL;
1761
1762	switch (cmd) {
1763	case DAMON_SYSFS_CMD_ON:
1764		return damon_sysfs_turn_damon_on(kdamond);
1765	case DAMON_SYSFS_CMD_OFF:
1766		return damon_sysfs_turn_damon_off(kdamond);
1767	case DAMON_SYSFS_CMD_COMMIT:
1768		return damon_sysfs_damon_call(
1769				damon_sysfs_commit_input, kdamond);
1770	case DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS:
1771		return damon_sysfs_damon_call(
1772				damon_sysfs_commit_schemes_quota_goals,
1773				kdamond);
1774	case DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS:
1775		return damon_sysfs_damon_call(
1776				damon_sysfs_upd_schemes_stats, kdamond);
1777	case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES:
1778		return damon_sysfs_update_schemes_tried_regions(kdamond, true);
1779	case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS:
1780		return damon_sysfs_update_schemes_tried_regions(kdamond, false);
1781	case DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS:
1782		return damon_sysfs_schemes_clear_regions(
1783			kdamond->contexts->contexts_arr[0]->schemes);
1784	case DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS:
1785		return damon_sysfs_damon_call(
1786				damon_sysfs_upd_schemes_effective_quotas,
1787				kdamond);
1788	case DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS:
1789		return damon_sysfs_damon_call(
1790				damon_sysfs_upd_tuned_intervals, kdamond);
1791	default:
1792		return -EINVAL;
1793	}
1794}
1795
1796static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
1797		const char *buf, size_t count)
1798{
1799	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1800			struct damon_sysfs_kdamond, kobj);
1801	enum damon_sysfs_cmd cmd;
1802	ssize_t ret = -EINVAL;
1803
1804	if (!mutex_trylock(&damon_sysfs_lock))
1805		return -EBUSY;
1806	for (cmd = 0; cmd < NR_DAMON_SYSFS_CMDS; cmd++) {
1807		if (sysfs_streq(buf, damon_sysfs_cmd_strs[cmd])) {
1808			ret = damon_sysfs_handle_cmd(cmd, kdamond);
1809			break;
1810		}
1811	}
1812	mutex_unlock(&damon_sysfs_lock);
1813	if (!ret)
1814		ret = count;
1815	return ret;
1816}
1817
1818static ssize_t pid_show(struct kobject *kobj,
1819		struct kobj_attribute *attr, char *buf)
1820{
1821	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1822			struct damon_sysfs_kdamond, kobj);
1823	struct damon_ctx *ctx;
1824	int pid = -1;
1825
1826	if (!mutex_trylock(&damon_sysfs_lock))
1827		return -EBUSY;
1828	ctx = kdamond->damon_ctx;
1829	if (!ctx)
1830		goto out;
1831
1832	mutex_lock(&ctx->kdamond_lock);
1833	if (ctx->kdamond)
1834		pid = ctx->kdamond->pid;
1835	mutex_unlock(&ctx->kdamond_lock);
1836out:
1837	mutex_unlock(&damon_sysfs_lock);
1838	return sysfs_emit(buf, "%d\n", pid);
1839}
1840
1841static ssize_t refresh_ms_show(struct kobject *kobj,
1842		struct kobj_attribute *attr, char *buf)
1843{
1844	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1845			struct damon_sysfs_kdamond, kobj);
1846
1847	return sysfs_emit(buf, "%u\n", kdamond->refresh_ms);
1848}
1849
1850static ssize_t refresh_ms_store(struct kobject *kobj,
1851		struct kobj_attribute *attr, const char *buf, size_t count)
1852{
1853	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1854			struct damon_sysfs_kdamond, kobj);
1855	unsigned int nr;
1856	int err = kstrtouint(buf, 0, &nr);
1857
1858	if (err)
1859		return err;
1860
1861	kdamond->refresh_ms = nr;
1862	return count;
1863}
1864
1865static void damon_sysfs_kdamond_release(struct kobject *kobj)
1866{
1867	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1868			struct damon_sysfs_kdamond, kobj);
1869
1870	if (kdamond->damon_ctx)
1871		damon_destroy_ctx(kdamond->damon_ctx);
1872	kfree(kdamond);
1873}
1874
1875static struct kobj_attribute damon_sysfs_kdamond_state_attr =
1876		__ATTR_RW_MODE(state, 0600);
1877
1878static struct kobj_attribute damon_sysfs_kdamond_pid_attr =
1879		__ATTR_RO_MODE(pid, 0400);
1880
1881static struct kobj_attribute damon_sysfs_kdamond_refresh_ms_attr =
1882		__ATTR_RW_MODE(refresh_ms, 0600);
1883
1884static struct attribute *damon_sysfs_kdamond_attrs[] = {
1885	&damon_sysfs_kdamond_state_attr.attr,
1886	&damon_sysfs_kdamond_pid_attr.attr,
1887	&damon_sysfs_kdamond_refresh_ms_attr.attr,
1888	NULL,
1889};
1890ATTRIBUTE_GROUPS(damon_sysfs_kdamond);
1891
1892static const struct kobj_type damon_sysfs_kdamond_ktype = {
1893	.release = damon_sysfs_kdamond_release,
1894	.sysfs_ops = &kobj_sysfs_ops,
1895	.default_groups = damon_sysfs_kdamond_groups,
1896};
1897
1898/*
1899 * kdamonds directory
1900 */
1901
1902struct damon_sysfs_kdamonds {
1903	struct kobject kobj;
1904	struct damon_sysfs_kdamond **kdamonds_arr;
1905	int nr;
1906};
1907
1908static struct damon_sysfs_kdamonds *damon_sysfs_kdamonds_alloc(void)
1909{
1910	return kzalloc(sizeof(struct damon_sysfs_kdamonds), GFP_KERNEL);
1911}
1912
1913static void damon_sysfs_kdamonds_rm_dirs(struct damon_sysfs_kdamonds *kdamonds)
1914{
1915	struct damon_sysfs_kdamond **kdamonds_arr = kdamonds->kdamonds_arr;
1916	int i;
1917
1918	for (i = 0; i < kdamonds->nr; i++) {
1919		damon_sysfs_kdamond_rm_dirs(kdamonds_arr[i]);
1920		kobject_put(&kdamonds_arr[i]->kobj);
1921	}
1922	kdamonds->nr = 0;
1923	kfree(kdamonds_arr);
1924	kdamonds->kdamonds_arr = NULL;
1925}
1926
1927static bool damon_sysfs_kdamonds_busy(struct damon_sysfs_kdamond **kdamonds,
1928		int nr_kdamonds)
1929{
1930	int i;
1931
1932	for (i = 0; i < nr_kdamonds; i++) {
1933		if (damon_sysfs_kdamond_running(kdamonds[i]))
1934			return true;
1935	}
1936
1937	return false;
1938}
1939
1940static int damon_sysfs_kdamonds_add_dirs(struct damon_sysfs_kdamonds *kdamonds,
1941		int nr_kdamonds)
1942{
1943	struct damon_sysfs_kdamond **kdamonds_arr, *kdamond;
1944	int err, i;
1945
1946	if (damon_sysfs_kdamonds_busy(kdamonds->kdamonds_arr, kdamonds->nr))
1947		return -EBUSY;
1948
1949	damon_sysfs_kdamonds_rm_dirs(kdamonds);
1950	if (!nr_kdamonds)
1951		return 0;
1952
1953	kdamonds_arr = kmalloc_array(nr_kdamonds, sizeof(*kdamonds_arr),
1954			GFP_KERNEL | __GFP_NOWARN);
1955	if (!kdamonds_arr)
1956		return -ENOMEM;
1957	kdamonds->kdamonds_arr = kdamonds_arr;
1958
1959	for (i = 0; i < nr_kdamonds; i++) {
1960		kdamond = damon_sysfs_kdamond_alloc();
1961		if (!kdamond) {
1962			damon_sysfs_kdamonds_rm_dirs(kdamonds);
1963			return -ENOMEM;
1964		}
1965
1966		err = kobject_init_and_add(&kdamond->kobj,
1967				&damon_sysfs_kdamond_ktype, &kdamonds->kobj,
1968				"%d", i);
1969		if (err)
1970			goto out;
1971
1972		err = damon_sysfs_kdamond_add_dirs(kdamond);
1973		if (err)
1974			goto out;
1975
1976		kdamonds_arr[i] = kdamond;
1977		kdamonds->nr++;
1978	}
1979	return 0;
1980
1981out:
1982	damon_sysfs_kdamonds_rm_dirs(kdamonds);
1983	kobject_put(&kdamond->kobj);
1984	return err;
1985}
1986
1987static ssize_t nr_kdamonds_show(struct kobject *kobj,
1988		struct kobj_attribute *attr, char *buf)
1989{
1990	struct damon_sysfs_kdamonds *kdamonds = container_of(kobj,
1991			struct damon_sysfs_kdamonds, kobj);
1992
1993	return sysfs_emit(buf, "%d\n", kdamonds->nr);
1994}
1995
1996static ssize_t nr_kdamonds_store(struct kobject *kobj,
1997		struct kobj_attribute *attr, const char *buf, size_t count)
1998{
1999	struct damon_sysfs_kdamonds *kdamonds;
2000	int nr, err;
2001
2002	err = kstrtoint(buf, 0, &nr);
2003	if (err)
2004		return err;
2005	if (nr < 0)
2006		return -EINVAL;
2007
2008	kdamonds = container_of(kobj, struct damon_sysfs_kdamonds, kobj);
2009
2010	if (!mutex_trylock(&damon_sysfs_lock))
2011		return -EBUSY;
2012	err = damon_sysfs_kdamonds_add_dirs(kdamonds, nr);
2013	mutex_unlock(&damon_sysfs_lock);
2014	if (err)
2015		return err;
2016
2017	return count;
2018}
2019
2020static void damon_sysfs_kdamonds_release(struct kobject *kobj)
2021{
2022	kfree(container_of(kobj, struct damon_sysfs_kdamonds, kobj));
2023}
2024
2025static struct kobj_attribute damon_sysfs_kdamonds_nr_attr =
2026		__ATTR_RW_MODE(nr_kdamonds, 0600);
2027
2028static struct attribute *damon_sysfs_kdamonds_attrs[] = {
2029	&damon_sysfs_kdamonds_nr_attr.attr,
2030	NULL,
2031};
2032ATTRIBUTE_GROUPS(damon_sysfs_kdamonds);
2033
2034static const struct kobj_type damon_sysfs_kdamonds_ktype = {
2035	.release = damon_sysfs_kdamonds_release,
2036	.sysfs_ops = &kobj_sysfs_ops,
2037	.default_groups = damon_sysfs_kdamonds_groups,
2038};
2039
2040/*
2041 * damon user interface directory
2042 */
2043
2044struct damon_sysfs_ui_dir {
2045	struct kobject kobj;
2046	struct damon_sysfs_kdamonds *kdamonds;
2047};
2048
2049static struct damon_sysfs_ui_dir *damon_sysfs_ui_dir_alloc(void)
2050{
2051	return kzalloc(sizeof(struct damon_sysfs_ui_dir), GFP_KERNEL);
2052}
2053
2054static int damon_sysfs_ui_dir_add_dirs(struct damon_sysfs_ui_dir *ui_dir)
2055{
2056	struct damon_sysfs_kdamonds *kdamonds;
2057	int err;
2058
2059	kdamonds = damon_sysfs_kdamonds_alloc();
2060	if (!kdamonds)
2061		return -ENOMEM;
2062
2063	err = kobject_init_and_add(&kdamonds->kobj,
2064			&damon_sysfs_kdamonds_ktype, &ui_dir->kobj,
2065			"kdamonds");
2066	if (err) {
2067		kobject_put(&kdamonds->kobj);
2068		return err;
2069	}
2070	ui_dir->kdamonds = kdamonds;
2071	return err;
2072}
2073
2074static void damon_sysfs_ui_dir_release(struct kobject *kobj)
2075{
2076	kfree(container_of(kobj, struct damon_sysfs_ui_dir, kobj));
2077}
2078
2079static struct attribute *damon_sysfs_ui_dir_attrs[] = {
2080	NULL,
2081};
2082ATTRIBUTE_GROUPS(damon_sysfs_ui_dir);
2083
2084static const struct kobj_type damon_sysfs_ui_dir_ktype = {
2085	.release = damon_sysfs_ui_dir_release,
2086	.sysfs_ops = &kobj_sysfs_ops,
2087	.default_groups = damon_sysfs_ui_dir_groups,
2088};
2089
2090static int __init damon_sysfs_init(void)
2091{
2092	struct kobject *damon_sysfs_root;
2093	struct damon_sysfs_ui_dir *admin;
2094	int err;
2095
2096	damon_sysfs_root = kobject_create_and_add("damon", mm_kobj);
2097	if (!damon_sysfs_root)
2098		return -ENOMEM;
2099
2100	admin = damon_sysfs_ui_dir_alloc();
2101	if (!admin) {
2102		kobject_put(damon_sysfs_root);
2103		return -ENOMEM;
2104	}
2105	err = kobject_init_and_add(&admin->kobj, &damon_sysfs_ui_dir_ktype,
2106			damon_sysfs_root, "admin");
2107	if (err)
2108		goto out;
2109	err = damon_sysfs_ui_dir_add_dirs(admin);
2110	if (err)
2111		goto out;
2112	return 0;
2113
2114out:
2115	kobject_put(&admin->kobj);
2116	kobject_put(damon_sysfs_root);
2117	return err;
2118}
2119subsys_initcall(damon_sysfs_init);
2120
2121#include "tests/sysfs-kunit.h"
~/ Read-only file preview.