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