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