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 #include <linux/numa.h> 10 11 #include "sysfs-common.h" 12 13 /* 14 * scheme region directory 15 */ 16 17 struct damon_sysfs_scheme_region { 18 struct kobject kobj; 19 struct damon_addr_range ar; 20 unsigned int nr_accesses; 21 unsigned int age; 22 unsigned long sz_filter_passed; 23 struct list_head list; 24 }; 25 26 static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc( 27 struct damon_region *region) 28 { 29 struct damon_sysfs_scheme_region *sysfs_region = kmalloc( 30 sizeof(*sysfs_region), GFP_KERNEL); 31 32 if (!sysfs_region) 33 return NULL; 34 sysfs_region->kobj = (struct kobject){}; 35 sysfs_region->ar = region->ar; 36 sysfs_region->nr_accesses = region->nr_accesses_bp / 10000; 37 sysfs_region->age = region->age; 38 INIT_LIST_HEAD(&sysfs_region->list); 39 return sysfs_region; 40 } 41 42 static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr, 43 char *buf) 44 { 45 struct damon_sysfs_scheme_region *region = container_of(kobj, 46 struct damon_sysfs_scheme_region, kobj); 47 48 return sysfs_emit(buf, "%lu\n", region->ar.start); 49 } 50 51 static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr, 52 char *buf) 53 { 54 struct damon_sysfs_scheme_region *region = container_of(kobj, 55 struct damon_sysfs_scheme_region, kobj); 56 57 return sysfs_emit(buf, "%lu\n", region->ar.end); 58 } 59 60 static ssize_t nr_accesses_show(struct kobject *kobj, 61 struct kobj_attribute *attr, char *buf) 62 { 63 struct damon_sysfs_scheme_region *region = container_of(kobj, 64 struct damon_sysfs_scheme_region, kobj); 65 66 return sysfs_emit(buf, "%u\n", region->nr_accesses); 67 } 68 69 static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr, 70 char *buf) 71 { 72 struct damon_sysfs_scheme_region *region = container_of(kobj, 73 struct damon_sysfs_scheme_region, kobj); 74 75 return sysfs_emit(buf, "%u\n", region->age); 76 } 77 78 static ssize_t sz_filter_passed_show(struct kobject *kobj, 79 struct kobj_attribute *attr, char *buf) 80 { 81 struct damon_sysfs_scheme_region *region = container_of(kobj, 82 struct damon_sysfs_scheme_region, kobj); 83 84 return sysfs_emit(buf, "%lu\n", region->sz_filter_passed); 85 } 86 87 static void damon_sysfs_scheme_region_release(struct kobject *kobj) 88 { 89 struct damon_sysfs_scheme_region *region = container_of(kobj, 90 struct damon_sysfs_scheme_region, kobj); 91 92 list_del(®ion->list); 93 kfree(region); 94 } 95 96 static struct kobj_attribute damon_sysfs_scheme_region_start_attr = 97 __ATTR_RO_MODE(start, 0400); 98 99 static struct kobj_attribute damon_sysfs_scheme_region_end_attr = 100 __ATTR_RO_MODE(end, 0400); 101 102 static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr = 103 __ATTR_RO_MODE(nr_accesses, 0400); 104 105 static struct kobj_attribute damon_sysfs_scheme_region_age_attr = 106 __ATTR_RO_MODE(age, 0400); 107 108 static struct kobj_attribute damon_sysfs_scheme_region_sz_filter_passed_attr = 109 __ATTR_RO_MODE(sz_filter_passed, 0400); 110 111 static struct attribute *damon_sysfs_scheme_region_attrs[] = { 112 &damon_sysfs_scheme_region_start_attr.attr, 113 &damon_sysfs_scheme_region_end_attr.attr, 114 &damon_sysfs_scheme_region_nr_accesses_attr.attr, 115 &damon_sysfs_scheme_region_age_attr.attr, 116 &damon_sysfs_scheme_region_sz_filter_passed_attr.attr, 117 NULL, 118 }; 119 ATTRIBUTE_GROUPS(damon_sysfs_scheme_region); 120 121 static const struct kobj_type damon_sysfs_scheme_region_ktype = { 122 .release = damon_sysfs_scheme_region_release, 123 .sysfs_ops = &kobj_sysfs_ops, 124 .default_groups = damon_sysfs_scheme_region_groups, 125 }; 126 127 /* 128 * scheme regions directory 129 */ 130 131 struct damon_sysfs_scheme_regions { 132 struct kobject kobj; 133 struct list_head regions_list; 134 int nr_regions; 135 unsigned long total_bytes; 136 }; 137 138 static struct damon_sysfs_scheme_regions * 139 damon_sysfs_scheme_regions_alloc(void) 140 { 141 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions), 142 GFP_KERNEL); 143 144 if (!regions) 145 return NULL; 146 147 regions->kobj = (struct kobject){}; 148 INIT_LIST_HEAD(®ions->regions_list); 149 regions->nr_regions = 0; 150 regions->total_bytes = 0; 151 return regions; 152 } 153 154 static ssize_t total_bytes_show(struct kobject *kobj, 155 struct kobj_attribute *attr, char *buf) 156 { 157 struct damon_sysfs_scheme_regions *regions = container_of(kobj, 158 struct damon_sysfs_scheme_regions, kobj); 159 160 return sysfs_emit(buf, "%lu\n", regions->total_bytes); 161 } 162 163 static void damon_sysfs_scheme_regions_rm_dirs( 164 struct damon_sysfs_scheme_regions *regions) 165 { 166 struct damon_sysfs_scheme_region *r, *next; 167 168 list_for_each_entry_safe(r, next, ®ions->regions_list, list) { 169 /* release function deletes it from the list */ 170 kobject_put(&r->kobj); 171 regions->nr_regions--; 172 } 173 } 174 175 static void damon_sysfs_scheme_regions_release(struct kobject *kobj) 176 { 177 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj)); 178 } 179 180 static struct kobj_attribute damon_sysfs_scheme_regions_total_bytes_attr = 181 __ATTR_RO_MODE(total_bytes, 0400); 182 183 static struct attribute *damon_sysfs_scheme_regions_attrs[] = { 184 &damon_sysfs_scheme_regions_total_bytes_attr.attr, 185 NULL, 186 }; 187 ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions); 188 189 static const struct kobj_type damon_sysfs_scheme_regions_ktype = { 190 .release = damon_sysfs_scheme_regions_release, 191 .sysfs_ops = &kobj_sysfs_ops, 192 .default_groups = damon_sysfs_scheme_regions_groups, 193 }; 194 195 /* 196 * schemes/stats directory 197 */ 198 199 struct damon_sysfs_stats { 200 struct kobject kobj; 201 unsigned long nr_tried; 202 unsigned long sz_tried; 203 unsigned long nr_applied; 204 unsigned long sz_applied; 205 unsigned long sz_ops_filter_passed; 206 unsigned long qt_exceeds; 207 }; 208 209 static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void) 210 { 211 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL); 212 } 213 214 static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr, 215 char *buf) 216 { 217 struct damon_sysfs_stats *stats = container_of(kobj, 218 struct damon_sysfs_stats, kobj); 219 220 return sysfs_emit(buf, "%lu\n", stats->nr_tried); 221 } 222 223 static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr, 224 char *buf) 225 { 226 struct damon_sysfs_stats *stats = container_of(kobj, 227 struct damon_sysfs_stats, kobj); 228 229 return sysfs_emit(buf, "%lu\n", stats->sz_tried); 230 } 231 232 static ssize_t nr_applied_show(struct kobject *kobj, 233 struct kobj_attribute *attr, char *buf) 234 { 235 struct damon_sysfs_stats *stats = container_of(kobj, 236 struct damon_sysfs_stats, kobj); 237 238 return sysfs_emit(buf, "%lu\n", stats->nr_applied); 239 } 240 241 static ssize_t sz_applied_show(struct kobject *kobj, 242 struct kobj_attribute *attr, char *buf) 243 { 244 struct damon_sysfs_stats *stats = container_of(kobj, 245 struct damon_sysfs_stats, kobj); 246 247 return sysfs_emit(buf, "%lu\n", stats->sz_applied); 248 } 249 250 static ssize_t sz_ops_filter_passed_show(struct kobject *kobj, 251 struct kobj_attribute *attr, char *buf) 252 { 253 struct damon_sysfs_stats *stats = container_of(kobj, 254 struct damon_sysfs_stats, kobj); 255 256 return sysfs_emit(buf, "%lu\n", stats->sz_ops_filter_passed); 257 } 258 259 static ssize_t qt_exceeds_show(struct kobject *kobj, 260 struct kobj_attribute *attr, char *buf) 261 { 262 struct damon_sysfs_stats *stats = container_of(kobj, 263 struct damon_sysfs_stats, kobj); 264 265 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds); 266 } 267 268 static void damon_sysfs_stats_release(struct kobject *kobj) 269 { 270 kfree(container_of(kobj, struct damon_sysfs_stats, kobj)); 271 } 272 273 static struct kobj_attribute damon_sysfs_stats_nr_tried_attr = 274 __ATTR_RO_MODE(nr_tried, 0400); 275 276 static struct kobj_attribute damon_sysfs_stats_sz_tried_attr = 277 __ATTR_RO_MODE(sz_tried, 0400); 278 279 static struct kobj_attribute damon_sysfs_stats_nr_applied_attr = 280 __ATTR_RO_MODE(nr_applied, 0400); 281 282 static struct kobj_attribute damon_sysfs_stats_sz_applied_attr = 283 __ATTR_RO_MODE(sz_applied, 0400); 284 285 static struct kobj_attribute damon_sysfs_stats_sz_ops_filter_passed_attr = 286 __ATTR_RO_MODE(sz_ops_filter_passed, 0400); 287 288 static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr = 289 __ATTR_RO_MODE(qt_exceeds, 0400); 290 291 static struct attribute *damon_sysfs_stats_attrs[] = { 292 &damon_sysfs_stats_nr_tried_attr.attr, 293 &damon_sysfs_stats_sz_tried_attr.attr, 294 &damon_sysfs_stats_nr_applied_attr.attr, 295 &damon_sysfs_stats_sz_applied_attr.attr, 296 &damon_sysfs_stats_sz_ops_filter_passed_attr.attr, 297 &damon_sysfs_stats_qt_exceeds_attr.attr, 298 NULL, 299 }; 300 ATTRIBUTE_GROUPS(damon_sysfs_stats); 301 302 static const struct kobj_type damon_sysfs_stats_ktype = { 303 .release = damon_sysfs_stats_release, 304 .sysfs_ops = &kobj_sysfs_ops, 305 .default_groups = damon_sysfs_stats_groups, 306 }; 307 308 /* 309 * filter directory 310 */ 311 312 struct damon_sysfs_scheme_filter { 313 struct kobject kobj; 314 enum damos_filter_type type; 315 bool matching; 316 bool allow; 317 char *memcg_path; 318 struct damon_addr_range addr_range; 319 int target_idx; 320 }; 321 322 static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(void) 323 { 324 return kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL); 325 } 326 327 /* Should match with enum damos_filter_type */ 328 static const char * const damon_sysfs_scheme_filter_type_strs[] = { 329 "anon", 330 "memcg", 331 "young", 332 "addr", 333 "target", 334 }; 335 336 static ssize_t type_show(struct kobject *kobj, 337 struct kobj_attribute *attr, char *buf) 338 { 339 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 340 struct damon_sysfs_scheme_filter, kobj); 341 342 return sysfs_emit(buf, "%s\n", 343 damon_sysfs_scheme_filter_type_strs[filter->type]); 344 } 345 346 static ssize_t type_store(struct kobject *kobj, 347 struct kobj_attribute *attr, const char *buf, size_t count) 348 { 349 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 350 struct damon_sysfs_scheme_filter, kobj); 351 enum damos_filter_type type; 352 ssize_t ret = -EINVAL; 353 354 for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) { 355 if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[ 356 type])) { 357 filter->type = type; 358 ret = count; 359 break; 360 } 361 } 362 return ret; 363 } 364 365 static ssize_t matching_show(struct kobject *kobj, 366 struct kobj_attribute *attr, char *buf) 367 { 368 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 369 struct damon_sysfs_scheme_filter, kobj); 370 371 return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N'); 372 } 373 374 static ssize_t matching_store(struct kobject *kobj, 375 struct kobj_attribute *attr, const char *buf, size_t count) 376 { 377 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 378 struct damon_sysfs_scheme_filter, kobj); 379 bool matching; 380 int err = kstrtobool(buf, &matching); 381 382 if (err) 383 return err; 384 385 filter->matching = matching; 386 return count; 387 } 388 389 static ssize_t allow_show(struct kobject *kobj, 390 struct kobj_attribute *attr, char *buf) 391 { 392 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 393 struct damon_sysfs_scheme_filter, kobj); 394 395 return sysfs_emit(buf, "%c\n", filter->allow ? 'Y' : 'N'); 396 } 397 398 static ssize_t allow_store(struct kobject *kobj, 399 struct kobj_attribute *attr, const char *buf, size_t count) 400 { 401 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 402 struct damon_sysfs_scheme_filter, kobj); 403 bool allow; 404 int err = kstrtobool(buf, &allow); 405 406 if (err) 407 return err; 408 409 filter->allow = allow; 410 return count; 411 } 412 413 static ssize_t memcg_path_show(struct kobject *kobj, 414 struct kobj_attribute *attr, char *buf) 415 { 416 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 417 struct damon_sysfs_scheme_filter, kobj); 418 419 return sysfs_emit(buf, "%s\n", 420 filter->memcg_path ? filter->memcg_path : ""); 421 } 422 423 static ssize_t memcg_path_store(struct kobject *kobj, 424 struct kobj_attribute *attr, const char *buf, size_t count) 425 { 426 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 427 struct damon_sysfs_scheme_filter, kobj); 428 char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL); 429 430 if (!path) 431 return -ENOMEM; 432 433 strscpy(path, buf, count + 1); 434 filter->memcg_path = path; 435 return count; 436 } 437 438 static ssize_t addr_start_show(struct kobject *kobj, 439 struct kobj_attribute *attr, char *buf) 440 { 441 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 442 struct damon_sysfs_scheme_filter, kobj); 443 444 return sysfs_emit(buf, "%lu\n", filter->addr_range.start); 445 } 446 447 static ssize_t addr_start_store(struct kobject *kobj, 448 struct kobj_attribute *attr, const char *buf, size_t count) 449 { 450 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 451 struct damon_sysfs_scheme_filter, kobj); 452 int err = kstrtoul(buf, 0, &filter->addr_range.start); 453 454 return err ? err : count; 455 } 456 457 static ssize_t addr_end_show(struct kobject *kobj, 458 struct kobj_attribute *attr, char *buf) 459 { 460 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 461 struct damon_sysfs_scheme_filter, kobj); 462 463 return sysfs_emit(buf, "%lu\n", filter->addr_range.end); 464 } 465 466 static ssize_t addr_end_store(struct kobject *kobj, 467 struct kobj_attribute *attr, const char *buf, size_t count) 468 { 469 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 470 struct damon_sysfs_scheme_filter, kobj); 471 int err = kstrtoul(buf, 0, &filter->addr_range.end); 472 473 return err ? err : count; 474 } 475 476 static ssize_t damon_target_idx_show(struct kobject *kobj, 477 struct kobj_attribute *attr, char *buf) 478 { 479 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 480 struct damon_sysfs_scheme_filter, kobj); 481 482 return sysfs_emit(buf, "%d\n", filter->target_idx); 483 } 484 485 static ssize_t damon_target_idx_store(struct kobject *kobj, 486 struct kobj_attribute *attr, const char *buf, size_t count) 487 { 488 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 489 struct damon_sysfs_scheme_filter, kobj); 490 int err = kstrtoint(buf, 0, &filter->target_idx); 491 492 return err ? err : count; 493 } 494 495 static void damon_sysfs_scheme_filter_release(struct kobject *kobj) 496 { 497 struct damon_sysfs_scheme_filter *filter = container_of(kobj, 498 struct damon_sysfs_scheme_filter, kobj); 499 500 kfree(filter->memcg_path); 501 kfree(filter); 502 } 503 504 static struct kobj_attribute damon_sysfs_scheme_filter_type_attr = 505 __ATTR_RW_MODE(type, 0600); 506 507 static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr = 508 __ATTR_RW_MODE(matching, 0600); 509 510 static struct kobj_attribute damon_sysfs_scheme_filter_allow_attr = 511 __ATTR_RW_MODE(allow, 0600); 512 513 static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr = 514 __ATTR_RW_MODE(memcg_path, 0600); 515 516 static struct kobj_attribute damon_sysfs_scheme_filter_addr_start_attr = 517 __ATTR_RW_MODE(addr_start, 0600); 518 519 static struct kobj_attribute damon_sysfs_scheme_filter_addr_end_attr = 520 __ATTR_RW_MODE(addr_end, 0600); 521 522 static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr = 523 __ATTR_RW_MODE(damon_target_idx, 0600); 524 525 static struct attribute *damon_sysfs_scheme_filter_attrs[] = { 526 &damon_sysfs_scheme_filter_type_attr.attr, 527 &damon_sysfs_scheme_filter_matching_attr.attr, 528 &damon_sysfs_scheme_filter_allow_attr.attr, 529 &damon_sysfs_scheme_filter_memcg_path_attr.attr, 530 &damon_sysfs_scheme_filter_addr_start_attr.attr, 531 &damon_sysfs_scheme_filter_addr_end_attr.attr, 532 &damon_sysfs_scheme_filter_damon_target_idx_attr.attr, 533 NULL, 534 }; 535 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter); 536 537 static const struct kobj_type damon_sysfs_scheme_filter_ktype = { 538 .release = damon_sysfs_scheme_filter_release, 539 .sysfs_ops = &kobj_sysfs_ops, 540 .default_groups = damon_sysfs_scheme_filter_groups, 541 }; 542 543 /* 544 * filters directory 545 */ 546 547 struct damon_sysfs_scheme_filters { 548 struct kobject kobj; 549 struct damon_sysfs_scheme_filter **filters_arr; 550 int nr; 551 }; 552 553 static struct damon_sysfs_scheme_filters * 554 damon_sysfs_scheme_filters_alloc(void) 555 { 556 return kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL); 557 } 558 559 static void damon_sysfs_scheme_filters_rm_dirs( 560 struct damon_sysfs_scheme_filters *filters) 561 { 562 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr; 563 int i; 564 565 for (i = 0; i < filters->nr; i++) 566 kobject_put(&filters_arr[i]->kobj); 567 filters->nr = 0; 568 kfree(filters_arr); 569 filters->filters_arr = NULL; 570 } 571 572 static int damon_sysfs_scheme_filters_add_dirs( 573 struct damon_sysfs_scheme_filters *filters, int nr_filters) 574 { 575 struct damon_sysfs_scheme_filter **filters_arr, *filter; 576 int err, i; 577 578 damon_sysfs_scheme_filters_rm_dirs(filters); 579 if (!nr_filters) 580 return 0; 581 582 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr), 583 GFP_KERNEL | __GFP_NOWARN); 584 if (!filters_arr) 585 return -ENOMEM; 586 filters->filters_arr = filters_arr; 587 588 for (i = 0; i < nr_filters; i++) { 589 filter = damon_sysfs_scheme_filter_alloc(); 590 if (!filter) { 591 damon_sysfs_scheme_filters_rm_dirs(filters); 592 return -ENOMEM; 593 } 594 595 err = kobject_init_and_add(&filter->kobj, 596 &damon_sysfs_scheme_filter_ktype, 597 &filters->kobj, "%d", i); 598 if (err) { 599 kobject_put(&filter->kobj); 600 damon_sysfs_scheme_filters_rm_dirs(filters); 601 return err; 602 } 603 604 filters_arr[i] = filter; 605 filters->nr++; 606 } 607 return 0; 608 } 609 610 static ssize_t nr_filters_show(struct kobject *kobj, 611 struct kobj_attribute *attr, char *buf) 612 { 613 struct damon_sysfs_scheme_filters *filters = container_of(kobj, 614 struct damon_sysfs_scheme_filters, kobj); 615 616 return sysfs_emit(buf, "%d\n", filters->nr); 617 } 618 619 static ssize_t nr_filters_store(struct kobject *kobj, 620 struct kobj_attribute *attr, const char *buf, size_t count) 621 { 622 struct damon_sysfs_scheme_filters *filters; 623 int nr, err = kstrtoint(buf, 0, &nr); 624 625 if (err) 626 return err; 627 if (nr < 0) 628 return -EINVAL; 629 630 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj); 631 632 if (!mutex_trylock(&damon_sysfs_lock)) 633 return -EBUSY; 634 err = damon_sysfs_scheme_filters_add_dirs(filters, nr); 635 mutex_unlock(&damon_sysfs_lock); 636 if (err) 637 return err; 638 639 return count; 640 } 641 642 static void damon_sysfs_scheme_filters_release(struct kobject *kobj) 643 { 644 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj)); 645 } 646 647 static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr = 648 __ATTR_RW_MODE(nr_filters, 0600); 649 650 static struct attribute *damon_sysfs_scheme_filters_attrs[] = { 651 &damon_sysfs_scheme_filters_nr_attr.attr, 652 NULL, 653 }; 654 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters); 655 656 static const struct kobj_type damon_sysfs_scheme_filters_ktype = { 657 .release = damon_sysfs_scheme_filters_release, 658 .sysfs_ops = &kobj_sysfs_ops, 659 .default_groups = damon_sysfs_scheme_filters_groups, 660 }; 661 662 /* 663 * watermarks directory 664 */ 665 666 struct damon_sysfs_watermarks { 667 struct kobject kobj; 668 enum damos_wmark_metric metric; 669 unsigned long interval_us; 670 unsigned long high; 671 unsigned long mid; 672 unsigned long low; 673 }; 674 675 static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc( 676 enum damos_wmark_metric metric, unsigned long interval_us, 677 unsigned long high, unsigned long mid, unsigned long low) 678 { 679 struct damon_sysfs_watermarks *watermarks = kmalloc( 680 sizeof(*watermarks), GFP_KERNEL); 681 682 if (!watermarks) 683 return NULL; 684 watermarks->kobj = (struct kobject){}; 685 watermarks->metric = metric; 686 watermarks->interval_us = interval_us; 687 watermarks->high = high; 688 watermarks->mid = mid; 689 watermarks->low = low; 690 return watermarks; 691 } 692 693 /* Should match with enum damos_wmark_metric */ 694 static const char * const damon_sysfs_wmark_metric_strs[] = { 695 "none", 696 "free_mem_rate", 697 }; 698 699 static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr, 700 char *buf) 701 { 702 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 703 struct damon_sysfs_watermarks, kobj); 704 705 return sysfs_emit(buf, "%s\n", 706 damon_sysfs_wmark_metric_strs[watermarks->metric]); 707 } 708 709 static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr, 710 const char *buf, size_t count) 711 { 712 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 713 struct damon_sysfs_watermarks, kobj); 714 enum damos_wmark_metric metric; 715 716 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) { 717 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) { 718 watermarks->metric = metric; 719 return count; 720 } 721 } 722 return -EINVAL; 723 } 724 725 static ssize_t interval_us_show(struct kobject *kobj, 726 struct kobj_attribute *attr, char *buf) 727 { 728 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 729 struct damon_sysfs_watermarks, kobj); 730 731 return sysfs_emit(buf, "%lu\n", watermarks->interval_us); 732 } 733 734 static ssize_t interval_us_store(struct kobject *kobj, 735 struct kobj_attribute *attr, const char *buf, size_t count) 736 { 737 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 738 struct damon_sysfs_watermarks, kobj); 739 int err = kstrtoul(buf, 0, &watermarks->interval_us); 740 741 return err ? err : count; 742 } 743 744 static ssize_t high_show(struct kobject *kobj, 745 struct kobj_attribute *attr, char *buf) 746 { 747 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 748 struct damon_sysfs_watermarks, kobj); 749 750 return sysfs_emit(buf, "%lu\n", watermarks->high); 751 } 752 753 static ssize_t high_store(struct kobject *kobj, 754 struct kobj_attribute *attr, const char *buf, size_t count) 755 { 756 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 757 struct damon_sysfs_watermarks, kobj); 758 int err = kstrtoul(buf, 0, &watermarks->high); 759 760 return err ? err : count; 761 } 762 763 static ssize_t mid_show(struct kobject *kobj, 764 struct kobj_attribute *attr, char *buf) 765 { 766 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 767 struct damon_sysfs_watermarks, kobj); 768 769 return sysfs_emit(buf, "%lu\n", watermarks->mid); 770 } 771 772 static ssize_t mid_store(struct kobject *kobj, 773 struct kobj_attribute *attr, const char *buf, size_t count) 774 { 775 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 776 struct damon_sysfs_watermarks, kobj); 777 int err = kstrtoul(buf, 0, &watermarks->mid); 778 779 return err ? err : count; 780 } 781 782 static ssize_t low_show(struct kobject *kobj, 783 struct kobj_attribute *attr, char *buf) 784 { 785 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 786 struct damon_sysfs_watermarks, kobj); 787 788 return sysfs_emit(buf, "%lu\n", watermarks->low); 789 } 790 791 static ssize_t low_store(struct kobject *kobj, 792 struct kobj_attribute *attr, const char *buf, size_t count) 793 { 794 struct damon_sysfs_watermarks *watermarks = container_of(kobj, 795 struct damon_sysfs_watermarks, kobj); 796 int err = kstrtoul(buf, 0, &watermarks->low); 797 798 return err ? err : count; 799 } 800 801 static void damon_sysfs_watermarks_release(struct kobject *kobj) 802 { 803 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj)); 804 } 805 806 static struct kobj_attribute damon_sysfs_watermarks_metric_attr = 807 __ATTR_RW_MODE(metric, 0600); 808 809 static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr = 810 __ATTR_RW_MODE(interval_us, 0600); 811 812 static struct kobj_attribute damon_sysfs_watermarks_high_attr = 813 __ATTR_RW_MODE(high, 0600); 814 815 static struct kobj_attribute damon_sysfs_watermarks_mid_attr = 816 __ATTR_RW_MODE(mid, 0600); 817 818 static struct kobj_attribute damon_sysfs_watermarks_low_attr = 819 __ATTR_RW_MODE(low, 0600); 820 821 static struct attribute *damon_sysfs_watermarks_attrs[] = { 822 &damon_sysfs_watermarks_metric_attr.attr, 823 &damon_sysfs_watermarks_interval_us_attr.attr, 824 &damon_sysfs_watermarks_high_attr.attr, 825 &damon_sysfs_watermarks_mid_attr.attr, 826 &damon_sysfs_watermarks_low_attr.attr, 827 NULL, 828 }; 829 ATTRIBUTE_GROUPS(damon_sysfs_watermarks); 830 831 static const struct kobj_type damon_sysfs_watermarks_ktype = { 832 .release = damon_sysfs_watermarks_release, 833 .sysfs_ops = &kobj_sysfs_ops, 834 .default_groups = damon_sysfs_watermarks_groups, 835 }; 836 837 /* 838 * quota goal directory 839 */ 840 841 struct damos_sysfs_quota_goal { 842 struct kobject kobj; 843 enum damos_quota_goal_metric metric; 844 unsigned long target_value; 845 unsigned long current_value; 846 }; 847 848 /* This should match with enum damos_action */ 849 static const char * const damos_sysfs_quota_goal_metric_strs[] = { 850 "user_input", 851 "some_mem_psi_us", 852 }; 853 854 static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void) 855 { 856 return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL); 857 } 858 859 static ssize_t target_metric_show(struct kobject *kobj, 860 struct kobj_attribute *attr, char *buf) 861 { 862 struct damos_sysfs_quota_goal *goal = container_of(kobj, 863 struct damos_sysfs_quota_goal, kobj); 864 865 return sysfs_emit(buf, "%s\n", 866 damos_sysfs_quota_goal_metric_strs[goal->metric]); 867 } 868 869 static ssize_t target_metric_store(struct kobject *kobj, 870 struct kobj_attribute *attr, const char *buf, size_t count) 871 { 872 struct damos_sysfs_quota_goal *goal = container_of(kobj, 873 struct damos_sysfs_quota_goal, kobj); 874 enum damos_quota_goal_metric m; 875 876 for (m = 0; m < NR_DAMOS_QUOTA_GOAL_METRICS; m++) { 877 if (sysfs_streq(buf, damos_sysfs_quota_goal_metric_strs[m])) { 878 goal->metric = m; 879 return count; 880 } 881 } 882 return -EINVAL; 883 } 884 885 static ssize_t target_value_show(struct kobject *kobj, 886 struct kobj_attribute *attr, char *buf) 887 { 888 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct 889 damos_sysfs_quota_goal, kobj); 890 891 return sysfs_emit(buf, "%lu\n", goal->target_value); 892 } 893 894 static ssize_t target_value_store(struct kobject *kobj, 895 struct kobj_attribute *attr, const char *buf, size_t count) 896 { 897 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct 898 damos_sysfs_quota_goal, kobj); 899 int err = kstrtoul(buf, 0, &goal->target_value); 900 901 return err ? err : count; 902 } 903 904 static ssize_t current_value_show(struct kobject *kobj, 905 struct kobj_attribute *attr, char *buf) 906 { 907 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct 908 damos_sysfs_quota_goal, kobj); 909 910 return sysfs_emit(buf, "%lu\n", goal->current_value); 911 } 912 913 static ssize_t current_value_store(struct kobject *kobj, 914 struct kobj_attribute *attr, const char *buf, size_t count) 915 { 916 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct 917 damos_sysfs_quota_goal, kobj); 918 int err = kstrtoul(buf, 0, &goal->current_value); 919 920 /* feed callback should check existence of this file and read value */ 921 return err ? err : count; 922 } 923 924 static void damos_sysfs_quota_goal_release(struct kobject *kobj) 925 { 926 /* or, notify this release to the feed callback */ 927 kfree(container_of(kobj, struct damos_sysfs_quota_goal, kobj)); 928 } 929 930 static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr = 931 __ATTR_RW_MODE(target_metric, 0600); 932 933 static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr = 934 __ATTR_RW_MODE(target_value, 0600); 935 936 static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr = 937 __ATTR_RW_MODE(current_value, 0600); 938 939 static struct attribute *damos_sysfs_quota_goal_attrs[] = { 940 &damos_sysfs_quota_goal_target_metric_attr.attr, 941 &damos_sysfs_quota_goal_target_value_attr.attr, 942 &damos_sysfs_quota_goal_current_value_attr.attr, 943 NULL, 944 }; 945 ATTRIBUTE_GROUPS(damos_sysfs_quota_goal); 946 947 static const struct kobj_type damos_sysfs_quota_goal_ktype = { 948 .release = damos_sysfs_quota_goal_release, 949 .sysfs_ops = &kobj_sysfs_ops, 950 .default_groups = damos_sysfs_quota_goal_groups, 951 }; 952 953 /* 954 * quota goals directory 955 */ 956 957 struct damos_sysfs_quota_goals { 958 struct kobject kobj; 959 struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */ 960 int nr; 961 }; 962 963 static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void) 964 { 965 return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL); 966 } 967 968 static void damos_sysfs_quota_goals_rm_dirs( 969 struct damos_sysfs_quota_goals *goals) 970 { 971 struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr; 972 int i; 973 974 for (i = 0; i < goals->nr; i++) 975 kobject_put(&goals_arr[i]->kobj); 976 goals->nr = 0; 977 kfree(goals_arr); 978 goals->goals_arr = NULL; 979 } 980 981 static int damos_sysfs_quota_goals_add_dirs( 982 struct damos_sysfs_quota_goals *goals, int nr_goals) 983 { 984 struct damos_sysfs_quota_goal **goals_arr, *goal; 985 int err, i; 986 987 damos_sysfs_quota_goals_rm_dirs(goals); 988 if (!nr_goals) 989 return 0; 990 991 goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr), 992 GFP_KERNEL | __GFP_NOWARN); 993 if (!goals_arr) 994 return -ENOMEM; 995 goals->goals_arr = goals_arr; 996 997 for (i = 0; i < nr_goals; i++) { 998 goal = damos_sysfs_quota_goal_alloc(); 999 if (!goal) { 1000 damos_sysfs_quota_goals_rm_dirs(goals); 1001 return -ENOMEM; 1002 } 1003 1004 err = kobject_init_and_add(&goal->kobj, 1005 &damos_sysfs_quota_goal_ktype, &goals->kobj, 1006 "%d", i); 1007 if (err) { 1008 kobject_put(&goal->kobj); 1009 damos_sysfs_quota_goals_rm_dirs(goals); 1010 return err; 1011 } 1012 1013 goals_arr[i] = goal; 1014 goals->nr++; 1015 } 1016 return 0; 1017 } 1018 1019 static ssize_t nr_goals_show(struct kobject *kobj, 1020 struct kobj_attribute *attr, char *buf) 1021 { 1022 struct damos_sysfs_quota_goals *goals = container_of(kobj, 1023 struct damos_sysfs_quota_goals, kobj); 1024 1025 return sysfs_emit(buf, "%d\n", goals->nr); 1026 } 1027 1028 static ssize_t nr_goals_store(struct kobject *kobj, 1029 struct kobj_attribute *attr, const char *buf, size_t count) 1030 { 1031 struct damos_sysfs_quota_goals *goals; 1032 int nr, err = kstrtoint(buf, 0, &nr); 1033 1034 if (err) 1035 return err; 1036 if (nr < 0) 1037 return -EINVAL; 1038 1039 goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj); 1040 1041 if (!mutex_trylock(&damon_sysfs_lock)) 1042 return -EBUSY; 1043 err = damos_sysfs_quota_goals_add_dirs(goals, nr); 1044 mutex_unlock(&damon_sysfs_lock); 1045 if (err) 1046 return err; 1047 1048 return count; 1049 } 1050 1051 static void damos_sysfs_quota_goals_release(struct kobject *kobj) 1052 { 1053 kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj)); 1054 } 1055 1056 static struct kobj_attribute damos_sysfs_quota_goals_nr_attr = 1057 __ATTR_RW_MODE(nr_goals, 0600); 1058 1059 static struct attribute *damos_sysfs_quota_goals_attrs[] = { 1060 &damos_sysfs_quota_goals_nr_attr.attr, 1061 NULL, 1062 }; 1063 ATTRIBUTE_GROUPS(damos_sysfs_quota_goals); 1064 1065 static const struct kobj_type damos_sysfs_quota_goals_ktype = { 1066 .release = damos_sysfs_quota_goals_release, 1067 .sysfs_ops = &kobj_sysfs_ops, 1068 .default_groups = damos_sysfs_quota_goals_groups, 1069 }; 1070 1071 /* 1072 * scheme/weights directory 1073 */ 1074 1075 struct damon_sysfs_weights { 1076 struct kobject kobj; 1077 unsigned int sz; 1078 unsigned int nr_accesses; 1079 unsigned int age; 1080 }; 1081 1082 static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz, 1083 unsigned int nr_accesses, unsigned int age) 1084 { 1085 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights), 1086 GFP_KERNEL); 1087 1088 if (!weights) 1089 return NULL; 1090 weights->kobj = (struct kobject){}; 1091 weights->sz = sz; 1092 weights->nr_accesses = nr_accesses; 1093 weights->age = age; 1094 return weights; 1095 } 1096 1097 static ssize_t sz_permil_show(struct kobject *kobj, 1098 struct kobj_attribute *attr, char *buf) 1099 { 1100 struct damon_sysfs_weights *weights = container_of(kobj, 1101 struct damon_sysfs_weights, kobj); 1102 1103 return sysfs_emit(buf, "%u\n", weights->sz); 1104 } 1105 1106 static ssize_t sz_permil_store(struct kobject *kobj, 1107 struct kobj_attribute *attr, const char *buf, size_t count) 1108 { 1109 struct damon_sysfs_weights *weights = container_of(kobj, 1110 struct damon_sysfs_weights, kobj); 1111 int err = kstrtouint(buf, 0, &weights->sz); 1112 1113 return err ? err : count; 1114 } 1115 1116 static ssize_t nr_accesses_permil_show(struct kobject *kobj, 1117 struct kobj_attribute *attr, char *buf) 1118 { 1119 struct damon_sysfs_weights *weights = container_of(kobj, 1120 struct damon_sysfs_weights, kobj); 1121 1122 return sysfs_emit(buf, "%u\n", weights->nr_accesses); 1123 } 1124 1125 static ssize_t nr_accesses_permil_store(struct kobject *kobj, 1126 struct kobj_attribute *attr, const char *buf, size_t count) 1127 { 1128 struct damon_sysfs_weights *weights = container_of(kobj, 1129 struct damon_sysfs_weights, kobj); 1130 int err = kstrtouint(buf, 0, &weights->nr_accesses); 1131 1132 return err ? err : count; 1133 } 1134 1135 static ssize_t age_permil_show(struct kobject *kobj, 1136 struct kobj_attribute *attr, char *buf) 1137 { 1138 struct damon_sysfs_weights *weights = container_of(kobj, 1139 struct damon_sysfs_weights, kobj); 1140 1141 return sysfs_emit(buf, "%u\n", weights->age); 1142 } 1143 1144 static ssize_t age_permil_store(struct kobject *kobj, 1145 struct kobj_attribute *attr, const char *buf, size_t count) 1146 { 1147 struct damon_sysfs_weights *weights = container_of(kobj, 1148 struct damon_sysfs_weights, kobj); 1149 int err = kstrtouint(buf, 0, &weights->age); 1150 1151 return err ? err : count; 1152 } 1153 1154 static void damon_sysfs_weights_release(struct kobject *kobj) 1155 { 1156 kfree(container_of(kobj, struct damon_sysfs_weights, kobj)); 1157 } 1158 1159 static struct kobj_attribute damon_sysfs_weights_sz_attr = 1160 __ATTR_RW_MODE(sz_permil, 0600); 1161 1162 static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr = 1163 __ATTR_RW_MODE(nr_accesses_permil, 0600); 1164 1165 static struct kobj_attribute damon_sysfs_weights_age_attr = 1166 __ATTR_RW_MODE(age_permil, 0600); 1167 1168 static struct attribute *damon_sysfs_weights_attrs[] = { 1169 &damon_sysfs_weights_sz_attr.attr, 1170 &damon_sysfs_weights_nr_accesses_attr.attr, 1171 &damon_sysfs_weights_age_attr.attr, 1172 NULL, 1173 }; 1174 ATTRIBUTE_GROUPS(damon_sysfs_weights); 1175 1176 static const struct kobj_type damon_sysfs_weights_ktype = { 1177 .release = damon_sysfs_weights_release, 1178 .sysfs_ops = &kobj_sysfs_ops, 1179 .default_groups = damon_sysfs_weights_groups, 1180 }; 1181 1182 /* 1183 * quotas directory 1184 */ 1185 1186 struct damon_sysfs_quotas { 1187 struct kobject kobj; 1188 struct damon_sysfs_weights *weights; 1189 struct damos_sysfs_quota_goals *goals; 1190 unsigned long ms; 1191 unsigned long sz; 1192 unsigned long reset_interval_ms; 1193 unsigned long effective_sz; /* Effective size quota in bytes */ 1194 }; 1195 1196 static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void) 1197 { 1198 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL); 1199 } 1200 1201 static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas) 1202 { 1203 struct damon_sysfs_weights *weights; 1204 struct damos_sysfs_quota_goals *goals; 1205 int err; 1206 1207 weights = damon_sysfs_weights_alloc(0, 0, 0); 1208 if (!weights) 1209 return -ENOMEM; 1210 1211 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype, 1212 "as->kobj, "weights"); 1213 if (err) { 1214 kobject_put(&weights->kobj); 1215 return err; 1216 } 1217 quotas->weights = weights; 1218 1219 goals = damos_sysfs_quota_goals_alloc(); 1220 if (!goals) { 1221 kobject_put(&weights->kobj); 1222 return -ENOMEM; 1223 } 1224 err = kobject_init_and_add(&goals->kobj, 1225 &damos_sysfs_quota_goals_ktype, "as->kobj, 1226 "goals"); 1227 if (err) { 1228 kobject_put(&weights->kobj); 1229 kobject_put(&goals->kobj); 1230 } else { 1231 quotas->goals = goals; 1232 } 1233 1234 return err; 1235 } 1236 1237 static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas) 1238 { 1239 kobject_put("as->weights->kobj); 1240 damos_sysfs_quota_goals_rm_dirs(quotas->goals); 1241 kobject_put("as->goals->kobj); 1242 } 1243 1244 static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr, 1245 char *buf) 1246 { 1247 struct damon_sysfs_quotas *quotas = container_of(kobj, 1248 struct damon_sysfs_quotas, kobj); 1249 1250 return sysfs_emit(buf, "%lu\n", quotas->ms); 1251 } 1252 1253 static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr, 1254 const char *buf, size_t count) 1255 { 1256 struct damon_sysfs_quotas *quotas = container_of(kobj, 1257 struct damon_sysfs_quotas, kobj); 1258 int err = kstrtoul(buf, 0, "as->ms); 1259 1260 if (err) 1261 return -EINVAL; 1262 return count; 1263 } 1264 1265 static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr, 1266 char *buf) 1267 { 1268 struct damon_sysfs_quotas *quotas = container_of(kobj, 1269 struct damon_sysfs_quotas, kobj); 1270 1271 return sysfs_emit(buf, "%lu\n", quotas->sz); 1272 } 1273 1274 static ssize_t bytes_store(struct kobject *kobj, 1275 struct kobj_attribute *attr, const char *buf, size_t count) 1276 { 1277 struct damon_sysfs_quotas *quotas = container_of(kobj, 1278 struct damon_sysfs_quotas, kobj); 1279 int err = kstrtoul(buf, 0, "as->sz); 1280 1281 if (err) 1282 return -EINVAL; 1283 return count; 1284 } 1285 1286 static ssize_t reset_interval_ms_show(struct kobject *kobj, 1287 struct kobj_attribute *attr, char *buf) 1288 { 1289 struct damon_sysfs_quotas *quotas = container_of(kobj, 1290 struct damon_sysfs_quotas, kobj); 1291 1292 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms); 1293 } 1294 1295 static ssize_t reset_interval_ms_store(struct kobject *kobj, 1296 struct kobj_attribute *attr, const char *buf, size_t count) 1297 { 1298 struct damon_sysfs_quotas *quotas = container_of(kobj, 1299 struct damon_sysfs_quotas, kobj); 1300 int err = kstrtoul(buf, 0, "as->reset_interval_ms); 1301 1302 if (err) 1303 return -EINVAL; 1304 return count; 1305 } 1306 1307 static ssize_t effective_bytes_show(struct kobject *kobj, 1308 struct kobj_attribute *attr, char *buf) 1309 { 1310 struct damon_sysfs_quotas *quotas = container_of(kobj, 1311 struct damon_sysfs_quotas, kobj); 1312 1313 return sysfs_emit(buf, "%lu\n", quotas->effective_sz); 1314 } 1315 1316 static void damon_sysfs_quotas_release(struct kobject *kobj) 1317 { 1318 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj)); 1319 } 1320 1321 static struct kobj_attribute damon_sysfs_quotas_ms_attr = 1322 __ATTR_RW_MODE(ms, 0600); 1323 1324 static struct kobj_attribute damon_sysfs_quotas_sz_attr = 1325 __ATTR_RW_MODE(bytes, 0600); 1326 1327 static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr = 1328 __ATTR_RW_MODE(reset_interval_ms, 0600); 1329 1330 static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr = 1331 __ATTR_RO_MODE(effective_bytes, 0400); 1332 1333 static struct attribute *damon_sysfs_quotas_attrs[] = { 1334 &damon_sysfs_quotas_ms_attr.attr, 1335 &damon_sysfs_quotas_sz_attr.attr, 1336 &damon_sysfs_quotas_reset_interval_ms_attr.attr, 1337 &damon_sysfs_quotas_effective_bytes_attr.attr, 1338 NULL, 1339 }; 1340 ATTRIBUTE_GROUPS(damon_sysfs_quotas); 1341 1342 static const struct kobj_type damon_sysfs_quotas_ktype = { 1343 .release = damon_sysfs_quotas_release, 1344 .sysfs_ops = &kobj_sysfs_ops, 1345 .default_groups = damon_sysfs_quotas_groups, 1346 }; 1347 1348 /* 1349 * access_pattern directory 1350 */ 1351 1352 struct damon_sysfs_access_pattern { 1353 struct kobject kobj; 1354 struct damon_sysfs_ul_range *sz; 1355 struct damon_sysfs_ul_range *nr_accesses; 1356 struct damon_sysfs_ul_range *age; 1357 }; 1358 1359 static 1360 struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void) 1361 { 1362 struct damon_sysfs_access_pattern *access_pattern = 1363 kmalloc(sizeof(*access_pattern), GFP_KERNEL); 1364 1365 if (!access_pattern) 1366 return NULL; 1367 access_pattern->kobj = (struct kobject){}; 1368 return access_pattern; 1369 } 1370 1371 static int damon_sysfs_access_pattern_add_range_dir( 1372 struct damon_sysfs_access_pattern *access_pattern, 1373 struct damon_sysfs_ul_range **range_dir_ptr, 1374 char *name) 1375 { 1376 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0); 1377 int err; 1378 1379 if (!range) 1380 return -ENOMEM; 1381 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype, 1382 &access_pattern->kobj, name); 1383 if (err) 1384 kobject_put(&range->kobj); 1385 else 1386 *range_dir_ptr = range; 1387 return err; 1388 } 1389 1390 static int damon_sysfs_access_pattern_add_dirs( 1391 struct damon_sysfs_access_pattern *access_pattern) 1392 { 1393 int err; 1394 1395 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 1396 &access_pattern->sz, "sz"); 1397 if (err) 1398 goto put_sz_out; 1399 1400 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 1401 &access_pattern->nr_accesses, "nr_accesses"); 1402 if (err) 1403 goto put_nr_accesses_sz_out; 1404 1405 err = damon_sysfs_access_pattern_add_range_dir(access_pattern, 1406 &access_pattern->age, "age"); 1407 if (err) 1408 goto put_age_nr_accesses_sz_out; 1409 return 0; 1410 1411 put_age_nr_accesses_sz_out: 1412 kobject_put(&access_pattern->age->kobj); 1413 access_pattern->age = NULL; 1414 put_nr_accesses_sz_out: 1415 kobject_put(&access_pattern->nr_accesses->kobj); 1416 access_pattern->nr_accesses = NULL; 1417 put_sz_out: 1418 kobject_put(&access_pattern->sz->kobj); 1419 access_pattern->sz = NULL; 1420 return err; 1421 } 1422 1423 static void damon_sysfs_access_pattern_rm_dirs( 1424 struct damon_sysfs_access_pattern *access_pattern) 1425 { 1426 kobject_put(&access_pattern->sz->kobj); 1427 kobject_put(&access_pattern->nr_accesses->kobj); 1428 kobject_put(&access_pattern->age->kobj); 1429 } 1430 1431 static void damon_sysfs_access_pattern_release(struct kobject *kobj) 1432 { 1433 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj)); 1434 } 1435 1436 static struct attribute *damon_sysfs_access_pattern_attrs[] = { 1437 NULL, 1438 }; 1439 ATTRIBUTE_GROUPS(damon_sysfs_access_pattern); 1440 1441 static const struct kobj_type damon_sysfs_access_pattern_ktype = { 1442 .release = damon_sysfs_access_pattern_release, 1443 .sysfs_ops = &kobj_sysfs_ops, 1444 .default_groups = damon_sysfs_access_pattern_groups, 1445 }; 1446 1447 /* 1448 * scheme directory 1449 */ 1450 1451 struct damon_sysfs_scheme { 1452 struct kobject kobj; 1453 enum damos_action action; 1454 struct damon_sysfs_access_pattern *access_pattern; 1455 unsigned long apply_interval_us; 1456 struct damon_sysfs_quotas *quotas; 1457 struct damon_sysfs_watermarks *watermarks; 1458 struct damon_sysfs_scheme_filters *filters; 1459 struct damon_sysfs_stats *stats; 1460 struct damon_sysfs_scheme_regions *tried_regions; 1461 int target_nid; 1462 }; 1463 1464 /* This should match with enum damos_action */ 1465 static const char * const damon_sysfs_damos_action_strs[] = { 1466 "willneed", 1467 "cold", 1468 "pageout", 1469 "hugepage", 1470 "nohugepage", 1471 "lru_prio", 1472 "lru_deprio", 1473 "migrate_hot", 1474 "migrate_cold", 1475 "stat", 1476 }; 1477 1478 static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc( 1479 enum damos_action action, unsigned long apply_interval_us) 1480 { 1481 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme), 1482 GFP_KERNEL); 1483 1484 if (!scheme) 1485 return NULL; 1486 scheme->kobj = (struct kobject){}; 1487 scheme->action = action; 1488 scheme->apply_interval_us = apply_interval_us; 1489 scheme->target_nid = NUMA_NO_NODE; 1490 return scheme; 1491 } 1492 1493 static int damon_sysfs_scheme_set_access_pattern( 1494 struct damon_sysfs_scheme *scheme) 1495 { 1496 struct damon_sysfs_access_pattern *access_pattern; 1497 int err; 1498 1499 access_pattern = damon_sysfs_access_pattern_alloc(); 1500 if (!access_pattern) 1501 return -ENOMEM; 1502 err = kobject_init_and_add(&access_pattern->kobj, 1503 &damon_sysfs_access_pattern_ktype, &scheme->kobj, 1504 "access_pattern"); 1505 if (err) 1506 goto out; 1507 err = damon_sysfs_access_pattern_add_dirs(access_pattern); 1508 if (err) 1509 goto out; 1510 scheme->access_pattern = access_pattern; 1511 return 0; 1512 1513 out: 1514 kobject_put(&access_pattern->kobj); 1515 return err; 1516 } 1517 1518 static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme) 1519 { 1520 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc(); 1521 int err; 1522 1523 if (!quotas) 1524 return -ENOMEM; 1525 err = kobject_init_and_add("as->kobj, &damon_sysfs_quotas_ktype, 1526 &scheme->kobj, "quotas"); 1527 if (err) 1528 goto out; 1529 err = damon_sysfs_quotas_add_dirs(quotas); 1530 if (err) 1531 goto out; 1532 scheme->quotas = quotas; 1533 return 0; 1534 1535 out: 1536 kobject_put("as->kobj); 1537 return err; 1538 } 1539 1540 static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme) 1541 { 1542 struct damon_sysfs_watermarks *watermarks = 1543 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0); 1544 int err; 1545 1546 if (!watermarks) 1547 return -ENOMEM; 1548 err = kobject_init_and_add(&watermarks->kobj, 1549 &damon_sysfs_watermarks_ktype, &scheme->kobj, 1550 "watermarks"); 1551 if (err) 1552 kobject_put(&watermarks->kobj); 1553 else 1554 scheme->watermarks = watermarks; 1555 return err; 1556 } 1557 1558 static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme) 1559 { 1560 struct damon_sysfs_scheme_filters *filters = 1561 damon_sysfs_scheme_filters_alloc(); 1562 int err; 1563 1564 if (!filters) 1565 return -ENOMEM; 1566 err = kobject_init_and_add(&filters->kobj, 1567 &damon_sysfs_scheme_filters_ktype, &scheme->kobj, 1568 "filters"); 1569 if (err) 1570 kobject_put(&filters->kobj); 1571 else 1572 scheme->filters = filters; 1573 return err; 1574 } 1575 1576 static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme) 1577 { 1578 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc(); 1579 int err; 1580 1581 if (!stats) 1582 return -ENOMEM; 1583 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype, 1584 &scheme->kobj, "stats"); 1585 if (err) 1586 kobject_put(&stats->kobj); 1587 else 1588 scheme->stats = stats; 1589 return err; 1590 } 1591 1592 static int damon_sysfs_scheme_set_tried_regions( 1593 struct damon_sysfs_scheme *scheme) 1594 { 1595 struct damon_sysfs_scheme_regions *tried_regions = 1596 damon_sysfs_scheme_regions_alloc(); 1597 int err; 1598 1599 if (!tried_regions) 1600 return -ENOMEM; 1601 err = kobject_init_and_add(&tried_regions->kobj, 1602 &damon_sysfs_scheme_regions_ktype, &scheme->kobj, 1603 "tried_regions"); 1604 if (err) 1605 kobject_put(&tried_regions->kobj); 1606 else 1607 scheme->tried_regions = tried_regions; 1608 return err; 1609 } 1610 1611 static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) 1612 { 1613 int err; 1614 1615 err = damon_sysfs_scheme_set_access_pattern(scheme); 1616 if (err) 1617 return err; 1618 err = damon_sysfs_scheme_set_quotas(scheme); 1619 if (err) 1620 goto put_access_pattern_out; 1621 err = damon_sysfs_scheme_set_watermarks(scheme); 1622 if (err) 1623 goto put_quotas_access_pattern_out; 1624 err = damon_sysfs_scheme_set_filters(scheme); 1625 if (err) 1626 goto put_watermarks_quotas_access_pattern_out; 1627 err = damon_sysfs_scheme_set_stats(scheme); 1628 if (err) 1629 goto put_filters_watermarks_quotas_access_pattern_out; 1630 err = damon_sysfs_scheme_set_tried_regions(scheme); 1631 if (err) 1632 goto put_tried_regions_out; 1633 return 0; 1634 1635 put_tried_regions_out: 1636 kobject_put(&scheme->tried_regions->kobj); 1637 scheme->tried_regions = NULL; 1638 put_filters_watermarks_quotas_access_pattern_out: 1639 kobject_put(&scheme->filters->kobj); 1640 scheme->filters = NULL; 1641 put_watermarks_quotas_access_pattern_out: 1642 kobject_put(&scheme->watermarks->kobj); 1643 scheme->watermarks = NULL; 1644 put_quotas_access_pattern_out: 1645 kobject_put(&scheme->quotas->kobj); 1646 scheme->quotas = NULL; 1647 put_access_pattern_out: 1648 kobject_put(&scheme->access_pattern->kobj); 1649 scheme->access_pattern = NULL; 1650 return err; 1651 } 1652 1653 static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme) 1654 { 1655 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); 1656 kobject_put(&scheme->access_pattern->kobj); 1657 damon_sysfs_quotas_rm_dirs(scheme->quotas); 1658 kobject_put(&scheme->quotas->kobj); 1659 kobject_put(&scheme->watermarks->kobj); 1660 damon_sysfs_scheme_filters_rm_dirs(scheme->filters); 1661 kobject_put(&scheme->filters->kobj); 1662 kobject_put(&scheme->stats->kobj); 1663 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions); 1664 kobject_put(&scheme->tried_regions->kobj); 1665 } 1666 1667 static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr, 1668 char *buf) 1669 { 1670 struct damon_sysfs_scheme *scheme = container_of(kobj, 1671 struct damon_sysfs_scheme, kobj); 1672 1673 return sysfs_emit(buf, "%s\n", 1674 damon_sysfs_damos_action_strs[scheme->action]); 1675 } 1676 1677 static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr, 1678 const char *buf, size_t count) 1679 { 1680 struct damon_sysfs_scheme *scheme = container_of(kobj, 1681 struct damon_sysfs_scheme, kobj); 1682 enum damos_action action; 1683 1684 for (action = 0; action < NR_DAMOS_ACTIONS; action++) { 1685 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) { 1686 scheme->action = action; 1687 return count; 1688 } 1689 } 1690 return -EINVAL; 1691 } 1692 1693 static ssize_t apply_interval_us_show(struct kobject *kobj, 1694 struct kobj_attribute *attr, char *buf) 1695 { 1696 struct damon_sysfs_scheme *scheme = container_of(kobj, 1697 struct damon_sysfs_scheme, kobj); 1698 1699 return sysfs_emit(buf, "%lu\n", scheme->apply_interval_us); 1700 } 1701 1702 static ssize_t apply_interval_us_store(struct kobject *kobj, 1703 struct kobj_attribute *attr, const char *buf, size_t count) 1704 { 1705 struct damon_sysfs_scheme *scheme = container_of(kobj, 1706 struct damon_sysfs_scheme, kobj); 1707 int err = kstrtoul(buf, 0, &scheme->apply_interval_us); 1708 1709 return err ? err : count; 1710 } 1711 1712 static ssize_t target_nid_show(struct kobject *kobj, 1713 struct kobj_attribute *attr, char *buf) 1714 { 1715 struct damon_sysfs_scheme *scheme = container_of(kobj, 1716 struct damon_sysfs_scheme, kobj); 1717 1718 return sysfs_emit(buf, "%d\n", scheme->target_nid); 1719 } 1720 1721 static ssize_t target_nid_store(struct kobject *kobj, 1722 struct kobj_attribute *attr, const char *buf, size_t count) 1723 { 1724 struct damon_sysfs_scheme *scheme = container_of(kobj, 1725 struct damon_sysfs_scheme, kobj); 1726 int err = 0; 1727 1728 /* TODO: error handling for target_nid range. */ 1729 err = kstrtoint(buf, 0, &scheme->target_nid); 1730 1731 return err ? err : count; 1732 } 1733 1734 static void damon_sysfs_scheme_release(struct kobject *kobj) 1735 { 1736 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj)); 1737 } 1738 1739 static struct kobj_attribute damon_sysfs_scheme_action_attr = 1740 __ATTR_RW_MODE(action, 0600); 1741 1742 static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr = 1743 __ATTR_RW_MODE(apply_interval_us, 0600); 1744 1745 static struct kobj_attribute damon_sysfs_scheme_target_nid_attr = 1746 __ATTR_RW_MODE(target_nid, 0600); 1747 1748 static struct attribute *damon_sysfs_scheme_attrs[] = { 1749 &damon_sysfs_scheme_action_attr.attr, 1750 &damon_sysfs_scheme_apply_interval_us_attr.attr, 1751 &damon_sysfs_scheme_target_nid_attr.attr, 1752 NULL, 1753 }; 1754 ATTRIBUTE_GROUPS(damon_sysfs_scheme); 1755 1756 static const struct kobj_type damon_sysfs_scheme_ktype = { 1757 .release = damon_sysfs_scheme_release, 1758 .sysfs_ops = &kobj_sysfs_ops, 1759 .default_groups = damon_sysfs_scheme_groups, 1760 }; 1761 1762 /* 1763 * schemes directory 1764 */ 1765 1766 struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void) 1767 { 1768 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL); 1769 } 1770 1771 void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes) 1772 { 1773 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr; 1774 int i; 1775 1776 for (i = 0; i < schemes->nr; i++) { 1777 damon_sysfs_scheme_rm_dirs(schemes_arr[i]); 1778 kobject_put(&schemes_arr[i]->kobj); 1779 } 1780 schemes->nr = 0; 1781 kfree(schemes_arr); 1782 schemes->schemes_arr = NULL; 1783 } 1784 1785 static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes, 1786 int nr_schemes) 1787 { 1788 struct damon_sysfs_scheme **schemes_arr, *scheme; 1789 int err, i; 1790 1791 damon_sysfs_schemes_rm_dirs(schemes); 1792 if (!nr_schemes) 1793 return 0; 1794 1795 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr), 1796 GFP_KERNEL | __GFP_NOWARN); 1797 if (!schemes_arr) 1798 return -ENOMEM; 1799 schemes->schemes_arr = schemes_arr; 1800 1801 for (i = 0; i < nr_schemes; i++) { 1802 /* 1803 * apply_interval_us as 0 means same to aggregation interval 1804 * (same to before-apply_interval behavior) 1805 */ 1806 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT, 0); 1807 if (!scheme) { 1808 damon_sysfs_schemes_rm_dirs(schemes); 1809 return -ENOMEM; 1810 } 1811 1812 err = kobject_init_and_add(&scheme->kobj, 1813 &damon_sysfs_scheme_ktype, &schemes->kobj, 1814 "%d", i); 1815 if (err) 1816 goto out; 1817 err = damon_sysfs_scheme_add_dirs(scheme); 1818 if (err) 1819 goto out; 1820 1821 schemes_arr[i] = scheme; 1822 schemes->nr++; 1823 } 1824 return 0; 1825 1826 out: 1827 damon_sysfs_schemes_rm_dirs(schemes); 1828 kobject_put(&scheme->kobj); 1829 return err; 1830 } 1831 1832 static ssize_t nr_schemes_show(struct kobject *kobj, 1833 struct kobj_attribute *attr, char *buf) 1834 { 1835 struct damon_sysfs_schemes *schemes = container_of(kobj, 1836 struct damon_sysfs_schemes, kobj); 1837 1838 return sysfs_emit(buf, "%d\n", schemes->nr); 1839 } 1840 1841 static ssize_t nr_schemes_store(struct kobject *kobj, 1842 struct kobj_attribute *attr, const char *buf, size_t count) 1843 { 1844 struct damon_sysfs_schemes *schemes; 1845 int nr, err = kstrtoint(buf, 0, &nr); 1846 1847 if (err) 1848 return err; 1849 if (nr < 0) 1850 return -EINVAL; 1851 1852 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj); 1853 1854 if (!mutex_trylock(&damon_sysfs_lock)) 1855 return -EBUSY; 1856 err = damon_sysfs_schemes_add_dirs(schemes, nr); 1857 mutex_unlock(&damon_sysfs_lock); 1858 if (err) 1859 return err; 1860 return count; 1861 } 1862 1863 static void damon_sysfs_schemes_release(struct kobject *kobj) 1864 { 1865 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj)); 1866 } 1867 1868 static struct kobj_attribute damon_sysfs_schemes_nr_attr = 1869 __ATTR_RW_MODE(nr_schemes, 0600); 1870 1871 static struct attribute *damon_sysfs_schemes_attrs[] = { 1872 &damon_sysfs_schemes_nr_attr.attr, 1873 NULL, 1874 }; 1875 ATTRIBUTE_GROUPS(damon_sysfs_schemes); 1876 1877 const struct kobj_type damon_sysfs_schemes_ktype = { 1878 .release = damon_sysfs_schemes_release, 1879 .sysfs_ops = &kobj_sysfs_ops, 1880 .default_groups = damon_sysfs_schemes_groups, 1881 }; 1882 1883 static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg, 1884 char *memcg_path_buf, char *path) 1885 { 1886 #ifdef CONFIG_MEMCG 1887 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX); 1888 if (sysfs_streq(memcg_path_buf, path)) 1889 return true; 1890 #endif /* CONFIG_MEMCG */ 1891 return false; 1892 } 1893 1894 static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id) 1895 { 1896 struct mem_cgroup *memcg; 1897 char *path; 1898 bool found = false; 1899 1900 if (!memcg_path) 1901 return -EINVAL; 1902 1903 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL); 1904 if (!path) 1905 return -ENOMEM; 1906 1907 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg; 1908 memcg = mem_cgroup_iter(NULL, memcg, NULL)) { 1909 /* skip removed memcg */ 1910 if (!mem_cgroup_id(memcg)) 1911 continue; 1912 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) { 1913 *id = mem_cgroup_id(memcg); 1914 found = true; 1915 break; 1916 } 1917 } 1918 1919 kfree(path); 1920 return found ? 0 : -EINVAL; 1921 } 1922 1923 static int damon_sysfs_add_scheme_filters(struct damos *scheme, 1924 struct damon_sysfs_scheme_filters *sysfs_filters) 1925 { 1926 int i; 1927 1928 for (i = 0; i < sysfs_filters->nr; i++) { 1929 struct damon_sysfs_scheme_filter *sysfs_filter = 1930 sysfs_filters->filters_arr[i]; 1931 struct damos_filter *filter = 1932 damos_new_filter(sysfs_filter->type, 1933 sysfs_filter->matching, 1934 sysfs_filter->allow); 1935 int err; 1936 1937 if (!filter) 1938 return -ENOMEM; 1939 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) { 1940 err = damon_sysfs_memcg_path_to_id( 1941 sysfs_filter->memcg_path, 1942 &filter->memcg_id); 1943 if (err) { 1944 damos_destroy_filter(filter); 1945 return err; 1946 } 1947 } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) { 1948 if (sysfs_filter->addr_range.end < 1949 sysfs_filter->addr_range.start) { 1950 damos_destroy_filter(filter); 1951 return -EINVAL; 1952 } 1953 filter->addr_range = sysfs_filter->addr_range; 1954 } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) { 1955 filter->target_idx = sysfs_filter->target_idx; 1956 } 1957 1958 damos_add_filter(scheme, filter); 1959 } 1960 return 0; 1961 } 1962 1963 static int damos_sysfs_add_quota_score( 1964 struct damos_sysfs_quota_goals *sysfs_goals, 1965 struct damos_quota *quota) 1966 { 1967 struct damos_quota_goal *goal; 1968 int i; 1969 1970 for (i = 0; i < sysfs_goals->nr; i++) { 1971 struct damos_sysfs_quota_goal *sysfs_goal = 1972 sysfs_goals->goals_arr[i]; 1973 1974 if (!sysfs_goal->target_value) 1975 continue; 1976 1977 goal = damos_new_quota_goal(sysfs_goal->metric, 1978 sysfs_goal->target_value); 1979 if (!goal) 1980 return -ENOMEM; 1981 if (sysfs_goal->metric == DAMOS_QUOTA_USER_INPUT) 1982 goal->current_value = sysfs_goal->current_value; 1983 damos_add_quota_goal(quota, goal); 1984 } 1985 return 0; 1986 } 1987 1988 int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes, 1989 struct damon_ctx *ctx) 1990 { 1991 struct damos *scheme; 1992 struct damos_quota quota = {}; 1993 int i = 0; 1994 1995 INIT_LIST_HEAD("a.goals); 1996 damon_for_each_scheme(scheme, ctx) { 1997 struct damon_sysfs_scheme *sysfs_scheme; 1998 struct damos_quota_goal *g, *g_next; 1999 int err; 2000 2001 /* user could have removed the scheme sysfs dir */ 2002 if (i >= sysfs_schemes->nr) 2003 break; 2004 2005 sysfs_scheme = sysfs_schemes->schemes_arr[i]; 2006 err = damos_sysfs_add_quota_score(sysfs_scheme->quotas->goals, 2007 "a); 2008 if (err) { 2009 damos_for_each_quota_goal_safe(g, g_next, "a) 2010 damos_destroy_quota_goal(g); 2011 return err; 2012 } 2013 err = damos_commit_quota_goals(&scheme->quota, "a); 2014 damos_for_each_quota_goal_safe(g, g_next, "a) 2015 damos_destroy_quota_goal(g); 2016 if (err) 2017 return err; 2018 i++; 2019 } 2020 return 0; 2021 } 2022 2023 void damos_sysfs_update_effective_quotas( 2024 struct damon_sysfs_schemes *sysfs_schemes, 2025 struct damon_ctx *ctx) 2026 { 2027 struct damos *scheme; 2028 int schemes_idx = 0; 2029 2030 damon_for_each_scheme(scheme, ctx) { 2031 struct damon_sysfs_quotas *sysfs_quotas; 2032 2033 /* user could have removed the scheme sysfs dir */ 2034 if (schemes_idx >= sysfs_schemes->nr) 2035 break; 2036 2037 sysfs_quotas = 2038 sysfs_schemes->schemes_arr[schemes_idx++]->quotas; 2039 sysfs_quotas->effective_sz = scheme->quota.esz; 2040 } 2041 } 2042 2043 static struct damos *damon_sysfs_mk_scheme( 2044 struct damon_sysfs_scheme *sysfs_scheme) 2045 { 2046 struct damon_sysfs_access_pattern *access_pattern = 2047 sysfs_scheme->access_pattern; 2048 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas; 2049 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights; 2050 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks; 2051 struct damon_sysfs_scheme_filters *sysfs_filters = 2052 sysfs_scheme->filters; 2053 struct damos *scheme; 2054 int err; 2055 2056 struct damos_access_pattern pattern = { 2057 .min_sz_region = access_pattern->sz->min, 2058 .max_sz_region = access_pattern->sz->max, 2059 .min_nr_accesses = access_pattern->nr_accesses->min, 2060 .max_nr_accesses = access_pattern->nr_accesses->max, 2061 .min_age_region = access_pattern->age->min, 2062 .max_age_region = access_pattern->age->max, 2063 }; 2064 struct damos_quota quota = { 2065 .ms = sysfs_quotas->ms, 2066 .sz = sysfs_quotas->sz, 2067 .reset_interval = sysfs_quotas->reset_interval_ms, 2068 .weight_sz = sysfs_weights->sz, 2069 .weight_nr_accesses = sysfs_weights->nr_accesses, 2070 .weight_age = sysfs_weights->age, 2071 }; 2072 struct damos_watermarks wmarks = { 2073 .metric = sysfs_wmarks->metric, 2074 .interval = sysfs_wmarks->interval_us, 2075 .high = sysfs_wmarks->high, 2076 .mid = sysfs_wmarks->mid, 2077 .low = sysfs_wmarks->low, 2078 }; 2079 2080 scheme = damon_new_scheme(&pattern, sysfs_scheme->action, 2081 sysfs_scheme->apply_interval_us, "a, &wmarks, 2082 sysfs_scheme->target_nid); 2083 if (!scheme) 2084 return NULL; 2085 2086 err = damos_sysfs_add_quota_score(sysfs_quotas->goals, &scheme->quota); 2087 if (err) { 2088 damon_destroy_scheme(scheme); 2089 return NULL; 2090 } 2091 2092 err = damon_sysfs_add_scheme_filters(scheme, sysfs_filters); 2093 if (err) { 2094 damon_destroy_scheme(scheme); 2095 return NULL; 2096 } 2097 return scheme; 2098 } 2099 2100 int damon_sysfs_add_schemes(struct damon_ctx *ctx, 2101 struct damon_sysfs_schemes *sysfs_schemes) 2102 { 2103 int i; 2104 2105 for (i = 0; i < sysfs_schemes->nr; i++) { 2106 struct damos *scheme, *next; 2107 2108 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]); 2109 if (!scheme) { 2110 damon_for_each_scheme_safe(scheme, next, ctx) 2111 damon_destroy_scheme(scheme); 2112 return -ENOMEM; 2113 } 2114 damon_add_scheme(ctx, scheme); 2115 } 2116 return 0; 2117 } 2118 2119 void damon_sysfs_schemes_update_stats( 2120 struct damon_sysfs_schemes *sysfs_schemes, 2121 struct damon_ctx *ctx) 2122 { 2123 struct damos *scheme; 2124 int schemes_idx = 0; 2125 2126 damon_for_each_scheme(scheme, ctx) { 2127 struct damon_sysfs_stats *sysfs_stats; 2128 2129 /* user could have removed the scheme sysfs dir */ 2130 if (schemes_idx >= sysfs_schemes->nr) 2131 break; 2132 2133 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats; 2134 sysfs_stats->nr_tried = scheme->stat.nr_tried; 2135 sysfs_stats->sz_tried = scheme->stat.sz_tried; 2136 sysfs_stats->nr_applied = scheme->stat.nr_applied; 2137 sysfs_stats->sz_applied = scheme->stat.sz_applied; 2138 sysfs_stats->sz_ops_filter_passed = 2139 scheme->stat.sz_ops_filter_passed; 2140 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds; 2141 } 2142 } 2143 2144 /** 2145 * damos_sysfs_populate_region_dir() - Populate a schemes tried region dir. 2146 * @sysfs_schemes: Schemes directory to populate regions directory. 2147 * @ctx: Corresponding DAMON context. 2148 * @t: DAMON target of @r. 2149 * @r: DAMON region to populate the directory for. 2150 * @s: Corresponding scheme. 2151 * @total_bytes_only: Whether the request is for bytes update only. 2152 * @sz_filter_passed: Bytes of @r that passed filters of @s. 2153 * 2154 * Called from DAMOS walk callback while holding damon_sysfs_lock. 2155 */ 2156 void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes, 2157 struct damon_ctx *ctx, struct damon_target *t, 2158 struct damon_region *r, struct damos *s, bool total_bytes_only, 2159 unsigned long sz_filter_passed) 2160 { 2161 struct damos *scheme; 2162 struct damon_sysfs_scheme_regions *sysfs_regions; 2163 struct damon_sysfs_scheme_region *region; 2164 int schemes_idx = 0; 2165 2166 damon_for_each_scheme(scheme, ctx) { 2167 if (scheme == s) 2168 break; 2169 schemes_idx++; 2170 } 2171 2172 /* user could have removed the scheme sysfs dir */ 2173 if (schemes_idx >= sysfs_schemes->nr) 2174 return; 2175 2176 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions; 2177 sysfs_regions->total_bytes += r->ar.end - r->ar.start; 2178 if (total_bytes_only) 2179 return; 2180 2181 region = damon_sysfs_scheme_region_alloc(r); 2182 if (!region) 2183 return; 2184 region->sz_filter_passed = sz_filter_passed; 2185 list_add_tail(®ion->list, &sysfs_regions->regions_list); 2186 sysfs_regions->nr_regions++; 2187 if (kobject_init_and_add(®ion->kobj, 2188 &damon_sysfs_scheme_region_ktype, 2189 &sysfs_regions->kobj, "%d", 2190 sysfs_regions->nr_regions++)) { 2191 kobject_put(®ion->kobj); 2192 } 2193 } 2194 2195 /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */ 2196 int damon_sysfs_schemes_clear_regions( 2197 struct damon_sysfs_schemes *sysfs_schemes) 2198 { 2199 int i; 2200 2201 for (i = 0; i < sysfs_schemes->nr; i++) { 2202 struct damon_sysfs_scheme *sysfs_scheme; 2203 2204 sysfs_scheme = sysfs_schemes->schemes_arr[i]; 2205 damon_sysfs_scheme_regions_rm_dirs( 2206 sysfs_scheme->tried_regions); 2207 sysfs_scheme->tried_regions->total_bytes = 0; 2208 } 2209 return 0; 2210 } 2211