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/slab.h> 9 10 #include "sysfs-common.h" 11 12 /* 13 * scheme region directory 14 */ 15 16 struct damon_sysfs_scheme_region { 17 struct kobject kobj; 18 struct damon_addr_range ar; 19 unsigned int nr_accesses; 20 unsigned int age; 21 struct list_head list; 22 }; 23 24 static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc( 25 struct damon_region *region) 26 { 27 struct damon_sysfs_scheme_region *sysfs_region = kmalloc( 28 sizeof(*sysfs_region), GFP_KERNEL); 29 30 if (!sysfs_region) 31 return NULL; 32 sysfs_region->kobj = (struct kobject){}; 33 sysfs_region->ar = region->ar; 34 sysfs_region->nr_accesses = region->nr_accesses; 35 sysfs_region->age = region->age; 36 INIT_LIST_HEAD(&sysfs_region->list); 37 return sysfs_region; 38 } 39 40 static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr, 41 char *buf) 42 { 43 struct damon_sysfs_scheme_region *region = container_of(kobj, 44 struct damon_sysfs_scheme_region, kobj); 45 46 return sysfs_emit(buf, "%lu\n", region->ar.start); 47 } 48 49 static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr, 50 char *buf) 51 { 52 struct damon_sysfs_scheme_region *region = container_of(kobj, 53 struct damon_sysfs_scheme_region, kobj); 54 55 return sysfs_emit(buf, "%lu\n", region->ar.end); 56 } 57 58 static ssize_t nr_accesses_show(struct kobject *kobj, 59 struct kobj_attribute *attr, char *buf) 60 { 61 struct damon_sysfs_scheme_region *region = container_of(kobj, 62 struct damon_sysfs_scheme_region, kobj); 63 64 return sysfs_emit(buf, "%u\n", region->nr_accesses); 65 } 66 67 static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr, 68 char *buf) 69 { 70 struct damon_sysfs_scheme_region *region = container_of(kobj, 71 struct damon_sysfs_scheme_region, kobj); 72 73 return sysfs_emit(buf, "%u\n", region->age); 74 } 75 76 static void damon_sysfs_scheme_region_release(struct kobject *kobj) 77 { 78 struct damon_sysfs_scheme_region *region = container_of(kobj, 79 struct damon_sysfs_scheme_region, kobj); 80 81 list_del(®ion->list); 82 kfree(region); 83 } 84 85 static struct kobj_attribute damon_sysfs_scheme_region_start_attr = 86 __ATTR_RO_MODE(start, 0400); 87 88 static struct kobj_attribute damon_sysfs_scheme_region_end_attr = 89 __ATTR_RO_MODE(end, 0400); 90 91 static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr = 92 __ATTR_RO_MODE(nr_accesses, 0400); 93 94 static struct kobj_attribute damon_sysfs_scheme_region_age_attr = 95 __ATTR_RO_MODE(age, 0400); 96 97 static struct attribute *damon_sysfs_scheme_region_attrs[] = { 98 &damon_sysfs_scheme_region_start_attr.attr, 99 &damon_sysfs_scheme_region_end_attr.attr, 100 &damon_sysfs_scheme_region_nr_accesses_attr.attr, 101 &damon_sysfs_scheme_region_age_attr.attr, 102 NULL, 103 }; 104 ATTRIBUTE_GROUPS(damon_sysfs_scheme_region); 105 106 static const struct kobj_type damon_sysfs_scheme_region_ktype = { 107 .release = damon_sysfs_scheme_region_release, 108 .sysfs_ops = &kobj_sysfs_ops, 109 .default_groups = damon_sysfs_scheme_region_groups, 110 }; 111 112 /* 113 * scheme regions directory 114 */ 115 116 struct damon_sysfs_scheme_regions { 117 struct kobject kobj; 118 struct list_head regions_list; 119 int nr_regions; 120 }; 121 122 static struct damon_sysfs_scheme_regions * 123 damon_sysfs_scheme_regions_alloc(void) 124 { 125 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions), 126 GFP_KERNEL); 127 128 regions->kobj = (struct kobject){}; 129 INIT_LIST_HEAD(®ions->regions_list); 130 regions->nr_regions = 0; 131 return regions; 132 } 133 134 static void damon_sysfs_scheme_regions_rm_dirs( 135 struct damon_sysfs_scheme_regions *regions) 136 { 137 struct damon_sysfs_scheme_region *r, *next; 138 139 list_for_each_entry_safe(r, next, ®ions->regions_list, list) { 140 /* release function deletes it from the list */ 141 kobject_put(&r->kobj); 142 regions->nr_regions--; 143 } 144 } 145 146 static void damon_sysfs_scheme_regions_release(struct kobject *kobj) 147 { 148 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj)); 149 } 150 151 static struct attribute *damon_sysfs_scheme_regions_attrs[] = { 152 NULL, 153 }; 154 ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions); 155 156 static const struct kobj_type damon_sysfs_scheme_regions_ktype = { 157 .release = damon_sysfs_scheme_regions_release, 158 .sysfs_ops = &kobj_sysfs_ops, 159 .default_groups = damon_sysfs_scheme_regions_groups, 160 }; 161 162 /* 163 * schemes/stats directory 164 */ 165 166 struct damon_sysfs_stats { 167 struct kobject kobj; 168 unsigned long nr_tried; 169 unsigned long sz_tried; 170 unsigned long nr_applied; 171 unsigned long sz_applied; 172 unsigned long qt_exceeds; 173 }; 174 175 static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void) 176 { 177 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL); 178 } 179 180 static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr, 181 char *buf) 182 { 183 struct damon_sysfs_stats *stats = container_of(kobj, 184 struct damon_sysfs_stats, kobj); 185 186 return sysfs_emit(buf, "%lu\n", stats->nr_tried); 187 } 188 189 static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr, 190 char *buf) 191 { 192 struct damon_sysfs_stats *stats = container_of(kobj, 193 struct damon_sysfs_stats, kobj); 194 195 return sysfs_emit(buf, "%lu\n", stats->sz_tried); 196 } 197 198 static ssize_t nr_applied_show(struct kobject *kobj, 199 struct kobj_attribute *attr, char *buf) 200 { 201 struct damon_sysfs_stats *stats = container_of(kobj, 202 struct damon_sysfs_stats, kobj); 203 204 return sysfs_emit(buf, "%lu\n", stats->nr_applied); 205 } 206 207 static ssize_t sz_applied_show(struct kobject *kobj, 208 struct kobj_attribute *attr, char *buf) 209 { 210 struct damon_sysfs_stats *stats = container_of(kobj, 211 struct damon_sysfs_stats, kobj); 212 213 return sysfs_emit(buf, "%lu\n", stats->sz_applied); 214 } 215 216 static ssize_t qt_exceeds_show(struct kobject *kobj, 217 struct kobj_attribute *attr, char *buf) 218 { 219 struct damon_sysfs_stats *stats = container_of(kobj, 220 struct damon_sysfs_stats, kobj); 221 222 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds); 223 } 224 225 static void damon_sysfs_stats_release(struct kobject *kobj) 226 { 227 kfree(container_of(kobj, struct damon_sysfs_stats, kobj)); 228 } 229 230 static struct kobj_attribute damon_sysfs_stats_nr_tried_attr = 231 __ATTR_RO_MODE(nr_tried, 0400); 232 233 static struct kobj_attribute damon_sysfs_stats_sz_tried_attr = 234 __ATTR_RO_MODE(sz_tried, 0400); 235 236 static struct kobj_attribute damon_sysfs_stats_nr_applied_attr = 237 __ATTR_RO_MODE(nr_applied, 0400); 238 239 static struct kobj_attribute damon_sysfs_stats_sz_applied_attr = 240 __ATTR_RO_MODE(sz_applied, 0400); 241 242 static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr = 243 __ATTR_RO_MODE(qt_exceeds, 0400); 244 245 static struct attribute *damon_sysfs_stats_attrs[] = { 246 &damon_sysfs_stats_nr_tried_attr.attr, 247 &damon_sysfs_stats_sz_tried_attr.attr, 248 &damon_sysfs_stats_nr_applied_attr.attr, 249 &damon_sysfs_stats_sz_applied_attr.attr, 250 &damon_sysfs_stats_qt_exceeds_attr.attr, 251 NULL, 252 }; 253 ATTRIBUTE_GROUPS(damon_sysfs_stats); 254 255 static const struct kobj_type damon_sysfs_stats_ktype = { 256 .release = damon_sysfs_stats_release, 257 .sysfs_ops = &kobj_sysfs_ops, 258 .default_groups = damon_sysfs_stats_groups, 259 }; 260 261 /* 262 * filter directory 263 */ 264 265 struct damon_sysfs_scheme_filter { 266 struct kobject kobj; 267 enum damos_filter_type type; 268 bool matching; 269 char *memcg_path; 270 }; 271 272 static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(void) 273 { 274 return kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL); 275 } 276 277 /* Should match with enum damos_filter_type */ 278 static const char * const damon_sysfs_scheme_filter_type_strs[] = { 279 "anon", 280 "memcg", 281 }; 282 283 static ssize_t type_show(struct kobject *kobj, 284 struct kobj_attribute *attr, char *buf) 285 { 286 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 287 struct damon_sysfs_scheme_filter, kobj); 288 289 return sysfs_emit(buf, "%s\n", 290 damon_sysfs_scheme_filter_type_strs[filter->type]); 291 } 292 293 static ssize_t type_store(struct kobject *kobj, 294 struct kobj_attribute *attr, const char *buf, size_t count) 295 { 296 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 297 struct damon_sysfs_scheme_filter, kobj); 298 enum damos_filter_type type; 299 ssize_t ret = -EINVAL; 300 301 for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) { 302 if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[ 303 type])) { 304 filter->type = type; 305 ret = count; 306 break; 307 } 308 } 309 return ret; 310 } 311 312 static ssize_t matching_show(struct kobject *kobj, 313 struct kobj_attribute *attr, char *buf) 314 { 315 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 316 struct damon_sysfs_scheme_filter, kobj); 317 318 return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N'); 319 } 320 321 static ssize_t matching_store(struct kobject *kobj, 322 struct kobj_attribute *attr, const char *buf, size_t count) 323 { 324 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 325 struct damon_sysfs_scheme_filter, kobj); 326 bool matching; 327 int err = kstrtobool(buf, &matching); 328 329 if (err) 330 return err; 331 332 filter->matching = matching; 333 return count; 334 } 335 336 static ssize_t memcg_path_show(struct kobject *kobj, 337 struct kobj_attribute *attr, char *buf) 338 { 339 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 340 struct damon_sysfs_scheme_filter, kobj); 341 342 return sysfs_emit(buf, "%s\n", 343 filter->memcg_path ? filter->memcg_path : ""); 344 } 345 346 static ssize_t memcg_path_store(struct kobject *kobj, 347 struct kobj_attribute *attr, const char *buf, size_t count) 348 { 349 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 350 struct damon_sysfs_scheme_filter, kobj); 351 char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL); 352 353 if (!path) 354 return -ENOMEM; 355 356 strscpy(path, buf, count + 1); 357 filter->memcg_path = path; 358 return count; 359 } 360 361 static void damon_sysfs_scheme_filter_release(struct kobject *kobj) 362 { 363 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 364 struct damon_sysfs_scheme_filter, kobj); 365 366 kfree(filter->memcg_path); 367 kfree(filter); 368 } 369 370 static struct kobj_attribute damon_sysfs_scheme_filter_type_attr = 371 __ATTR_RW_MODE(type, 0600); 372 373 static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr = 374 __ATTR_RW_MODE(matching, 0600); 375 376 static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr = 377 __ATTR_RW_MODE(memcg_path, 0600); 378 379 static struct attribute *damon_sysfs_scheme_filter_attrs[] = { 380 &damon_sysfs_scheme_filter_type_attr.attr, 381 &damon_sysfs_scheme_filter_matching_attr.attr, 382 &damon_sysfs_scheme_filter_memcg_path_attr.attr, 383 NULL, 384 }; 385 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter); 386 387 static struct kobj_type damon_sysfs_scheme_filter_ktype = { 388 .release = damon_sysfs_scheme_filter_release, 389 .sysfs_ops = &kobj_sysfs_ops, 390 .default_groups = damon_sysfs_scheme_filter_groups, 391 }; 392 393 /* 394 * filters directory 395 */ 396 397 struct damon_sysfs_scheme_filters { 398 struct kobject kobj; 399 struct damon_sysfs_scheme_filter **filters_arr; 400 int nr; 401 }; 402 403 static struct damon_sysfs_scheme_filters * 404 damon_sysfs_scheme_filters_alloc(void) 405 { 406 return kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL); 407 } 408 409 static void damon_sysfs_scheme_filters_rm_dirs( 410 struct damon_sysfs_scheme_filters *filters) 411 { 412 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr; 413 int i; 414 415 for (i = 0; i < filters->nr; i++) 416 kobject_put(&filters_arr[i]->kobj); 417 filters->nr = 0; 418 kfree(filters_arr); 419 filters->filters_arr = NULL; 420 } 421 422 static int damon_sysfs_scheme_filters_add_dirs( 423 struct damon_sysfs_scheme_filters *filters, int nr_filters) 424 { 425 struct damon_sysfs_scheme_filter **filters_arr, *filter; 426 int err, i; 427 428 damon_sysfs_scheme_filters_rm_dirs(filters); 429 if (!nr_filters) 430 return 0; 431 432 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr), 433 GFP_KERNEL | __GFP_NOWARN); 434 if (!filters_arr) 435 return -ENOMEM; 436 filters->filters_arr = filters_arr; 437 438 for (i = 0; i < nr_filters; i++) { 439 filter = damon_sysfs_scheme_filter_alloc(); 440 if (!filter) { 441 damon_sysfs_scheme_filters_rm_dirs(filters); 442 return -ENOMEM; 443 } 444 445 err = kobject_init_and_add(&filter->kobj, 446 &damon_sysfs_scheme_filter_ktype, 447 &filters->kobj, "%d", i); 448 if (err) { 449 kobject_put(&filter->kobj); 450 damon_sysfs_scheme_filters_rm_dirs(filters); 451 return err; 452 } 453 454 filters_arr[i] = filter; 455 filters->nr++; 456 } 457 return 0; 458 } 459 460 static ssize_t nr_filters_show(struct kobject *kobj, 461 struct kobj_attribute *attr, char *buf) 462 { 463 struct damon_sysfs_scheme_filters *filters = container_of(kobj, 464 struct damon_sysfs_scheme_filters, kobj); 465 466 return sysfs_emit(buf, "%d\n", filters->nr); 467 } 468 469 static ssize_t nr_filters_store(struct kobject *kobj, 470 struct kobj_attribute *attr, const char *buf, size_t count) 471 { 472 struct damon_sysfs_scheme_filters *filters; 473 int nr, err = kstrtoint(buf, 0, &nr); 474 475 if (err) 476 return err; 477 if (nr < 0) 478 return -EINVAL; 479 480 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj); 481 482 if (!mutex_trylock(&damon_sysfs_lock)) 483 return -EBUSY; 484 err = damon_sysfs_scheme_filters_add_dirs(filters, nr); 485 mutex_unlock(&damon_sysfs_lock); 486 if (err) 487 return err; 488 489 return count; 490 } 491 492 static void damon_sysfs_scheme_filters_release(struct kobject *kobj) 493 { 494 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj)); 495 } 496 497 static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr = 498 __ATTR_RW_MODE(nr_filters, 0600); 499 500 static struct attribute *damon_sysfs_scheme_filters_attrs[] = { 501 &damon_sysfs_scheme_filters_nr_attr.attr, 502 NULL, 503 }; 504 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters); 505 506 static struct kobj_type damon_sysfs_scheme_filters_ktype = { 507 .release = damon_sysfs_scheme_filters_release, 508 .sysfs_ops = &kobj_sysfs_ops, 509 .default_groups = damon_sysfs_scheme_filters_groups, 510 }; 511 512 /* 513 * watermarks directory 514 */ 515 516 struct damon_sysfs_watermarks { 517 struct kobject kobj; 518 enum damos_wmark_metric metric; 519 unsigned long interval_us; 520 unsigned long high; 521 unsigned long mid; 522 unsigned long low; 523 }; 524 525 static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc( 526 enum damos_wmark_metric metric, unsigned long interval_us, 527 unsigned long high, unsigned long mid, unsigned long low) 528 { 529 struct damon_sysfs_watermarks *watermarks = kmalloc( 530 sizeof(*watermarks), GFP_KERNEL); 531 532 if (!watermarks) 533 return NULL; 534 watermarks->kobj = (struct kobject){}; 535 watermarks->metric = metric; 536 watermarks->interval_us = interval_us; 537 watermarks->high = high; 538 watermarks->mid = mid; 539 watermarks->low = low; 540 return watermarks; 541 } 542 543 /* Should match with enum damos_wmark_metric */ 544 static const char * const damon_sysfs_wmark_metric_strs[] = { 545 "none", 546 "free_mem_rate", 547 }; 548 549 static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr, 550 char *buf) 551 { 552 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 553 struct damon_sysfs_watermarks, kobj); 554 555 return sysfs_emit(buf, "%s\n", 556 damon_sysfs_wmark_metric_strs[watermarks->metric]); 557 } 558 559 static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr, 560 const char *buf, size_t count) 561 { 562 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 563 struct damon_sysfs_watermarks, kobj); 564 enum damos_wmark_metric metric; 565 566 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) { 567 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) { 568 watermarks->metric = metric; 569 return count; 570 } 571 } 572 return -EINVAL; 573 } 574 575 static ssize_t interval_us_show(struct kobject *kobj, 576 struct kobj_attribute *attr, char *buf) 577 { 578 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 579 struct damon_sysfs_watermarks, kobj); 580 581 return sysfs_emit(buf, "%lu\n", watermarks->interval_us); 582 } 583 584 static ssize_t interval_us_store(struct kobject *kobj, 585 struct kobj_attribute *attr, const char *buf, size_t count) 586 { 587 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 588 struct damon_sysfs_watermarks, kobj); 589 int err = kstrtoul(buf, 0, &watermarks->interval_us); 590 591 return err ? err : count; 592 } 593 594 static ssize_t high_show(struct kobject *kobj, 595 struct kobj_attribute *attr, char *buf) 596 { 597 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 598 struct damon_sysfs_watermarks, kobj); 599 600 return sysfs_emit(buf, "%lu\n", watermarks->high); 601 } 602 603 static ssize_t high_store(struct kobject *kobj, 604 struct kobj_attribute *attr, const char *buf, size_t count) 605 { 606 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 607 struct damon_sysfs_watermarks, kobj); 608 int err = kstrtoul(buf, 0, &watermarks->high); 609 610 return err ? err : count; 611 } 612 613 static ssize_t mid_show(struct kobject *kobj, 614 struct kobj_attribute *attr, char *buf) 615 { 616 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 617 struct damon_sysfs_watermarks, kobj); 618 619 return sysfs_emit(buf, "%lu\n", watermarks->mid); 620 } 621 622 static ssize_t mid_store(struct kobject *kobj, 623 struct kobj_attribute *attr, const char *buf, size_t count) 624 { 625 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 626 struct damon_sysfs_watermarks, kobj); 627 int err = kstrtoul(buf, 0, &watermarks->mid); 628 629 return err ? err : count; 630 } 631 632 static ssize_t low_show(struct kobject *kobj, 633 struct kobj_attribute *attr, char *buf) 634 { 635 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 636 struct damon_sysfs_watermarks, kobj); 637 638 return sysfs_emit(buf, "%lu\n", watermarks->low); 639 } 640 641 static ssize_t low_store(struct kobject *kobj, 642 struct kobj_attribute *attr, const char *buf, size_t count) 643 { 644 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 645 struct damon_sysfs_watermarks, kobj); 646 int err = kstrtoul(buf, 0, &watermarks->low); 647 648 return err ? err : count; 649 } 650 651 static void damon_sysfs_watermarks_release(struct kobject *kobj) 652 { 653 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj)); 654 } 655 656 static struct kobj_attribute damon_sysfs_watermarks_metric_attr = 657 __ATTR_RW_MODE(metric, 0600); 658 659 static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr = 660 __ATTR_RW_MODE(interval_us, 0600); 661 662 static struct kobj_attribute damon_sysfs_watermarks_high_attr = 663 __ATTR_RW_MODE(high, 0600); 664 665 static struct kobj_attribute damon_sysfs_watermarks_mid_attr = 666 __ATTR_RW_MODE(mid, 0600); 667 668 static struct kobj_attribute damon_sysfs_watermarks_low_attr = 669 __ATTR_RW_MODE(low, 0600); 670 671 static struct attribute *damon_sysfs_watermarks_attrs[] = { 672 &damon_sysfs_watermarks_metric_attr.attr, 673 &damon_sysfs_watermarks_interval_us_attr.attr, 674 &damon_sysfs_watermarks_high_attr.attr, 675 &damon_sysfs_watermarks_mid_attr.attr, 676 &damon_sysfs_watermarks_low_attr.attr, 677 NULL, 678 }; 679 ATTRIBUTE_GROUPS(damon_sysfs_watermarks); 680 681 static const struct kobj_type damon_sysfs_watermarks_ktype = { 682 .release = damon_sysfs_watermarks_release, 683 .sysfs_ops = &kobj_sysfs_ops, 684 .default_groups = damon_sysfs_watermarks_groups, 685 }; 686 687 /* 688 * scheme/weights directory 689 */ 690 691 struct damon_sysfs_weights { 692 struct kobject kobj; 693 unsigned int sz; 694 unsigned int nr_accesses; 695 unsigned int age; 696 }; 697 698 static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz, 699 unsigned int nr_accesses, unsigned int age) 700 { 701 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights), 702 GFP_KERNEL); 703 704 if (!weights) 705 return NULL; 706 weights->kobj = (struct kobject){}; 707 weights->sz = sz; 708 weights->nr_accesses = nr_accesses; 709 weights->age = age; 710 return weights; 711 } 712 713 static ssize_t sz_permil_show(struct kobject *kobj, 714 struct kobj_attribute *attr, char *buf) 715 { 716 struct damon_sysfs_weights *weights = container_of(kobj, 717 struct damon_sysfs_weights, kobj); 718 719 return sysfs_emit(buf, "%u\n", weights->sz); 720 } 721 722 static ssize_t sz_permil_store(struct kobject *kobj, 723 struct kobj_attribute *attr, const char *buf, size_t count) 724 { 725 struct damon_sysfs_weights *weights = container_of(kobj, 726 struct damon_sysfs_weights, kobj); 727 int err = kstrtouint(buf, 0, &weights->sz); 728 729 return err ? err : count; 730 } 731 732 static ssize_t nr_accesses_permil_show(struct kobject *kobj, 733 struct kobj_attribute *attr, char *buf) 734 { 735 struct damon_sysfs_weights *weights = container_of(kobj, 736 struct damon_sysfs_weights, kobj); 737 738 return sysfs_emit(buf, "%u\n", weights->nr_accesses); 739 } 740 741 static ssize_t nr_accesses_permil_store(struct kobject *kobj, 742 struct kobj_attribute *attr, const char *buf, size_t count) 743 { 744 struct damon_sysfs_weights *weights = container_of(kobj, 745 struct damon_sysfs_weights, kobj); 746 int err = kstrtouint(buf, 0, &weights->nr_accesses); 747 748 return err ? err : count; 749 } 750 751 static ssize_t age_permil_show(struct kobject *kobj, 752 struct kobj_attribute *attr, char *buf) 753 { 754 struct damon_sysfs_weights *weights = container_of(kobj, 755 struct damon_sysfs_weights, kobj); 756 757 return sysfs_emit(buf, "%u\n", weights->age); 758 } 759 760 static ssize_t age_permil_store(struct kobject *kobj, 761 struct kobj_attribute *attr, const char *buf, size_t count) 762 { 763 struct damon_sysfs_weights *weights = container_of(kobj, 764 struct damon_sysfs_weights, kobj); 765 int err = kstrtouint(buf, 0, &weights->age); 766 767 return err ? err : count; 768 } 769 770 static void damon_sysfs_weights_release(struct kobject *kobj) 771 { 772 kfree(container_of(kobj, struct damon_sysfs_weights, kobj)); 773 } 774 775 static struct kobj_attribute damon_sysfs_weights_sz_attr = 776 __ATTR_RW_MODE(sz_permil, 0600); 777 778 static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr = 779 __ATTR_RW_MODE(nr_accesses_permil, 0600); 780 781 static struct kobj_attribute damon_sysfs_weights_age_attr = 782 __ATTR_RW_MODE(age_permil, 0600); 783 784 static struct attribute *damon_sysfs_weights_attrs[] = { 785 &damon_sysfs_weights_sz_attr.attr, 786 &damon_sysfs_weights_nr_accesses_attr.attr, 787 &damon_sysfs_weights_age_attr.attr, 788 NULL, 789 }; 790 ATTRIBUTE_GROUPS(damon_sysfs_weights); 791 792 static const struct kobj_type damon_sysfs_weights_ktype = { 793 .release = damon_sysfs_weights_release, 794 .sysfs_ops = &kobj_sysfs_ops, 795 .default_groups = damon_sysfs_weights_groups, 796 }; 797 798 /* 799 * quotas directory 800 */ 801 802 struct damon_sysfs_quotas { 803 struct kobject kobj; 804 struct damon_sysfs_weights *weights; 805 unsigned long ms; 806 unsigned long sz; 807 unsigned long reset_interval_ms; 808 }; 809 810 static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void) 811 { 812 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL); 813 } 814 815 static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas) 816 { 817 struct damon_sysfs_weights *weights; 818 int err; 819 820 weights = damon_sysfs_weights_alloc(0, 0, 0); 821 if (!weights) 822 return -ENOMEM; 823 824 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype, 825 "as->kobj, "weights"); 826 if (err) 827 kobject_put(&weights->kobj); 828 else 829 quotas->weights = weights; 830 return err; 831 } 832 833 static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas) 834 { 835 kobject_put("as->weights->kobj); 836 } 837 838 static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr, 839 char *buf) 840 { 841 struct damon_sysfs_quotas *quotas = container_of(kobj, 842 struct damon_sysfs_quotas, kobj); 843 844 return sysfs_emit(buf, "%lu\n", quotas->ms); 845 } 846 847 static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr, 848 const char *buf, size_t count) 849 { 850 struct damon_sysfs_quotas *quotas = container_of(kobj, 851 struct damon_sysfs_quotas, kobj); 852 int err = kstrtoul(buf, 0, "as->ms); 853 854 if (err) 855 return -EINVAL; 856 return count; 857 } 858 859 static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr, 860 char *buf) 861 { 862 struct damon_sysfs_quotas *quotas = container_of(kobj, 863 struct damon_sysfs_quotas, kobj); 864 865 return sysfs_emit(buf, "%lu\n", quotas->sz); 866 } 867 868 static ssize_t bytes_store(struct kobject *kobj, 869 struct kobj_attribute *attr, const char *buf, size_t count) 870 { 871 struct damon_sysfs_quotas *quotas = container_of(kobj, 872 struct damon_sysfs_quotas, kobj); 873 int err = kstrtoul(buf, 0, "as->sz); 874 875 if (err) 876 return -EINVAL; 877 return count; 878 } 879 880 static ssize_t reset_interval_ms_show(struct kobject *kobj, 881 struct kobj_attribute *attr, char *buf) 882 { 883 struct damon_sysfs_quotas *quotas = container_of(kobj, 884 struct damon_sysfs_quotas, kobj); 885 886 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms); 887 } 888 889 static ssize_t reset_interval_ms_store(struct kobject *kobj, 890 struct kobj_attribute *attr, const char *buf, size_t count) 891 { 892 struct damon_sysfs_quotas *quotas = container_of(kobj, 893 struct damon_sysfs_quotas, kobj); 894 int err = kstrtoul(buf, 0, "as->reset_interval_ms); 895 896 if (err) 897 return -EINVAL; 898 return count; 899 } 900 901 static void damon_sysfs_quotas_release(struct kobject *kobj) 902 { 903 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj)); 904 } 905 906 static struct kobj_attribute damon_sysfs_quotas_ms_attr = 907 __ATTR_RW_MODE(ms, 0600); 908 909 static struct kobj_attribute damon_sysfs_quotas_sz_attr = 910 __ATTR_RW_MODE(bytes, 0600); 911 912 static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr = 913 __ATTR_RW_MODE(reset_interval_ms, 0600); 914 915 static struct attribute *damon_sysfs_quotas_attrs[] = { 916 &damon_sysfs_quotas_ms_attr.attr, 917 &damon_sysfs_quotas_sz_attr.attr, 918 &damon_sysfs_quotas_reset_interval_ms_attr.attr, 919 NULL, 920 }; 921 ATTRIBUTE_GROUPS(damon_sysfs_quotas); 922 923 static const struct kobj_type damon_sysfs_quotas_ktype = { 924 .release = damon_sysfs_quotas_release, 925 .sysfs_ops = &kobj_sysfs_ops, 926 .default_groups = damon_sysfs_quotas_groups, 927 }; 928 929 /* 930 * access_pattern directory 931 */ 932 933 struct damon_sysfs_access_pattern { 934 struct kobject kobj; 935 struct damon_sysfs_ul_range *sz; 936 struct damon_sysfs_ul_range *nr_accesses; 937 struct damon_sysfs_ul_range *age; 938 }; 939 940 static 941 struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void) 942 { 943 struct damon_sysfs_access_pattern *access_pattern = 944 kmalloc(sizeof(*access_pattern), GFP_KERNEL); 945 946 if (!access_pattern) 947 return NULL; 948 access_pattern->kobj = (struct kobject){}; 949 return access_pattern; 950 } 951 952 static int damon_sysfs_access_pattern_add_range_dir( 953 struct damon_sysfs_access_pattern *access_pattern, 954 struct damon_sysfs_ul_range **range_dir_ptr, 955 char *name) 956 { 957 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0); 958 int err; 959 960 if (!range) 961 return -ENOMEM; 962 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype, 963 &access_pattern->kobj, name); 964 if (err) 965 kobject_put(&range->kobj); 966 else 967 *range_dir_ptr = range; 968 return err; 969 } 970 971 static int damon_sysfs_access_pattern_add_dirs( 972 struct damon_sysfs_access_pattern *access_pattern) 973 { 974 int err; 975 976 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 977 &access_pattern->sz, "sz"); 978 if (err) 979 goto put_sz_out; 980 981 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 982 &access_pattern->nr_accesses, "nr_accesses"); 983 if (err) 984 goto put_nr_accesses_sz_out; 985 986 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 987 &access_pattern->age, "age"); 988 if (err) 989 goto put_age_nr_accesses_sz_out; 990 return 0; 991 992 put_age_nr_accesses_sz_out: 993 kobject_put(&access_pattern->age->kobj); 994 access_pattern->age = NULL; 995 put_nr_accesses_sz_out: 996 kobject_put(&access_pattern->nr_accesses->kobj); 997 access_pattern->nr_accesses = NULL; 998 put_sz_out: 999 kobject_put(&access_pattern->sz->kobj); 1000 access_pattern->sz = NULL; 1001 return err; 1002 } 1003 1004 static void damon_sysfs_access_pattern_rm_dirs( 1005 struct damon_sysfs_access_pattern *access_pattern) 1006 { 1007 kobject_put(&access_pattern->sz->kobj); 1008 kobject_put(&access_pattern->nr_accesses->kobj); 1009 kobject_put(&access_pattern->age->kobj); 1010 } 1011 1012 static void damon_sysfs_access_pattern_release(struct kobject *kobj) 1013 { 1014 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj)); 1015 } 1016 1017 static struct attribute *damon_sysfs_access_pattern_attrs[] = { 1018 NULL, 1019 }; 1020 ATTRIBUTE_GROUPS(damon_sysfs_access_pattern); 1021 1022 static const struct kobj_type damon_sysfs_access_pattern_ktype = { 1023 .release = damon_sysfs_access_pattern_release, 1024 .sysfs_ops = &kobj_sysfs_ops, 1025 .default_groups = damon_sysfs_access_pattern_groups, 1026 }; 1027 1028 /* 1029 * scheme directory 1030 */ 1031 1032 struct damon_sysfs_scheme { 1033 struct kobject kobj; 1034 enum damos_action action; 1035 struct damon_sysfs_access_pattern *access_pattern; 1036 struct damon_sysfs_quotas *quotas; 1037 struct damon_sysfs_watermarks *watermarks; 1038 struct damon_sysfs_scheme_filters *filters; 1039 struct damon_sysfs_stats *stats; 1040 struct damon_sysfs_scheme_regions *tried_regions; 1041 }; 1042 1043 /* This should match with enum damos_action */ 1044 static const char * const damon_sysfs_damos_action_strs[] = { 1045 "willneed", 1046 "cold", 1047 "pageout", 1048 "hugepage", 1049 "nohugepage", 1050 "lru_prio", 1051 "lru_deprio", 1052 "stat", 1053 }; 1054 1055 static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc( 1056 enum damos_action action) 1057 { 1058 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme), 1059 GFP_KERNEL); 1060 1061 if (!scheme) 1062 return NULL; 1063 scheme->kobj = (struct kobject){}; 1064 scheme->action = action; 1065 return scheme; 1066 } 1067 1068 static int damon_sysfs_scheme_set_access_pattern( 1069 struct damon_sysfs_scheme *scheme) 1070 { 1071 struct damon_sysfs_access_pattern *access_pattern; 1072 int err; 1073 1074 access_pattern = damon_sysfs_access_pattern_alloc(); 1075 if (!access_pattern) 1076 return -ENOMEM; 1077 err = kobject_init_and_add(&access_pattern->kobj, 1078 &damon_sysfs_access_pattern_ktype, &scheme->kobj, 1079 "access_pattern"); 1080 if (err) 1081 goto out; 1082 err = damon_sysfs_access_pattern_add_dirs(access_pattern); 1083 if (err) 1084 goto out; 1085 scheme->access_pattern = access_pattern; 1086 return 0; 1087 1088 out: 1089 kobject_put(&access_pattern->kobj); 1090 return err; 1091 } 1092 1093 static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme) 1094 { 1095 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc(); 1096 int err; 1097 1098 if (!quotas) 1099 return -ENOMEM; 1100 err = kobject_init_and_add("as->kobj, &damon_sysfs_quotas_ktype, 1101 &scheme->kobj, "quotas"); 1102 if (err) 1103 goto out; 1104 err = damon_sysfs_quotas_add_dirs(quotas); 1105 if (err) 1106 goto out; 1107 scheme->quotas = quotas; 1108 return 0; 1109 1110 out: 1111 kobject_put("as->kobj); 1112 return err; 1113 } 1114 1115 static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme) 1116 { 1117 struct damon_sysfs_watermarks *watermarks = 1118 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0); 1119 int err; 1120 1121 if (!watermarks) 1122 return -ENOMEM; 1123 err = kobject_init_and_add(&watermarks->kobj, 1124 &damon_sysfs_watermarks_ktype, &scheme->kobj, 1125 "watermarks"); 1126 if (err) 1127 kobject_put(&watermarks->kobj); 1128 else 1129 scheme->watermarks = watermarks; 1130 return err; 1131 } 1132 1133 static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme) 1134 { 1135 struct damon_sysfs_scheme_filters *filters = 1136 damon_sysfs_scheme_filters_alloc(); 1137 int err; 1138 1139 if (!filters) 1140 return -ENOMEM; 1141 err = kobject_init_and_add(&filters->kobj, 1142 &damon_sysfs_scheme_filters_ktype, &scheme->kobj, 1143 "filters"); 1144 if (err) 1145 kobject_put(&filters->kobj); 1146 else 1147 scheme->filters = filters; 1148 return err; 1149 } 1150 1151 static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme) 1152 { 1153 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc(); 1154 int err; 1155 1156 if (!stats) 1157 return -ENOMEM; 1158 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype, 1159 &scheme->kobj, "stats"); 1160 if (err) 1161 kobject_put(&stats->kobj); 1162 else 1163 scheme->stats = stats; 1164 return err; 1165 } 1166 1167 static int damon_sysfs_scheme_set_tried_regions( 1168 struct damon_sysfs_scheme *scheme) 1169 { 1170 struct damon_sysfs_scheme_regions *tried_regions = 1171 damon_sysfs_scheme_regions_alloc(); 1172 int err; 1173 1174 if (!tried_regions) 1175 return -ENOMEM; 1176 err = kobject_init_and_add(&tried_regions->kobj, 1177 &damon_sysfs_scheme_regions_ktype, &scheme->kobj, 1178 "tried_regions"); 1179 if (err) 1180 kobject_put(&tried_regions->kobj); 1181 else 1182 scheme->tried_regions = tried_regions; 1183 return err; 1184 } 1185 1186 static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) 1187 { 1188 int err; 1189 1190 err = damon_sysfs_scheme_set_access_pattern(scheme); 1191 if (err) 1192 return err; 1193 err = damon_sysfs_scheme_set_quotas(scheme); 1194 if (err) 1195 goto put_access_pattern_out; 1196 err = damon_sysfs_scheme_set_watermarks(scheme); 1197 if (err) 1198 goto put_quotas_access_pattern_out; 1199 err = damon_sysfs_scheme_set_filters(scheme); 1200 if (err) 1201 goto put_watermarks_quotas_access_pattern_out; 1202 err = damon_sysfs_scheme_set_stats(scheme); 1203 if (err) 1204 goto put_filters_watermarks_quotas_access_pattern_out; 1205 err = damon_sysfs_scheme_set_tried_regions(scheme); 1206 if (err) 1207 goto put_tried_regions_out; 1208 return 0; 1209 1210 put_tried_regions_out: 1211 kobject_put(&scheme->tried_regions->kobj); 1212 scheme->tried_regions = NULL; 1213 put_filters_watermarks_quotas_access_pattern_out: 1214 kobject_put(&scheme->filters->kobj); 1215 scheme->filters = NULL; 1216 put_watermarks_quotas_access_pattern_out: 1217 kobject_put(&scheme->watermarks->kobj); 1218 scheme->watermarks = NULL; 1219 put_quotas_access_pattern_out: 1220 kobject_put(&scheme->quotas->kobj); 1221 scheme->quotas = NULL; 1222 put_access_pattern_out: 1223 kobject_put(&scheme->access_pattern->kobj); 1224 scheme->access_pattern = NULL; 1225 return err; 1226 } 1227 1228 static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme) 1229 { 1230 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); 1231 kobject_put(&scheme->access_pattern->kobj); 1232 damon_sysfs_quotas_rm_dirs(scheme->quotas); 1233 kobject_put(&scheme->quotas->kobj); 1234 kobject_put(&scheme->watermarks->kobj); 1235 damon_sysfs_scheme_filters_rm_dirs(scheme->filters); 1236 kobject_put(&scheme->filters->kobj); 1237 kobject_put(&scheme->stats->kobj); 1238 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions); 1239 kobject_put(&scheme->tried_regions->kobj); 1240 } 1241 1242 static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr, 1243 char *buf) 1244 { 1245 struct damon_sysfs_scheme *scheme = container_of(kobj, 1246 struct damon_sysfs_scheme, kobj); 1247 1248 return sysfs_emit(buf, "%s\n", 1249 damon_sysfs_damos_action_strs[scheme->action]); 1250 } 1251 1252 static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr, 1253 const char *buf, size_t count) 1254 { 1255 struct damon_sysfs_scheme *scheme = container_of(kobj, 1256 struct damon_sysfs_scheme, kobj); 1257 enum damos_action action; 1258 1259 for (action = 0; action < NR_DAMOS_ACTIONS; action++) { 1260 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) { 1261 scheme->action = action; 1262 return count; 1263 } 1264 } 1265 return -EINVAL; 1266 } 1267 1268 static void damon_sysfs_scheme_release(struct kobject *kobj) 1269 { 1270 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj)); 1271 } 1272 1273 static struct kobj_attribute damon_sysfs_scheme_action_attr = 1274 __ATTR_RW_MODE(action, 0600); 1275 1276 static struct attribute *damon_sysfs_scheme_attrs[] = { 1277 &damon_sysfs_scheme_action_attr.attr, 1278 NULL, 1279 }; 1280 ATTRIBUTE_GROUPS(damon_sysfs_scheme); 1281 1282 static const struct kobj_type damon_sysfs_scheme_ktype = { 1283 .release = damon_sysfs_scheme_release, 1284 .sysfs_ops = &kobj_sysfs_ops, 1285 .default_groups = damon_sysfs_scheme_groups, 1286 }; 1287 1288 /* 1289 * schemes directory 1290 */ 1291 1292 struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void) 1293 { 1294 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL); 1295 } 1296 1297 void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes) 1298 { 1299 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr; 1300 int i; 1301 1302 for (i = 0; i < schemes->nr; i++) { 1303 damon_sysfs_scheme_rm_dirs(schemes_arr[i]); 1304 kobject_put(&schemes_arr[i]->kobj); 1305 } 1306 schemes->nr = 0; 1307 kfree(schemes_arr); 1308 schemes->schemes_arr = NULL; 1309 } 1310 1311 static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes, 1312 int nr_schemes) 1313 { 1314 struct damon_sysfs_scheme **schemes_arr, *scheme; 1315 int err, i; 1316 1317 damon_sysfs_schemes_rm_dirs(schemes); 1318 if (!nr_schemes) 1319 return 0; 1320 1321 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr), 1322 GFP_KERNEL | __GFP_NOWARN); 1323 if (!schemes_arr) 1324 return -ENOMEM; 1325 schemes->schemes_arr = schemes_arr; 1326 1327 for (i = 0; i < nr_schemes; i++) { 1328 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT); 1329 if (!scheme) { 1330 damon_sysfs_schemes_rm_dirs(schemes); 1331 return -ENOMEM; 1332 } 1333 1334 err = kobject_init_and_add(&scheme->kobj, 1335 &damon_sysfs_scheme_ktype, &schemes->kobj, 1336 "%d", i); 1337 if (err) 1338 goto out; 1339 err = damon_sysfs_scheme_add_dirs(scheme); 1340 if (err) 1341 goto out; 1342 1343 schemes_arr[i] = scheme; 1344 schemes->nr++; 1345 } 1346 return 0; 1347 1348 out: 1349 damon_sysfs_schemes_rm_dirs(schemes); 1350 kobject_put(&scheme->kobj); 1351 return err; 1352 } 1353 1354 static ssize_t nr_schemes_show(struct kobject *kobj, 1355 struct kobj_attribute *attr, char *buf) 1356 { 1357 struct damon_sysfs_schemes *schemes = container_of(kobj, 1358 struct damon_sysfs_schemes, kobj); 1359 1360 return sysfs_emit(buf, "%d\n", schemes->nr); 1361 } 1362 1363 static ssize_t nr_schemes_store(struct kobject *kobj, 1364 struct kobj_attribute *attr, const char *buf, size_t count) 1365 { 1366 struct damon_sysfs_schemes *schemes; 1367 int nr, err = kstrtoint(buf, 0, &nr); 1368 1369 if (err) 1370 return err; 1371 if (nr < 0) 1372 return -EINVAL; 1373 1374 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj); 1375 1376 if (!mutex_trylock(&damon_sysfs_lock)) 1377 return -EBUSY; 1378 err = damon_sysfs_schemes_add_dirs(schemes, nr); 1379 mutex_unlock(&damon_sysfs_lock); 1380 if (err) 1381 return err; 1382 return count; 1383 } 1384 1385 static void damon_sysfs_schemes_release(struct kobject *kobj) 1386 { 1387 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj)); 1388 } 1389 1390 static struct kobj_attribute damon_sysfs_schemes_nr_attr = 1391 __ATTR_RW_MODE(nr_schemes, 0600); 1392 1393 static struct attribute *damon_sysfs_schemes_attrs[] = { 1394 &damon_sysfs_schemes_nr_attr.attr, 1395 NULL, 1396 }; 1397 ATTRIBUTE_GROUPS(damon_sysfs_schemes); 1398 1399 const struct kobj_type damon_sysfs_schemes_ktype = { 1400 .release = damon_sysfs_schemes_release, 1401 .sysfs_ops = &kobj_sysfs_ops, 1402 .default_groups = damon_sysfs_schemes_groups, 1403 }; 1404 1405 static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg, 1406 char *memcg_path_buf, char *path) 1407 { 1408 #ifdef CONFIG_MEMCG 1409 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX); 1410 if (sysfs_streq(memcg_path_buf, path)) 1411 return true; 1412 #endif /* CONFIG_MEMCG */ 1413 return false; 1414 } 1415 1416 static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id) 1417 { 1418 struct mem_cgroup *memcg; 1419 char *path; 1420 bool found = false; 1421 1422 if (!memcg_path) 1423 return -EINVAL; 1424 1425 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL); 1426 if (!path) 1427 return -ENOMEM; 1428 1429 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg; 1430 memcg = mem_cgroup_iter(NULL, memcg, NULL)) { 1431 /* skip removed memcg */ 1432 if (!mem_cgroup_id(memcg)) 1433 continue; 1434 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) { 1435 *id = mem_cgroup_id(memcg); 1436 found = true; 1437 break; 1438 } 1439 } 1440 1441 kfree(path); 1442 return found ? 0 : -EINVAL; 1443 } 1444 1445 static int damon_sysfs_set_scheme_filters(struct damos *scheme, 1446 struct damon_sysfs_scheme_filters *sysfs_filters) 1447 { 1448 int i; 1449 struct damos_filter *filter, *next; 1450 1451 damos_for_each_filter_safe(filter, next, scheme) 1452 damos_destroy_filter(filter); 1453 1454 for (i = 0; i < sysfs_filters->nr; i++) { 1455 struct damon_sysfs_scheme_filter *sysfs_filter = 1456 sysfs_filters->filters_arr[i]; 1457 struct damos_filter *filter = 1458 damos_new_filter(sysfs_filter->type, 1459 sysfs_filter->matching); 1460 int err; 1461 1462 if (!filter) 1463 return -ENOMEM; 1464 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) { 1465 err = damon_sysfs_memcg_path_to_id( 1466 sysfs_filter->memcg_path, 1467 &filter->memcg_id); 1468 if (err) { 1469 damos_destroy_filter(filter); 1470 return err; 1471 } 1472 } 1473 damos_add_filter(scheme, filter); 1474 } 1475 return 0; 1476 } 1477 1478 static struct damos *damon_sysfs_mk_scheme( 1479 struct damon_sysfs_scheme *sysfs_scheme) 1480 { 1481 struct damon_sysfs_access_pattern *access_pattern = 1482 sysfs_scheme->access_pattern; 1483 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas; 1484 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights; 1485 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks; 1486 struct damon_sysfs_scheme_filters *sysfs_filters = 1487 sysfs_scheme->filters; 1488 struct damos *scheme; 1489 int err; 1490 1491 struct damos_access_pattern pattern = { 1492 .min_sz_region = access_pattern->sz->min, 1493 .max_sz_region = access_pattern->sz->max, 1494 .min_nr_accesses = access_pattern->nr_accesses->min, 1495 .max_nr_accesses = access_pattern->nr_accesses->max, 1496 .min_age_region = access_pattern->age->min, 1497 .max_age_region = access_pattern->age->max, 1498 }; 1499 struct damos_quota quota = { 1500 .ms = sysfs_quotas->ms, 1501 .sz = sysfs_quotas->sz, 1502 .reset_interval = sysfs_quotas->reset_interval_ms, 1503 .weight_sz = sysfs_weights->sz, 1504 .weight_nr_accesses = sysfs_weights->nr_accesses, 1505 .weight_age = sysfs_weights->age, 1506 }; 1507 struct damos_watermarks wmarks = { 1508 .metric = sysfs_wmarks->metric, 1509 .interval = sysfs_wmarks->interval_us, 1510 .high = sysfs_wmarks->high, 1511 .mid = sysfs_wmarks->mid, 1512 .low = sysfs_wmarks->low, 1513 }; 1514 1515 scheme = damon_new_scheme(&pattern, sysfs_scheme->action, "a, 1516 &wmarks); 1517 if (!scheme) 1518 return NULL; 1519 1520 err = damon_sysfs_set_scheme_filters(scheme, sysfs_filters); 1521 if (err) { 1522 damon_destroy_scheme(scheme); 1523 return NULL; 1524 } 1525 return scheme; 1526 } 1527 1528 static void damon_sysfs_update_scheme(struct damos *scheme, 1529 struct damon_sysfs_scheme *sysfs_scheme) 1530 { 1531 struct damon_sysfs_access_pattern *access_pattern = 1532 sysfs_scheme->access_pattern; 1533 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas; 1534 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights; 1535 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks; 1536 int err; 1537 1538 scheme->pattern.min_sz_region = access_pattern->sz->min; 1539 scheme->pattern.max_sz_region = access_pattern->sz->max; 1540 scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min; 1541 scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max; 1542 scheme->pattern.min_age_region = access_pattern->age->min; 1543 scheme->pattern.max_age_region = access_pattern->age->max; 1544 1545 scheme->action = sysfs_scheme->action; 1546 1547 scheme->quota.ms = sysfs_quotas->ms; 1548 scheme->quota.sz = sysfs_quotas->sz; 1549 scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms; 1550 scheme->quota.weight_sz = sysfs_weights->sz; 1551 scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses; 1552 scheme->quota.weight_age = sysfs_weights->age; 1553 1554 scheme->wmarks.metric = sysfs_wmarks->metric; 1555 scheme->wmarks.interval = sysfs_wmarks->interval_us; 1556 scheme->wmarks.high = sysfs_wmarks->high; 1557 scheme->wmarks.mid = sysfs_wmarks->mid; 1558 scheme->wmarks.low = sysfs_wmarks->low; 1559 1560 err = damon_sysfs_set_scheme_filters(scheme, sysfs_scheme->filters); 1561 if (err) 1562 damon_destroy_scheme(scheme); 1563 } 1564 1565 int damon_sysfs_set_schemes(struct damon_ctx *ctx, 1566 struct damon_sysfs_schemes *sysfs_schemes) 1567 { 1568 struct damos *scheme, *next; 1569 int i = 0; 1570 1571 damon_for_each_scheme_safe(scheme, next, ctx) { 1572 if (i < sysfs_schemes->nr) 1573 damon_sysfs_update_scheme(scheme, 1574 sysfs_schemes->schemes_arr[i]); 1575 else 1576 damon_destroy_scheme(scheme); 1577 i++; 1578 } 1579 1580 for (; i < sysfs_schemes->nr; i++) { 1581 struct damos *scheme, *next; 1582 1583 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]); 1584 if (!scheme) { 1585 damon_for_each_scheme_safe(scheme, next, ctx) 1586 damon_destroy_scheme(scheme); 1587 return -ENOMEM; 1588 } 1589 damon_add_scheme(ctx, scheme); 1590 } 1591 return 0; 1592 } 1593 1594 void damon_sysfs_schemes_update_stats( 1595 struct damon_sysfs_schemes *sysfs_schemes, 1596 struct damon_ctx *ctx) 1597 { 1598 struct damos *scheme; 1599 int schemes_idx = 0; 1600 1601 damon_for_each_scheme(scheme, ctx) { 1602 struct damon_sysfs_stats *sysfs_stats; 1603 1604 /* user could have removed the scheme sysfs dir */ 1605 if (schemes_idx >= sysfs_schemes->nr) 1606 break; 1607 1608 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats; 1609 sysfs_stats->nr_tried = scheme->stat.nr_tried; 1610 sysfs_stats->sz_tried = scheme->stat.sz_tried; 1611 sysfs_stats->nr_applied = scheme->stat.nr_applied; 1612 sysfs_stats->sz_applied = scheme->stat.sz_applied; 1613 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds; 1614 } 1615 } 1616 1617 /* 1618 * damon_sysfs_schemes that need to update its schemes regions dir. Protected 1619 * by damon_sysfs_lock 1620 */ 1621 static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback; 1622 static int damon_sysfs_schemes_region_idx; 1623 1624 /* 1625 * DAMON callback that called before damos apply. While this callback is 1626 * registered, damon_sysfs_lock should be held to ensure the regions 1627 * directories exist. 1628 */ 1629 static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx, 1630 struct damon_target *t, struct damon_region *r, 1631 struct damos *s) 1632 { 1633 struct damos *scheme; 1634 struct damon_sysfs_scheme_regions *sysfs_regions; 1635 struct damon_sysfs_scheme_region *region; 1636 struct damon_sysfs_schemes *sysfs_schemes = 1637 damon_sysfs_schemes_for_damos_callback; 1638 int schemes_idx = 0; 1639 1640 damon_for_each_scheme(scheme, ctx) { 1641 if (scheme == s) 1642 break; 1643 schemes_idx++; 1644 } 1645 1646 /* user could have removed the scheme sysfs dir */ 1647 if (schemes_idx >= sysfs_schemes->nr) 1648 return 0; 1649 1650 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions; 1651 region = damon_sysfs_scheme_region_alloc(r); 1652 list_add_tail(®ion->list, &sysfs_regions->regions_list); 1653 sysfs_regions->nr_regions++; 1654 if (kobject_init_and_add(®ion->kobj, 1655 &damon_sysfs_scheme_region_ktype, 1656 &sysfs_regions->kobj, "%d", 1657 damon_sysfs_schemes_region_idx++)) { 1658 kobject_put(®ion->kobj); 1659 } 1660 return 0; 1661 } 1662 1663 /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */ 1664 int damon_sysfs_schemes_clear_regions( 1665 struct damon_sysfs_schemes *sysfs_schemes, 1666 struct damon_ctx *ctx) 1667 { 1668 struct damos *scheme; 1669 int schemes_idx = 0; 1670 1671 damon_for_each_scheme(scheme, ctx) { 1672 struct damon_sysfs_scheme *sysfs_scheme; 1673 1674 /* user could have removed the scheme sysfs dir */ 1675 if (schemes_idx >= sysfs_schemes->nr) 1676 break; 1677 1678 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++]; 1679 damon_sysfs_scheme_regions_rm_dirs( 1680 sysfs_scheme->tried_regions); 1681 } 1682 return 0; 1683 } 1684 1685 /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */ 1686 int damon_sysfs_schemes_update_regions_start( 1687 struct damon_sysfs_schemes *sysfs_schemes, 1688 struct damon_ctx *ctx) 1689 { 1690 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx); 1691 damon_sysfs_schemes_for_damos_callback = sysfs_schemes; 1692 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply; 1693 return 0; 1694 } 1695 1696 /* 1697 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller 1698 * should unlock damon_sysfs_lock which held before 1699 * damon_sysfs_schemes_update_regions_start() 1700 */ 1701 int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx) 1702 { 1703 damon_sysfs_schemes_for_damos_callback = NULL; 1704 ctx->callback.before_damos_apply = NULL; 1705 damon_sysfs_schemes_region_idx = 0; 1706 return 0; 1707 } 1708