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