Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/mm/damon/sysfs-schemes.c
51282 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* DAMON sysfs Interface
4
*
5
* Copyright (c) 2022 SeongJae Park <[email protected]>
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(&region->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(&regions->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, &regions->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
unsigned long nr_snapshots;
208
unsigned long max_nr_snapshots;
209
};
210
211
static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
212
{
213
return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
214
}
215
216
static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
217
char *buf)
218
{
219
struct damon_sysfs_stats *stats = container_of(kobj,
220
struct damon_sysfs_stats, kobj);
221
222
return sysfs_emit(buf, "%lu\n", stats->nr_tried);
223
}
224
225
static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
226
char *buf)
227
{
228
struct damon_sysfs_stats *stats = container_of(kobj,
229
struct damon_sysfs_stats, kobj);
230
231
return sysfs_emit(buf, "%lu\n", stats->sz_tried);
232
}
233
234
static ssize_t nr_applied_show(struct kobject *kobj,
235
struct kobj_attribute *attr, char *buf)
236
{
237
struct damon_sysfs_stats *stats = container_of(kobj,
238
struct damon_sysfs_stats, kobj);
239
240
return sysfs_emit(buf, "%lu\n", stats->nr_applied);
241
}
242
243
static ssize_t sz_applied_show(struct kobject *kobj,
244
struct kobj_attribute *attr, char *buf)
245
{
246
struct damon_sysfs_stats *stats = container_of(kobj,
247
struct damon_sysfs_stats, kobj);
248
249
return sysfs_emit(buf, "%lu\n", stats->sz_applied);
250
}
251
252
static ssize_t sz_ops_filter_passed_show(struct kobject *kobj,
253
struct kobj_attribute *attr, char *buf)
254
{
255
struct damon_sysfs_stats *stats = container_of(kobj,
256
struct damon_sysfs_stats, kobj);
257
258
return sysfs_emit(buf, "%lu\n", stats->sz_ops_filter_passed);
259
}
260
261
static ssize_t qt_exceeds_show(struct kobject *kobj,
262
struct kobj_attribute *attr, char *buf)
263
{
264
struct damon_sysfs_stats *stats = container_of(kobj,
265
struct damon_sysfs_stats, kobj);
266
267
return sysfs_emit(buf, "%lu\n", stats->qt_exceeds);
268
}
269
270
static ssize_t nr_snapshots_show(struct kobject *kobj,
271
struct kobj_attribute *attr, char *buf)
272
{
273
struct damon_sysfs_stats *stats = container_of(kobj,
274
struct damon_sysfs_stats, kobj);
275
276
return sysfs_emit(buf, "%lu\n", stats->nr_snapshots);
277
}
278
279
static ssize_t max_nr_snapshots_show(struct kobject *kobj,
280
struct kobj_attribute *attr, char *buf)
281
{
282
struct damon_sysfs_stats *stats = container_of(kobj,
283
struct damon_sysfs_stats, kobj);
284
285
return sysfs_emit(buf, "%lu\n", stats->max_nr_snapshots);
286
}
287
288
static ssize_t max_nr_snapshots_store(struct kobject *kobj,
289
struct kobj_attribute *attr, const char *buf, size_t count)
290
{
291
struct damon_sysfs_stats *stats = container_of(kobj,
292
struct damon_sysfs_stats, kobj);
293
unsigned long max_nr_snapshots, err = kstrtoul(buf, 0, &max_nr_snapshots);
294
295
if (err)
296
return err;
297
stats->max_nr_snapshots = max_nr_snapshots;
298
return count;
299
}
300
301
static void damon_sysfs_stats_release(struct kobject *kobj)
302
{
303
kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
304
}
305
306
static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
307
__ATTR_RO_MODE(nr_tried, 0400);
308
309
static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
310
__ATTR_RO_MODE(sz_tried, 0400);
311
312
static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
313
__ATTR_RO_MODE(nr_applied, 0400);
314
315
static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
316
__ATTR_RO_MODE(sz_applied, 0400);
317
318
static struct kobj_attribute damon_sysfs_stats_sz_ops_filter_passed_attr =
319
__ATTR_RO_MODE(sz_ops_filter_passed, 0400);
320
321
static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
322
__ATTR_RO_MODE(qt_exceeds, 0400);
323
324
static struct kobj_attribute damon_sysfs_stats_nr_snapshots_attr =
325
__ATTR_RO_MODE(nr_snapshots, 0400);
326
327
static struct kobj_attribute damon_sysfs_stats_max_nr_snapshots_attr =
328
__ATTR_RW_MODE(max_nr_snapshots, 0600);
329
330
static struct attribute *damon_sysfs_stats_attrs[] = {
331
&damon_sysfs_stats_nr_tried_attr.attr,
332
&damon_sysfs_stats_sz_tried_attr.attr,
333
&damon_sysfs_stats_nr_applied_attr.attr,
334
&damon_sysfs_stats_sz_applied_attr.attr,
335
&damon_sysfs_stats_sz_ops_filter_passed_attr.attr,
336
&damon_sysfs_stats_qt_exceeds_attr.attr,
337
&damon_sysfs_stats_nr_snapshots_attr.attr,
338
&damon_sysfs_stats_max_nr_snapshots_attr.attr,
339
NULL,
340
};
341
ATTRIBUTE_GROUPS(damon_sysfs_stats);
342
343
static const struct kobj_type damon_sysfs_stats_ktype = {
344
.release = damon_sysfs_stats_release,
345
.sysfs_ops = &kobj_sysfs_ops,
346
.default_groups = damon_sysfs_stats_groups,
347
};
348
349
/*
350
* filter directory
351
*/
352
353
/*
354
* enum damos_sysfs_filter_handle_layer - Layers handling filters of a dir.
355
*/
356
enum damos_sysfs_filter_handle_layer {
357
DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE,
358
DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS,
359
DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH,
360
};
361
362
struct damon_sysfs_scheme_filter {
363
struct kobject kobj;
364
enum damos_sysfs_filter_handle_layer handle_layer;
365
enum damos_filter_type type;
366
bool matching;
367
bool allow;
368
char *memcg_path;
369
struct damon_addr_range addr_range;
370
struct damon_size_range sz_range;
371
int target_idx;
372
};
373
374
static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(
375
enum damos_sysfs_filter_handle_layer layer)
376
{
377
struct damon_sysfs_scheme_filter *filter;
378
379
filter = kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL);
380
if (filter)
381
filter->handle_layer = layer;
382
return filter;
383
}
384
385
struct damos_sysfs_filter_type_name {
386
enum damos_filter_type type;
387
char *name;
388
};
389
390
static const struct damos_sysfs_filter_type_name
391
damos_sysfs_filter_type_names[] = {
392
{
393
.type = DAMOS_FILTER_TYPE_ANON,
394
.name = "anon",
395
},
396
{
397
.type = DAMOS_FILTER_TYPE_ACTIVE,
398
.name = "active",
399
},
400
{
401
.type = DAMOS_FILTER_TYPE_MEMCG,
402
.name = "memcg",
403
},
404
{
405
.type = DAMOS_FILTER_TYPE_YOUNG,
406
.name = "young",
407
},
408
{
409
.type = DAMOS_FILTER_TYPE_HUGEPAGE_SIZE,
410
.name = "hugepage_size",
411
},
412
{
413
.type = DAMOS_FILTER_TYPE_UNMAPPED,
414
.name = "unmapped",
415
},
416
{
417
.type = DAMOS_FILTER_TYPE_ADDR,
418
.name = "addr",
419
},
420
{
421
.type = DAMOS_FILTER_TYPE_TARGET,
422
.name = "target",
423
},
424
};
425
426
static ssize_t type_show(struct kobject *kobj,
427
struct kobj_attribute *attr, char *buf)
428
{
429
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
430
struct damon_sysfs_scheme_filter, kobj);
431
int i;
432
433
for (i = 0; i < ARRAY_SIZE(damos_sysfs_filter_type_names); i++) {
434
const struct damos_sysfs_filter_type_name *type_name;
435
436
type_name = &damos_sysfs_filter_type_names[i];
437
if (type_name->type == filter->type)
438
return sysfs_emit(buf, "%s\n", type_name->name);
439
}
440
return -EINVAL;
441
}
442
443
static bool damos_sysfs_scheme_filter_valid_type(
444
enum damos_sysfs_filter_handle_layer layer,
445
enum damos_filter_type type)
446
{
447
switch (layer) {
448
case DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH:
449
return true;
450
case DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE:
451
return !damos_filter_for_ops(type);
452
case DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS:
453
return damos_filter_for_ops(type);
454
default:
455
break;
456
}
457
return false;
458
}
459
460
static ssize_t type_store(struct kobject *kobj,
461
struct kobj_attribute *attr, const char *buf, size_t count)
462
{
463
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
464
struct damon_sysfs_scheme_filter, kobj);
465
ssize_t ret = -EINVAL;
466
int i;
467
468
for (i = 0; i < ARRAY_SIZE(damos_sysfs_filter_type_names); i++) {
469
const struct damos_sysfs_filter_type_name *type_name;
470
471
type_name = &damos_sysfs_filter_type_names[i];
472
if (sysfs_streq(buf, type_name->name)) {
473
if (!damos_sysfs_scheme_filter_valid_type(
474
filter->handle_layer,
475
type_name->type))
476
break;
477
filter->type = type_name->type;
478
ret = count;
479
break;
480
}
481
}
482
return ret;
483
}
484
485
static ssize_t matching_show(struct kobject *kobj,
486
struct kobj_attribute *attr, char *buf)
487
{
488
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
489
struct damon_sysfs_scheme_filter, kobj);
490
491
return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
492
}
493
494
static ssize_t matching_store(struct kobject *kobj,
495
struct kobj_attribute *attr, const char *buf, size_t count)
496
{
497
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
498
struct damon_sysfs_scheme_filter, kobj);
499
bool matching;
500
int err = kstrtobool(buf, &matching);
501
502
if (err)
503
return err;
504
505
filter->matching = matching;
506
return count;
507
}
508
509
static ssize_t allow_show(struct kobject *kobj,
510
struct kobj_attribute *attr, char *buf)
511
{
512
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
513
struct damon_sysfs_scheme_filter, kobj);
514
515
return sysfs_emit(buf, "%c\n", filter->allow ? 'Y' : 'N');
516
}
517
518
static ssize_t allow_store(struct kobject *kobj,
519
struct kobj_attribute *attr, const char *buf, size_t count)
520
{
521
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
522
struct damon_sysfs_scheme_filter, kobj);
523
bool allow;
524
int err = kstrtobool(buf, &allow);
525
526
if (err)
527
return err;
528
529
filter->allow = allow;
530
return count;
531
}
532
533
static ssize_t memcg_path_show(struct kobject *kobj,
534
struct kobj_attribute *attr, char *buf)
535
{
536
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
537
struct damon_sysfs_scheme_filter, kobj);
538
539
return sysfs_emit(buf, "%s\n",
540
filter->memcg_path ? filter->memcg_path : "");
541
}
542
543
static ssize_t memcg_path_store(struct kobject *kobj,
544
struct kobj_attribute *attr, const char *buf, size_t count)
545
{
546
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
547
struct damon_sysfs_scheme_filter, kobj);
548
char *path = kmalloc_array(size_add(count, 1), sizeof(*path),
549
GFP_KERNEL);
550
551
if (!path)
552
return -ENOMEM;
553
554
strscpy(path, buf, count + 1);
555
kfree(filter->memcg_path);
556
filter->memcg_path = path;
557
return count;
558
}
559
560
static ssize_t addr_start_show(struct kobject *kobj,
561
struct kobj_attribute *attr, char *buf)
562
{
563
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
564
struct damon_sysfs_scheme_filter, kobj);
565
566
return sysfs_emit(buf, "%lu\n", filter->addr_range.start);
567
}
568
569
static ssize_t addr_start_store(struct kobject *kobj,
570
struct kobj_attribute *attr, const char *buf, size_t count)
571
{
572
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
573
struct damon_sysfs_scheme_filter, kobj);
574
int err = kstrtoul(buf, 0, &filter->addr_range.start);
575
576
return err ? err : count;
577
}
578
579
static ssize_t addr_end_show(struct kobject *kobj,
580
struct kobj_attribute *attr, char *buf)
581
{
582
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
583
struct damon_sysfs_scheme_filter, kobj);
584
585
return sysfs_emit(buf, "%lu\n", filter->addr_range.end);
586
}
587
588
static ssize_t addr_end_store(struct kobject *kobj,
589
struct kobj_attribute *attr, const char *buf, size_t count)
590
{
591
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
592
struct damon_sysfs_scheme_filter, kobj);
593
int err = kstrtoul(buf, 0, &filter->addr_range.end);
594
595
return err ? err : count;
596
}
597
598
static ssize_t min_show(struct kobject *kobj,
599
struct kobj_attribute *attr, char *buf)
600
{
601
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
602
struct damon_sysfs_scheme_filter, kobj);
603
604
return sysfs_emit(buf, "%lu\n", filter->sz_range.min);
605
}
606
607
static ssize_t min_store(struct kobject *kobj,
608
struct kobj_attribute *attr, const char *buf, size_t count)
609
{
610
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
611
struct damon_sysfs_scheme_filter, kobj);
612
int err = kstrtoul(buf, 0, &filter->sz_range.min);
613
614
return err ? err : count;
615
}
616
617
static ssize_t max_show(struct kobject *kobj,
618
struct kobj_attribute *attr, char *buf)
619
{
620
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
621
struct damon_sysfs_scheme_filter, kobj);
622
623
return sysfs_emit(buf, "%lu\n", filter->sz_range.max);
624
}
625
626
static ssize_t max_store(struct kobject *kobj,
627
struct kobj_attribute *attr, const char *buf, size_t count)
628
{
629
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
630
struct damon_sysfs_scheme_filter, kobj);
631
int err = kstrtoul(buf, 0, &filter->sz_range.max);
632
633
return err ? err : count;
634
}
635
636
static ssize_t damon_target_idx_show(struct kobject *kobj,
637
struct kobj_attribute *attr, char *buf)
638
{
639
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
640
struct damon_sysfs_scheme_filter, kobj);
641
642
return sysfs_emit(buf, "%d\n", filter->target_idx);
643
}
644
645
static ssize_t damon_target_idx_store(struct kobject *kobj,
646
struct kobj_attribute *attr, const char *buf, size_t count)
647
{
648
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
649
struct damon_sysfs_scheme_filter, kobj);
650
int err = kstrtoint(buf, 0, &filter->target_idx);
651
652
return err ? err : count;
653
}
654
655
static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
656
{
657
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
658
struct damon_sysfs_scheme_filter, kobj);
659
660
kfree(filter->memcg_path);
661
kfree(filter);
662
}
663
664
static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
665
__ATTR_RW_MODE(type, 0600);
666
667
static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
668
__ATTR_RW_MODE(matching, 0600);
669
670
static struct kobj_attribute damon_sysfs_scheme_filter_allow_attr =
671
__ATTR_RW_MODE(allow, 0600);
672
673
static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
674
__ATTR_RW_MODE(memcg_path, 0600);
675
676
static struct kobj_attribute damon_sysfs_scheme_filter_addr_start_attr =
677
__ATTR_RW_MODE(addr_start, 0600);
678
679
static struct kobj_attribute damon_sysfs_scheme_filter_addr_end_attr =
680
__ATTR_RW_MODE(addr_end, 0600);
681
682
static struct kobj_attribute damon_sysfs_scheme_filter_min_attr =
683
__ATTR_RW_MODE(min, 0600);
684
685
static struct kobj_attribute damon_sysfs_scheme_filter_max_attr =
686
__ATTR_RW_MODE(max, 0600);
687
688
static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr =
689
__ATTR_RW_MODE(damon_target_idx, 0600);
690
691
static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
692
&damon_sysfs_scheme_filter_type_attr.attr,
693
&damon_sysfs_scheme_filter_matching_attr.attr,
694
&damon_sysfs_scheme_filter_allow_attr.attr,
695
&damon_sysfs_scheme_filter_memcg_path_attr.attr,
696
&damon_sysfs_scheme_filter_addr_start_attr.attr,
697
&damon_sysfs_scheme_filter_addr_end_attr.attr,
698
&damon_sysfs_scheme_filter_min_attr.attr,
699
&damon_sysfs_scheme_filter_max_attr.attr,
700
&damon_sysfs_scheme_filter_damon_target_idx_attr.attr,
701
NULL,
702
};
703
ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
704
705
static const struct kobj_type damon_sysfs_scheme_filter_ktype = {
706
.release = damon_sysfs_scheme_filter_release,
707
.sysfs_ops = &kobj_sysfs_ops,
708
.default_groups = damon_sysfs_scheme_filter_groups,
709
};
710
711
/*
712
* filters directory
713
*/
714
715
struct damon_sysfs_scheme_filters {
716
struct kobject kobj;
717
enum damos_sysfs_filter_handle_layer handle_layer;
718
struct damon_sysfs_scheme_filter **filters_arr;
719
int nr;
720
};
721
722
static struct damon_sysfs_scheme_filters *
723
damon_sysfs_scheme_filters_alloc(enum damos_sysfs_filter_handle_layer layer)
724
{
725
struct damon_sysfs_scheme_filters *filters;
726
727
filters = kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL);
728
if (filters)
729
filters->handle_layer = layer;
730
return filters;
731
}
732
733
static void damon_sysfs_scheme_filters_rm_dirs(
734
struct damon_sysfs_scheme_filters *filters)
735
{
736
struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;
737
int i;
738
739
for (i = 0; i < filters->nr; i++)
740
kobject_put(&filters_arr[i]->kobj);
741
filters->nr = 0;
742
kfree(filters_arr);
743
filters->filters_arr = NULL;
744
}
745
746
static int damon_sysfs_scheme_filters_add_dirs(
747
struct damon_sysfs_scheme_filters *filters, int nr_filters)
748
{
749
struct damon_sysfs_scheme_filter **filters_arr, *filter;
750
int err, i;
751
752
damon_sysfs_scheme_filters_rm_dirs(filters);
753
if (!nr_filters)
754
return 0;
755
756
filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
757
GFP_KERNEL | __GFP_NOWARN);
758
if (!filters_arr)
759
return -ENOMEM;
760
filters->filters_arr = filters_arr;
761
762
for (i = 0; i < nr_filters; i++) {
763
filter = damon_sysfs_scheme_filter_alloc(
764
filters->handle_layer);
765
if (!filter) {
766
damon_sysfs_scheme_filters_rm_dirs(filters);
767
return -ENOMEM;
768
}
769
770
err = kobject_init_and_add(&filter->kobj,
771
&damon_sysfs_scheme_filter_ktype,
772
&filters->kobj, "%d", i);
773
if (err) {
774
kobject_put(&filter->kobj);
775
damon_sysfs_scheme_filters_rm_dirs(filters);
776
return err;
777
}
778
779
filters_arr[i] = filter;
780
filters->nr++;
781
}
782
return 0;
783
}
784
785
static ssize_t nr_filters_show(struct kobject *kobj,
786
struct kobj_attribute *attr, char *buf)
787
{
788
struct damon_sysfs_scheme_filters *filters = container_of(kobj,
789
struct damon_sysfs_scheme_filters, kobj);
790
791
return sysfs_emit(buf, "%d\n", filters->nr);
792
}
793
794
static ssize_t nr_filters_store(struct kobject *kobj,
795
struct kobj_attribute *attr, const char *buf, size_t count)
796
{
797
struct damon_sysfs_scheme_filters *filters;
798
int nr, err = kstrtoint(buf, 0, &nr);
799
800
if (err)
801
return err;
802
if (nr < 0)
803
return -EINVAL;
804
805
filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj);
806
807
if (!mutex_trylock(&damon_sysfs_lock))
808
return -EBUSY;
809
err = damon_sysfs_scheme_filters_add_dirs(filters, nr);
810
mutex_unlock(&damon_sysfs_lock);
811
if (err)
812
return err;
813
814
return count;
815
}
816
817
static void damon_sysfs_scheme_filters_release(struct kobject *kobj)
818
{
819
kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj));
820
}
821
822
static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr =
823
__ATTR_RW_MODE(nr_filters, 0600);
824
825
static struct attribute *damon_sysfs_scheme_filters_attrs[] = {
826
&damon_sysfs_scheme_filters_nr_attr.attr,
827
NULL,
828
};
829
ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters);
830
831
static const struct kobj_type damon_sysfs_scheme_filters_ktype = {
832
.release = damon_sysfs_scheme_filters_release,
833
.sysfs_ops = &kobj_sysfs_ops,
834
.default_groups = damon_sysfs_scheme_filters_groups,
835
};
836
837
/*
838
* watermarks directory
839
*/
840
841
struct damon_sysfs_watermarks {
842
struct kobject kobj;
843
enum damos_wmark_metric metric;
844
unsigned long interval_us;
845
unsigned long high;
846
unsigned long mid;
847
unsigned long low;
848
};
849
850
static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
851
enum damos_wmark_metric metric, unsigned long interval_us,
852
unsigned long high, unsigned long mid, unsigned long low)
853
{
854
struct damon_sysfs_watermarks *watermarks = kmalloc(
855
sizeof(*watermarks), GFP_KERNEL);
856
857
if (!watermarks)
858
return NULL;
859
watermarks->kobj = (struct kobject){};
860
watermarks->metric = metric;
861
watermarks->interval_us = interval_us;
862
watermarks->high = high;
863
watermarks->mid = mid;
864
watermarks->low = low;
865
return watermarks;
866
}
867
868
struct damos_sysfs_wmark_metric_name {
869
enum damos_wmark_metric metric;
870
char *name;
871
};
872
873
static const struct damos_sysfs_wmark_metric_name
874
damos_sysfs_wmark_metric_names[] = {
875
{
876
.metric = DAMOS_WMARK_NONE,
877
.name = "none",
878
},
879
{
880
.metric = DAMOS_WMARK_FREE_MEM_RATE,
881
.name = "free_mem_rate",
882
},
883
};
884
885
static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
886
char *buf)
887
{
888
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
889
struct damon_sysfs_watermarks, kobj);
890
int i;
891
892
for (i = 0; i < ARRAY_SIZE(damos_sysfs_wmark_metric_names); i++) {
893
const struct damos_sysfs_wmark_metric_name *metric_name;
894
895
metric_name = &damos_sysfs_wmark_metric_names[i];
896
if (metric_name->metric == watermarks->metric)
897
return sysfs_emit(buf, "%s\n", metric_name->name);
898
}
899
return -EINVAL;
900
}
901
902
static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
903
const char *buf, size_t count)
904
{
905
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
906
struct damon_sysfs_watermarks, kobj);
907
int i;
908
909
for (i = 0; i < ARRAY_SIZE(damos_sysfs_wmark_metric_names); i++) {
910
const struct damos_sysfs_wmark_metric_name *metric_name;
911
912
metric_name = &damos_sysfs_wmark_metric_names[i];
913
if (sysfs_streq(buf, metric_name->name)) {
914
watermarks->metric = metric_name->metric;
915
return count;
916
}
917
}
918
return -EINVAL;
919
}
920
921
static ssize_t interval_us_show(struct kobject *kobj,
922
struct kobj_attribute *attr, char *buf)
923
{
924
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
925
struct damon_sysfs_watermarks, kobj);
926
927
return sysfs_emit(buf, "%lu\n", watermarks->interval_us);
928
}
929
930
static ssize_t interval_us_store(struct kobject *kobj,
931
struct kobj_attribute *attr, const char *buf, size_t count)
932
{
933
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
934
struct damon_sysfs_watermarks, kobj);
935
int err = kstrtoul(buf, 0, &watermarks->interval_us);
936
937
return err ? err : count;
938
}
939
940
static ssize_t high_show(struct kobject *kobj,
941
struct kobj_attribute *attr, char *buf)
942
{
943
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
944
struct damon_sysfs_watermarks, kobj);
945
946
return sysfs_emit(buf, "%lu\n", watermarks->high);
947
}
948
949
static ssize_t high_store(struct kobject *kobj,
950
struct kobj_attribute *attr, const char *buf, size_t count)
951
{
952
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
953
struct damon_sysfs_watermarks, kobj);
954
int err = kstrtoul(buf, 0, &watermarks->high);
955
956
return err ? err : count;
957
}
958
959
static ssize_t mid_show(struct kobject *kobj,
960
struct kobj_attribute *attr, char *buf)
961
{
962
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
963
struct damon_sysfs_watermarks, kobj);
964
965
return sysfs_emit(buf, "%lu\n", watermarks->mid);
966
}
967
968
static ssize_t mid_store(struct kobject *kobj,
969
struct kobj_attribute *attr, const char *buf, size_t count)
970
{
971
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
972
struct damon_sysfs_watermarks, kobj);
973
int err = kstrtoul(buf, 0, &watermarks->mid);
974
975
return err ? err : count;
976
}
977
978
static ssize_t low_show(struct kobject *kobj,
979
struct kobj_attribute *attr, char *buf)
980
{
981
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
982
struct damon_sysfs_watermarks, kobj);
983
984
return sysfs_emit(buf, "%lu\n", watermarks->low);
985
}
986
987
static ssize_t low_store(struct kobject *kobj,
988
struct kobj_attribute *attr, const char *buf, size_t count)
989
{
990
struct damon_sysfs_watermarks *watermarks = container_of(kobj,
991
struct damon_sysfs_watermarks, kobj);
992
int err = kstrtoul(buf, 0, &watermarks->low);
993
994
return err ? err : count;
995
}
996
997
static void damon_sysfs_watermarks_release(struct kobject *kobj)
998
{
999
kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
1000
}
1001
1002
static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
1003
__ATTR_RW_MODE(metric, 0600);
1004
1005
static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
1006
__ATTR_RW_MODE(interval_us, 0600);
1007
1008
static struct kobj_attribute damon_sysfs_watermarks_high_attr =
1009
__ATTR_RW_MODE(high, 0600);
1010
1011
static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
1012
__ATTR_RW_MODE(mid, 0600);
1013
1014
static struct kobj_attribute damon_sysfs_watermarks_low_attr =
1015
__ATTR_RW_MODE(low, 0600);
1016
1017
static struct attribute *damon_sysfs_watermarks_attrs[] = {
1018
&damon_sysfs_watermarks_metric_attr.attr,
1019
&damon_sysfs_watermarks_interval_us_attr.attr,
1020
&damon_sysfs_watermarks_high_attr.attr,
1021
&damon_sysfs_watermarks_mid_attr.attr,
1022
&damon_sysfs_watermarks_low_attr.attr,
1023
NULL,
1024
};
1025
ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
1026
1027
static const struct kobj_type damon_sysfs_watermarks_ktype = {
1028
.release = damon_sysfs_watermarks_release,
1029
.sysfs_ops = &kobj_sysfs_ops,
1030
.default_groups = damon_sysfs_watermarks_groups,
1031
};
1032
1033
/*
1034
* quota goal directory
1035
*/
1036
1037
struct damos_sysfs_quota_goal {
1038
struct kobject kobj;
1039
enum damos_quota_goal_metric metric;
1040
unsigned long target_value;
1041
unsigned long current_value;
1042
int nid;
1043
char *path;
1044
};
1045
1046
static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)
1047
{
1048
return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);
1049
}
1050
1051
struct damos_sysfs_qgoal_metric_name {
1052
enum damos_quota_goal_metric metric;
1053
char *name;
1054
};
1055
1056
static
1057
struct damos_sysfs_qgoal_metric_name damos_sysfs_qgoal_metric_names[] = {
1058
{
1059
.metric = DAMOS_QUOTA_USER_INPUT,
1060
.name = "user_input",
1061
},
1062
{
1063
.metric = DAMOS_QUOTA_SOME_MEM_PSI_US,
1064
.name = "some_mem_psi_us",
1065
},
1066
{
1067
.metric = DAMOS_QUOTA_NODE_MEM_USED_BP,
1068
.name = "node_mem_used_bp",
1069
},
1070
{
1071
.metric = DAMOS_QUOTA_NODE_MEM_FREE_BP,
1072
.name = "node_mem_free_bp",
1073
},
1074
{
1075
.metric = DAMOS_QUOTA_NODE_MEMCG_USED_BP,
1076
.name = "node_memcg_used_bp",
1077
},
1078
{
1079
.metric = DAMOS_QUOTA_NODE_MEMCG_FREE_BP,
1080
.name = "node_memcg_free_bp",
1081
},
1082
{
1083
.metric = DAMOS_QUOTA_ACTIVE_MEM_BP,
1084
.name = "active_mem_bp",
1085
},
1086
{
1087
.metric = DAMOS_QUOTA_INACTIVE_MEM_BP,
1088
.name = "inactive_mem_bp",
1089
},
1090
};
1091
1092
static ssize_t target_metric_show(struct kobject *kobj,
1093
struct kobj_attribute *attr, char *buf)
1094
{
1095
struct damos_sysfs_quota_goal *goal = container_of(kobj,
1096
struct damos_sysfs_quota_goal, kobj);
1097
int i;
1098
1099
for (i = 0; i < ARRAY_SIZE(damos_sysfs_qgoal_metric_names); i++) {
1100
struct damos_sysfs_qgoal_metric_name *metric_name;
1101
1102
metric_name = &damos_sysfs_qgoal_metric_names[i];
1103
if (metric_name->metric == goal->metric)
1104
return sysfs_emit(buf, "%s\n", metric_name->name);
1105
}
1106
return -EINVAL;
1107
}
1108
1109
static ssize_t target_metric_store(struct kobject *kobj,
1110
struct kobj_attribute *attr, const char *buf, size_t count)
1111
{
1112
struct damos_sysfs_quota_goal *goal = container_of(kobj,
1113
struct damos_sysfs_quota_goal, kobj);
1114
int i;
1115
1116
for (i = 0; i < ARRAY_SIZE(damos_sysfs_qgoal_metric_names); i++) {
1117
struct damos_sysfs_qgoal_metric_name *metric_name;
1118
1119
metric_name = &damos_sysfs_qgoal_metric_names[i];
1120
if (sysfs_streq(buf, metric_name->name)) {
1121
goal->metric = metric_name->metric;
1122
return count;
1123
}
1124
}
1125
return -EINVAL;
1126
}
1127
1128
static ssize_t target_value_show(struct kobject *kobj,
1129
struct kobj_attribute *attr, char *buf)
1130
{
1131
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1132
damos_sysfs_quota_goal, kobj);
1133
1134
return sysfs_emit(buf, "%lu\n", goal->target_value);
1135
}
1136
1137
static ssize_t target_value_store(struct kobject *kobj,
1138
struct kobj_attribute *attr, const char *buf, size_t count)
1139
{
1140
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1141
damos_sysfs_quota_goal, kobj);
1142
int err = kstrtoul(buf, 0, &goal->target_value);
1143
1144
return err ? err : count;
1145
}
1146
1147
static ssize_t current_value_show(struct kobject *kobj,
1148
struct kobj_attribute *attr, char *buf)
1149
{
1150
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1151
damos_sysfs_quota_goal, kobj);
1152
1153
return sysfs_emit(buf, "%lu\n", goal->current_value);
1154
}
1155
1156
static ssize_t current_value_store(struct kobject *kobj,
1157
struct kobj_attribute *attr, const char *buf, size_t count)
1158
{
1159
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1160
damos_sysfs_quota_goal, kobj);
1161
int err = kstrtoul(buf, 0, &goal->current_value);
1162
1163
/* feed callback should check existence of this file and read value */
1164
return err ? err : count;
1165
}
1166
1167
static ssize_t nid_show(struct kobject *kobj,
1168
struct kobj_attribute *attr, char *buf)
1169
{
1170
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1171
damos_sysfs_quota_goal, kobj);
1172
1173
1174
return sysfs_emit(buf, "%d\n", goal->nid);
1175
}
1176
1177
static ssize_t nid_store(struct kobject *kobj,
1178
struct kobj_attribute *attr, const char *buf, size_t count)
1179
{
1180
struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1181
damos_sysfs_quota_goal, kobj);
1182
int err = kstrtoint(buf, 0, &goal->nid);
1183
1184
/* feed callback should check existence of this file and read value */
1185
return err ? err : count;
1186
}
1187
1188
static ssize_t path_show(struct kobject *kobj,
1189
struct kobj_attribute *attr, char *buf)
1190
{
1191
struct damos_sysfs_quota_goal *goal = container_of(kobj,
1192
struct damos_sysfs_quota_goal, kobj);
1193
1194
return sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
1195
}
1196
1197
static ssize_t path_store(struct kobject *kobj,
1198
struct kobj_attribute *attr, const char *buf, size_t count)
1199
{
1200
struct damos_sysfs_quota_goal *goal = container_of(kobj,
1201
struct damos_sysfs_quota_goal, kobj);
1202
char *path = kmalloc_array(size_add(count, 1), sizeof(*path),
1203
GFP_KERNEL);
1204
1205
if (!path)
1206
return -ENOMEM;
1207
1208
strscpy(path, buf, count + 1);
1209
kfree(goal->path);
1210
goal->path = path;
1211
return count;
1212
}
1213
1214
static void damos_sysfs_quota_goal_release(struct kobject *kobj)
1215
{
1216
struct damos_sysfs_quota_goal *goal = container_of(kobj,
1217
struct damos_sysfs_quota_goal, kobj);
1218
1219
kfree(goal->path);
1220
kfree(goal);
1221
}
1222
1223
static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr =
1224
__ATTR_RW_MODE(target_metric, 0600);
1225
1226
static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =
1227
__ATTR_RW_MODE(target_value, 0600);
1228
1229
static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =
1230
__ATTR_RW_MODE(current_value, 0600);
1231
1232
static struct kobj_attribute damos_sysfs_quota_goal_nid_attr =
1233
__ATTR_RW_MODE(nid, 0600);
1234
1235
static struct kobj_attribute damos_sysfs_quota_goal_path_attr =
1236
__ATTR_RW_MODE(path, 0600);
1237
1238
static struct attribute *damos_sysfs_quota_goal_attrs[] = {
1239
&damos_sysfs_quota_goal_target_metric_attr.attr,
1240
&damos_sysfs_quota_goal_target_value_attr.attr,
1241
&damos_sysfs_quota_goal_current_value_attr.attr,
1242
&damos_sysfs_quota_goal_nid_attr.attr,
1243
&damos_sysfs_quota_goal_path_attr.attr,
1244
NULL,
1245
};
1246
ATTRIBUTE_GROUPS(damos_sysfs_quota_goal);
1247
1248
static const struct kobj_type damos_sysfs_quota_goal_ktype = {
1249
.release = damos_sysfs_quota_goal_release,
1250
.sysfs_ops = &kobj_sysfs_ops,
1251
.default_groups = damos_sysfs_quota_goal_groups,
1252
};
1253
1254
/*
1255
* quota goals directory
1256
*/
1257
1258
struct damos_sysfs_quota_goals {
1259
struct kobject kobj;
1260
struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */
1261
int nr;
1262
};
1263
1264
static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void)
1265
{
1266
return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL);
1267
}
1268
1269
static void damos_sysfs_quota_goals_rm_dirs(
1270
struct damos_sysfs_quota_goals *goals)
1271
{
1272
struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr;
1273
int i;
1274
1275
for (i = 0; i < goals->nr; i++)
1276
kobject_put(&goals_arr[i]->kobj);
1277
goals->nr = 0;
1278
kfree(goals_arr);
1279
goals->goals_arr = NULL;
1280
}
1281
1282
static int damos_sysfs_quota_goals_add_dirs(
1283
struct damos_sysfs_quota_goals *goals, int nr_goals)
1284
{
1285
struct damos_sysfs_quota_goal **goals_arr, *goal;
1286
int err, i;
1287
1288
damos_sysfs_quota_goals_rm_dirs(goals);
1289
if (!nr_goals)
1290
return 0;
1291
1292
goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr),
1293
GFP_KERNEL | __GFP_NOWARN);
1294
if (!goals_arr)
1295
return -ENOMEM;
1296
goals->goals_arr = goals_arr;
1297
1298
for (i = 0; i < nr_goals; i++) {
1299
goal = damos_sysfs_quota_goal_alloc();
1300
if (!goal) {
1301
damos_sysfs_quota_goals_rm_dirs(goals);
1302
return -ENOMEM;
1303
}
1304
1305
err = kobject_init_and_add(&goal->kobj,
1306
&damos_sysfs_quota_goal_ktype, &goals->kobj,
1307
"%d", i);
1308
if (err) {
1309
kobject_put(&goal->kobj);
1310
damos_sysfs_quota_goals_rm_dirs(goals);
1311
return err;
1312
}
1313
1314
goals_arr[i] = goal;
1315
goals->nr++;
1316
}
1317
return 0;
1318
}
1319
1320
static ssize_t nr_goals_show(struct kobject *kobj,
1321
struct kobj_attribute *attr, char *buf)
1322
{
1323
struct damos_sysfs_quota_goals *goals = container_of(kobj,
1324
struct damos_sysfs_quota_goals, kobj);
1325
1326
return sysfs_emit(buf, "%d\n", goals->nr);
1327
}
1328
1329
static ssize_t nr_goals_store(struct kobject *kobj,
1330
struct kobj_attribute *attr, const char *buf, size_t count)
1331
{
1332
struct damos_sysfs_quota_goals *goals;
1333
int nr, err = kstrtoint(buf, 0, &nr);
1334
1335
if (err)
1336
return err;
1337
if (nr < 0)
1338
return -EINVAL;
1339
1340
goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj);
1341
1342
if (!mutex_trylock(&damon_sysfs_lock))
1343
return -EBUSY;
1344
err = damos_sysfs_quota_goals_add_dirs(goals, nr);
1345
mutex_unlock(&damon_sysfs_lock);
1346
if (err)
1347
return err;
1348
1349
return count;
1350
}
1351
1352
static void damos_sysfs_quota_goals_release(struct kobject *kobj)
1353
{
1354
kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj));
1355
}
1356
1357
static struct kobj_attribute damos_sysfs_quota_goals_nr_attr =
1358
__ATTR_RW_MODE(nr_goals, 0600);
1359
1360
static struct attribute *damos_sysfs_quota_goals_attrs[] = {
1361
&damos_sysfs_quota_goals_nr_attr.attr,
1362
NULL,
1363
};
1364
ATTRIBUTE_GROUPS(damos_sysfs_quota_goals);
1365
1366
static const struct kobj_type damos_sysfs_quota_goals_ktype = {
1367
.release = damos_sysfs_quota_goals_release,
1368
.sysfs_ops = &kobj_sysfs_ops,
1369
.default_groups = damos_sysfs_quota_goals_groups,
1370
};
1371
1372
/*
1373
* scheme/weights directory
1374
*/
1375
1376
struct damon_sysfs_weights {
1377
struct kobject kobj;
1378
unsigned int sz;
1379
unsigned int nr_accesses;
1380
unsigned int age;
1381
};
1382
1383
static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
1384
unsigned int nr_accesses, unsigned int age)
1385
{
1386
struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
1387
GFP_KERNEL);
1388
1389
if (!weights)
1390
return NULL;
1391
weights->kobj = (struct kobject){};
1392
weights->sz = sz;
1393
weights->nr_accesses = nr_accesses;
1394
weights->age = age;
1395
return weights;
1396
}
1397
1398
static ssize_t sz_permil_show(struct kobject *kobj,
1399
struct kobj_attribute *attr, char *buf)
1400
{
1401
struct damon_sysfs_weights *weights = container_of(kobj,
1402
struct damon_sysfs_weights, kobj);
1403
1404
return sysfs_emit(buf, "%u\n", weights->sz);
1405
}
1406
1407
static ssize_t sz_permil_store(struct kobject *kobj,
1408
struct kobj_attribute *attr, const char *buf, size_t count)
1409
{
1410
struct damon_sysfs_weights *weights = container_of(kobj,
1411
struct damon_sysfs_weights, kobj);
1412
int err = kstrtouint(buf, 0, &weights->sz);
1413
1414
return err ? err : count;
1415
}
1416
1417
static ssize_t nr_accesses_permil_show(struct kobject *kobj,
1418
struct kobj_attribute *attr, char *buf)
1419
{
1420
struct damon_sysfs_weights *weights = container_of(kobj,
1421
struct damon_sysfs_weights, kobj);
1422
1423
return sysfs_emit(buf, "%u\n", weights->nr_accesses);
1424
}
1425
1426
static ssize_t nr_accesses_permil_store(struct kobject *kobj,
1427
struct kobj_attribute *attr, const char *buf, size_t count)
1428
{
1429
struct damon_sysfs_weights *weights = container_of(kobj,
1430
struct damon_sysfs_weights, kobj);
1431
int err = kstrtouint(buf, 0, &weights->nr_accesses);
1432
1433
return err ? err : count;
1434
}
1435
1436
static ssize_t age_permil_show(struct kobject *kobj,
1437
struct kobj_attribute *attr, char *buf)
1438
{
1439
struct damon_sysfs_weights *weights = container_of(kobj,
1440
struct damon_sysfs_weights, kobj);
1441
1442
return sysfs_emit(buf, "%u\n", weights->age);
1443
}
1444
1445
static ssize_t age_permil_store(struct kobject *kobj,
1446
struct kobj_attribute *attr, const char *buf, size_t count)
1447
{
1448
struct damon_sysfs_weights *weights = container_of(kobj,
1449
struct damon_sysfs_weights, kobj);
1450
int err = kstrtouint(buf, 0, &weights->age);
1451
1452
return err ? err : count;
1453
}
1454
1455
static void damon_sysfs_weights_release(struct kobject *kobj)
1456
{
1457
kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
1458
}
1459
1460
static struct kobj_attribute damon_sysfs_weights_sz_attr =
1461
__ATTR_RW_MODE(sz_permil, 0600);
1462
1463
static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
1464
__ATTR_RW_MODE(nr_accesses_permil, 0600);
1465
1466
static struct kobj_attribute damon_sysfs_weights_age_attr =
1467
__ATTR_RW_MODE(age_permil, 0600);
1468
1469
static struct attribute *damon_sysfs_weights_attrs[] = {
1470
&damon_sysfs_weights_sz_attr.attr,
1471
&damon_sysfs_weights_nr_accesses_attr.attr,
1472
&damon_sysfs_weights_age_attr.attr,
1473
NULL,
1474
};
1475
ATTRIBUTE_GROUPS(damon_sysfs_weights);
1476
1477
static const struct kobj_type damon_sysfs_weights_ktype = {
1478
.release = damon_sysfs_weights_release,
1479
.sysfs_ops = &kobj_sysfs_ops,
1480
.default_groups = damon_sysfs_weights_groups,
1481
};
1482
1483
/*
1484
* quotas directory
1485
*/
1486
1487
struct damon_sysfs_quotas {
1488
struct kobject kobj;
1489
struct damon_sysfs_weights *weights;
1490
struct damos_sysfs_quota_goals *goals;
1491
unsigned long ms;
1492
unsigned long sz;
1493
unsigned long reset_interval_ms;
1494
unsigned long effective_sz; /* Effective size quota in bytes */
1495
};
1496
1497
static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
1498
{
1499
return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
1500
}
1501
1502
static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
1503
{
1504
struct damon_sysfs_weights *weights;
1505
struct damos_sysfs_quota_goals *goals;
1506
int err;
1507
1508
weights = damon_sysfs_weights_alloc(0, 0, 0);
1509
if (!weights)
1510
return -ENOMEM;
1511
1512
err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
1513
&quotas->kobj, "weights");
1514
if (err) {
1515
kobject_put(&weights->kobj);
1516
return err;
1517
}
1518
quotas->weights = weights;
1519
1520
goals = damos_sysfs_quota_goals_alloc();
1521
if (!goals) {
1522
kobject_put(&weights->kobj);
1523
return -ENOMEM;
1524
}
1525
err = kobject_init_and_add(&goals->kobj,
1526
&damos_sysfs_quota_goals_ktype, &quotas->kobj,
1527
"goals");
1528
if (err) {
1529
kobject_put(&weights->kobj);
1530
kobject_put(&goals->kobj);
1531
} else {
1532
quotas->goals = goals;
1533
}
1534
1535
return err;
1536
}
1537
1538
static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
1539
{
1540
kobject_put(&quotas->weights->kobj);
1541
damos_sysfs_quota_goals_rm_dirs(quotas->goals);
1542
kobject_put(&quotas->goals->kobj);
1543
}
1544
1545
static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
1546
char *buf)
1547
{
1548
struct damon_sysfs_quotas *quotas = container_of(kobj,
1549
struct damon_sysfs_quotas, kobj);
1550
1551
return sysfs_emit(buf, "%lu\n", quotas->ms);
1552
}
1553
1554
static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
1555
const char *buf, size_t count)
1556
{
1557
struct damon_sysfs_quotas *quotas = container_of(kobj,
1558
struct damon_sysfs_quotas, kobj);
1559
int err = kstrtoul(buf, 0, &quotas->ms);
1560
1561
if (err)
1562
return -EINVAL;
1563
return count;
1564
}
1565
1566
static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
1567
char *buf)
1568
{
1569
struct damon_sysfs_quotas *quotas = container_of(kobj,
1570
struct damon_sysfs_quotas, kobj);
1571
1572
return sysfs_emit(buf, "%lu\n", quotas->sz);
1573
}
1574
1575
static ssize_t bytes_store(struct kobject *kobj,
1576
struct kobj_attribute *attr, const char *buf, size_t count)
1577
{
1578
struct damon_sysfs_quotas *quotas = container_of(kobj,
1579
struct damon_sysfs_quotas, kobj);
1580
int err = kstrtoul(buf, 0, &quotas->sz);
1581
1582
if (err)
1583
return -EINVAL;
1584
return count;
1585
}
1586
1587
static ssize_t reset_interval_ms_show(struct kobject *kobj,
1588
struct kobj_attribute *attr, char *buf)
1589
{
1590
struct damon_sysfs_quotas *quotas = container_of(kobj,
1591
struct damon_sysfs_quotas, kobj);
1592
1593
return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
1594
}
1595
1596
static ssize_t reset_interval_ms_store(struct kobject *kobj,
1597
struct kobj_attribute *attr, const char *buf, size_t count)
1598
{
1599
struct damon_sysfs_quotas *quotas = container_of(kobj,
1600
struct damon_sysfs_quotas, kobj);
1601
int err = kstrtoul(buf, 0, &quotas->reset_interval_ms);
1602
1603
if (err)
1604
return -EINVAL;
1605
return count;
1606
}
1607
1608
static ssize_t effective_bytes_show(struct kobject *kobj,
1609
struct kobj_attribute *attr, char *buf)
1610
{
1611
struct damon_sysfs_quotas *quotas = container_of(kobj,
1612
struct damon_sysfs_quotas, kobj);
1613
1614
return sysfs_emit(buf, "%lu\n", quotas->effective_sz);
1615
}
1616
1617
static void damon_sysfs_quotas_release(struct kobject *kobj)
1618
{
1619
kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
1620
}
1621
1622
static struct kobj_attribute damon_sysfs_quotas_ms_attr =
1623
__ATTR_RW_MODE(ms, 0600);
1624
1625
static struct kobj_attribute damon_sysfs_quotas_sz_attr =
1626
__ATTR_RW_MODE(bytes, 0600);
1627
1628
static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
1629
__ATTR_RW_MODE(reset_interval_ms, 0600);
1630
1631
static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr =
1632
__ATTR_RO_MODE(effective_bytes, 0400);
1633
1634
static struct attribute *damon_sysfs_quotas_attrs[] = {
1635
&damon_sysfs_quotas_ms_attr.attr,
1636
&damon_sysfs_quotas_sz_attr.attr,
1637
&damon_sysfs_quotas_reset_interval_ms_attr.attr,
1638
&damon_sysfs_quotas_effective_bytes_attr.attr,
1639
NULL,
1640
};
1641
ATTRIBUTE_GROUPS(damon_sysfs_quotas);
1642
1643
static const struct kobj_type damon_sysfs_quotas_ktype = {
1644
.release = damon_sysfs_quotas_release,
1645
.sysfs_ops = &kobj_sysfs_ops,
1646
.default_groups = damon_sysfs_quotas_groups,
1647
};
1648
1649
/*
1650
* access_pattern directory
1651
*/
1652
1653
struct damon_sysfs_access_pattern {
1654
struct kobject kobj;
1655
struct damon_sysfs_ul_range *sz;
1656
struct damon_sysfs_ul_range *nr_accesses;
1657
struct damon_sysfs_ul_range *age;
1658
};
1659
1660
static
1661
struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
1662
{
1663
struct damon_sysfs_access_pattern *access_pattern =
1664
kmalloc(sizeof(*access_pattern), GFP_KERNEL);
1665
1666
if (!access_pattern)
1667
return NULL;
1668
access_pattern->kobj = (struct kobject){};
1669
return access_pattern;
1670
}
1671
1672
static int damon_sysfs_access_pattern_add_range_dir(
1673
struct damon_sysfs_access_pattern *access_pattern,
1674
struct damon_sysfs_ul_range **range_dir_ptr,
1675
char *name)
1676
{
1677
struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
1678
int err;
1679
1680
if (!range)
1681
return -ENOMEM;
1682
err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
1683
&access_pattern->kobj, "%s", name);
1684
if (err)
1685
kobject_put(&range->kobj);
1686
else
1687
*range_dir_ptr = range;
1688
return err;
1689
}
1690
1691
static int damon_sysfs_access_pattern_add_dirs(
1692
struct damon_sysfs_access_pattern *access_pattern)
1693
{
1694
int err;
1695
1696
err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1697
&access_pattern->sz, "sz");
1698
if (err)
1699
goto put_sz_out;
1700
1701
err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1702
&access_pattern->nr_accesses, "nr_accesses");
1703
if (err)
1704
goto put_nr_accesses_sz_out;
1705
1706
err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1707
&access_pattern->age, "age");
1708
if (err)
1709
goto put_age_nr_accesses_sz_out;
1710
return 0;
1711
1712
put_age_nr_accesses_sz_out:
1713
kobject_put(&access_pattern->age->kobj);
1714
access_pattern->age = NULL;
1715
put_nr_accesses_sz_out:
1716
kobject_put(&access_pattern->nr_accesses->kobj);
1717
access_pattern->nr_accesses = NULL;
1718
put_sz_out:
1719
kobject_put(&access_pattern->sz->kobj);
1720
access_pattern->sz = NULL;
1721
return err;
1722
}
1723
1724
static void damon_sysfs_access_pattern_rm_dirs(
1725
struct damon_sysfs_access_pattern *access_pattern)
1726
{
1727
kobject_put(&access_pattern->sz->kobj);
1728
kobject_put(&access_pattern->nr_accesses->kobj);
1729
kobject_put(&access_pattern->age->kobj);
1730
}
1731
1732
static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1733
{
1734
kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1735
}
1736
1737
static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1738
NULL,
1739
};
1740
ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1741
1742
static const struct kobj_type damon_sysfs_access_pattern_ktype = {
1743
.release = damon_sysfs_access_pattern_release,
1744
.sysfs_ops = &kobj_sysfs_ops,
1745
.default_groups = damon_sysfs_access_pattern_groups,
1746
};
1747
1748
/*
1749
* dest (action destination) directory
1750
*/
1751
1752
struct damos_sysfs_dest {
1753
struct kobject kobj;
1754
unsigned int id;
1755
unsigned int weight;
1756
};
1757
1758
static struct damos_sysfs_dest *damos_sysfs_dest_alloc(void)
1759
{
1760
return kzalloc(sizeof(struct damos_sysfs_dest), GFP_KERNEL);
1761
}
1762
1763
static ssize_t id_show(
1764
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1765
{
1766
struct damos_sysfs_dest *dest = container_of(kobj,
1767
struct damos_sysfs_dest, kobj);
1768
1769
return sysfs_emit(buf, "%u\n", dest->id);
1770
}
1771
1772
static ssize_t id_store(struct kobject *kobj,
1773
struct kobj_attribute *attr, const char *buf, size_t count)
1774
{
1775
struct damos_sysfs_dest *dest = container_of(kobj,
1776
struct damos_sysfs_dest, kobj);
1777
int err = kstrtouint(buf, 0, &dest->id);
1778
1779
return err ? err : count;
1780
}
1781
1782
static ssize_t weight_show(
1783
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1784
{
1785
struct damos_sysfs_dest *dest = container_of(kobj,
1786
struct damos_sysfs_dest, kobj);
1787
1788
return sysfs_emit(buf, "%u\n", dest->weight);
1789
}
1790
1791
static ssize_t weight_store(struct kobject *kobj,
1792
struct kobj_attribute *attr, const char *buf, size_t count)
1793
{
1794
struct damos_sysfs_dest *dest = container_of(kobj,
1795
struct damos_sysfs_dest, kobj);
1796
int err = kstrtouint(buf, 0, &dest->weight);
1797
1798
return err ? err : count;
1799
}
1800
1801
static void damos_sysfs_dest_release(struct kobject *kobj)
1802
{
1803
struct damos_sysfs_dest *dest = container_of(kobj,
1804
struct damos_sysfs_dest, kobj);
1805
kfree(dest);
1806
}
1807
1808
static struct kobj_attribute damos_sysfs_dest_id_attr =
1809
__ATTR_RW_MODE(id, 0600);
1810
1811
static struct kobj_attribute damos_sysfs_dest_weight_attr =
1812
__ATTR_RW_MODE(weight, 0600);
1813
1814
static struct attribute *damos_sysfs_dest_attrs[] = {
1815
&damos_sysfs_dest_id_attr.attr,
1816
&damos_sysfs_dest_weight_attr.attr,
1817
NULL,
1818
};
1819
ATTRIBUTE_GROUPS(damos_sysfs_dest);
1820
1821
static const struct kobj_type damos_sysfs_dest_ktype = {
1822
.release = damos_sysfs_dest_release,
1823
.sysfs_ops = &kobj_sysfs_ops,
1824
.default_groups = damos_sysfs_dest_groups,
1825
};
1826
1827
/*
1828
* dests (action destinations) directory
1829
*/
1830
1831
struct damos_sysfs_dests {
1832
struct kobject kobj;
1833
struct damos_sysfs_dest **dests_arr;
1834
int nr;
1835
};
1836
1837
static struct damos_sysfs_dests *
1838
damos_sysfs_dests_alloc(void)
1839
{
1840
return kzalloc(sizeof(struct damos_sysfs_dests), GFP_KERNEL);
1841
}
1842
1843
static void damos_sysfs_dests_rm_dirs(
1844
struct damos_sysfs_dests *dests)
1845
{
1846
struct damos_sysfs_dest **dests_arr = dests->dests_arr;
1847
int i;
1848
1849
for (i = 0; i < dests->nr; i++)
1850
kobject_put(&dests_arr[i]->kobj);
1851
dests->nr = 0;
1852
kfree(dests_arr);
1853
dests->dests_arr = NULL;
1854
}
1855
1856
static int damos_sysfs_dests_add_dirs(
1857
struct damos_sysfs_dests *dests, int nr_dests)
1858
{
1859
struct damos_sysfs_dest **dests_arr, *dest;
1860
int err, i;
1861
1862
damos_sysfs_dests_rm_dirs(dests);
1863
if (!nr_dests)
1864
return 0;
1865
1866
dests_arr = kmalloc_array(nr_dests, sizeof(*dests_arr),
1867
GFP_KERNEL | __GFP_NOWARN);
1868
if (!dests_arr)
1869
return -ENOMEM;
1870
dests->dests_arr = dests_arr;
1871
1872
for (i = 0; i < nr_dests; i++) {
1873
dest = damos_sysfs_dest_alloc();
1874
if (!dest) {
1875
damos_sysfs_dests_rm_dirs(dests);
1876
return -ENOMEM;
1877
}
1878
1879
err = kobject_init_and_add(&dest->kobj,
1880
&damos_sysfs_dest_ktype,
1881
&dests->kobj, "%d", i);
1882
if (err) {
1883
kobject_put(&dest->kobj);
1884
damos_sysfs_dests_rm_dirs(dests);
1885
return err;
1886
}
1887
1888
dests_arr[i] = dest;
1889
dests->nr++;
1890
}
1891
return 0;
1892
}
1893
1894
static ssize_t nr_dests_show(struct kobject *kobj,
1895
struct kobj_attribute *attr, char *buf)
1896
{
1897
struct damos_sysfs_dests *dests = container_of(kobj,
1898
struct damos_sysfs_dests, kobj);
1899
1900
return sysfs_emit(buf, "%d\n", dests->nr);
1901
}
1902
1903
static ssize_t nr_dests_store(struct kobject *kobj,
1904
struct kobj_attribute *attr, const char *buf, size_t count)
1905
{
1906
struct damos_sysfs_dests *dests;
1907
int nr, err = kstrtoint(buf, 0, &nr);
1908
1909
if (err)
1910
return err;
1911
if (nr < 0)
1912
return -EINVAL;
1913
1914
dests = container_of(kobj, struct damos_sysfs_dests, kobj);
1915
1916
if (!mutex_trylock(&damon_sysfs_lock))
1917
return -EBUSY;
1918
err = damos_sysfs_dests_add_dirs(dests, nr);
1919
mutex_unlock(&damon_sysfs_lock);
1920
if (err)
1921
return err;
1922
1923
return count;
1924
}
1925
1926
static void damos_sysfs_dests_release(struct kobject *kobj)
1927
{
1928
kfree(container_of(kobj, struct damos_sysfs_dests, kobj));
1929
}
1930
1931
static struct kobj_attribute damos_sysfs_dests_nr_attr =
1932
__ATTR_RW_MODE(nr_dests, 0600);
1933
1934
static struct attribute *damos_sysfs_dests_attrs[] = {
1935
&damos_sysfs_dests_nr_attr.attr,
1936
NULL,
1937
};
1938
ATTRIBUTE_GROUPS(damos_sysfs_dests);
1939
1940
static const struct kobj_type damos_sysfs_dests_ktype = {
1941
.release = damos_sysfs_dests_release,
1942
.sysfs_ops = &kobj_sysfs_ops,
1943
.default_groups = damos_sysfs_dests_groups,
1944
};
1945
1946
/*
1947
* scheme directory
1948
*/
1949
1950
struct damon_sysfs_scheme {
1951
struct kobject kobj;
1952
enum damos_action action;
1953
struct damon_sysfs_access_pattern *access_pattern;
1954
unsigned long apply_interval_us;
1955
struct damon_sysfs_quotas *quotas;
1956
struct damon_sysfs_watermarks *watermarks;
1957
struct damon_sysfs_scheme_filters *core_filters;
1958
struct damon_sysfs_scheme_filters *ops_filters;
1959
struct damon_sysfs_scheme_filters *filters;
1960
struct damon_sysfs_stats *stats;
1961
struct damon_sysfs_scheme_regions *tried_regions;
1962
int target_nid;
1963
struct damos_sysfs_dests *dests;
1964
};
1965
1966
struct damos_sysfs_action_name {
1967
enum damos_action action;
1968
char *name;
1969
};
1970
1971
static struct damos_sysfs_action_name damos_sysfs_action_names[] = {
1972
{
1973
.action = DAMOS_WILLNEED,
1974
.name = "willneed",
1975
},
1976
{
1977
.action = DAMOS_COLD,
1978
.name = "cold",
1979
},
1980
{
1981
.action = DAMOS_PAGEOUT,
1982
.name = "pageout",
1983
},
1984
{
1985
.action = DAMOS_HUGEPAGE,
1986
.name = "hugepage",
1987
},
1988
{
1989
.action = DAMOS_NOHUGEPAGE,
1990
.name = "nohugepage",
1991
},
1992
{
1993
.action = DAMOS_LRU_PRIO,
1994
.name = "lru_prio",
1995
},
1996
{
1997
.action = DAMOS_LRU_DEPRIO,
1998
.name = "lru_deprio",
1999
},
2000
{
2001
.action = DAMOS_MIGRATE_HOT,
2002
.name = "migrate_hot",
2003
},
2004
{
2005
.action = DAMOS_MIGRATE_COLD,
2006
.name = "migrate_cold",
2007
},
2008
{
2009
.action = DAMOS_STAT,
2010
.name = "stat",
2011
},
2012
};
2013
2014
static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
2015
enum damos_action action, unsigned long apply_interval_us)
2016
{
2017
struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
2018
GFP_KERNEL);
2019
2020
if (!scheme)
2021
return NULL;
2022
scheme->kobj = (struct kobject){};
2023
scheme->action = action;
2024
scheme->apply_interval_us = apply_interval_us;
2025
scheme->target_nid = NUMA_NO_NODE;
2026
return scheme;
2027
}
2028
2029
static int damon_sysfs_scheme_set_access_pattern(
2030
struct damon_sysfs_scheme *scheme)
2031
{
2032
struct damon_sysfs_access_pattern *access_pattern;
2033
int err;
2034
2035
access_pattern = damon_sysfs_access_pattern_alloc();
2036
if (!access_pattern)
2037
return -ENOMEM;
2038
err = kobject_init_and_add(&access_pattern->kobj,
2039
&damon_sysfs_access_pattern_ktype, &scheme->kobj,
2040
"access_pattern");
2041
if (err)
2042
goto out;
2043
err = damon_sysfs_access_pattern_add_dirs(access_pattern);
2044
if (err)
2045
goto out;
2046
scheme->access_pattern = access_pattern;
2047
return 0;
2048
2049
out:
2050
kobject_put(&access_pattern->kobj);
2051
return err;
2052
}
2053
2054
static int damos_sysfs_set_dests(struct damon_sysfs_scheme *scheme)
2055
{
2056
struct damos_sysfs_dests *dests = damos_sysfs_dests_alloc();
2057
int err;
2058
2059
if (!dests)
2060
return -ENOMEM;
2061
err = kobject_init_and_add(&dests->kobj, &damos_sysfs_dests_ktype,
2062
&scheme->kobj, "dests");
2063
if (err)
2064
kobject_put(&dests->kobj);
2065
else
2066
scheme->dests = dests;
2067
return err;
2068
}
2069
2070
static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
2071
{
2072
struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
2073
int err;
2074
2075
if (!quotas)
2076
return -ENOMEM;
2077
err = kobject_init_and_add(&quotas->kobj, &damon_sysfs_quotas_ktype,
2078
&scheme->kobj, "quotas");
2079
if (err)
2080
goto out;
2081
err = damon_sysfs_quotas_add_dirs(quotas);
2082
if (err)
2083
goto out;
2084
scheme->quotas = quotas;
2085
return 0;
2086
2087
out:
2088
kobject_put(&quotas->kobj);
2089
return err;
2090
}
2091
2092
static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
2093
{
2094
struct damon_sysfs_watermarks *watermarks =
2095
damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
2096
int err;
2097
2098
if (!watermarks)
2099
return -ENOMEM;
2100
err = kobject_init_and_add(&watermarks->kobj,
2101
&damon_sysfs_watermarks_ktype, &scheme->kobj,
2102
"watermarks");
2103
if (err)
2104
kobject_put(&watermarks->kobj);
2105
else
2106
scheme->watermarks = watermarks;
2107
return err;
2108
}
2109
2110
static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme,
2111
enum damos_sysfs_filter_handle_layer layer, const char *name,
2112
struct damon_sysfs_scheme_filters **filters_ptr)
2113
{
2114
struct damon_sysfs_scheme_filters *filters =
2115
damon_sysfs_scheme_filters_alloc(layer);
2116
int err;
2117
2118
if (!filters)
2119
return -ENOMEM;
2120
err = kobject_init_and_add(&filters->kobj,
2121
&damon_sysfs_scheme_filters_ktype, &scheme->kobj,
2122
"%s", name);
2123
if (err)
2124
kobject_put(&filters->kobj);
2125
else
2126
*filters_ptr = filters;
2127
return err;
2128
}
2129
2130
static int damos_sysfs_set_filter_dirs(struct damon_sysfs_scheme *scheme)
2131
{
2132
int err;
2133
2134
err = damon_sysfs_scheme_set_filters(scheme,
2135
DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH, "filters",
2136
&scheme->filters);
2137
if (err)
2138
return err;
2139
err = damon_sysfs_scheme_set_filters(scheme,
2140
DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE, "core_filters",
2141
&scheme->core_filters);
2142
if (err)
2143
goto put_filters_out;
2144
err = damon_sysfs_scheme_set_filters(scheme,
2145
DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS, "ops_filters",
2146
&scheme->ops_filters);
2147
if (err)
2148
goto put_core_filters_out;
2149
return 0;
2150
2151
put_core_filters_out:
2152
kobject_put(&scheme->core_filters->kobj);
2153
scheme->core_filters = NULL;
2154
put_filters_out:
2155
kobject_put(&scheme->filters->kobj);
2156
scheme->filters = NULL;
2157
return err;
2158
}
2159
2160
static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
2161
{
2162
struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
2163
int err;
2164
2165
if (!stats)
2166
return -ENOMEM;
2167
err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
2168
&scheme->kobj, "stats");
2169
if (err)
2170
kobject_put(&stats->kobj);
2171
else
2172
scheme->stats = stats;
2173
return err;
2174
}
2175
2176
static int damon_sysfs_scheme_set_tried_regions(
2177
struct damon_sysfs_scheme *scheme)
2178
{
2179
struct damon_sysfs_scheme_regions *tried_regions =
2180
damon_sysfs_scheme_regions_alloc();
2181
int err;
2182
2183
if (!tried_regions)
2184
return -ENOMEM;
2185
err = kobject_init_and_add(&tried_regions->kobj,
2186
&damon_sysfs_scheme_regions_ktype, &scheme->kobj,
2187
"tried_regions");
2188
if (err)
2189
kobject_put(&tried_regions->kobj);
2190
else
2191
scheme->tried_regions = tried_regions;
2192
return err;
2193
}
2194
2195
static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
2196
{
2197
int err;
2198
2199
err = damon_sysfs_scheme_set_access_pattern(scheme);
2200
if (err)
2201
return err;
2202
err = damos_sysfs_set_dests(scheme);
2203
if (err)
2204
goto rmdir_put_access_pattern_out;
2205
err = damon_sysfs_scheme_set_quotas(scheme);
2206
if (err)
2207
goto put_dests_out;
2208
err = damon_sysfs_scheme_set_watermarks(scheme);
2209
if (err)
2210
goto rmdir_put_quotas_access_pattern_out;
2211
err = damos_sysfs_set_filter_dirs(scheme);
2212
if (err)
2213
goto put_watermarks_quotas_access_pattern_out;
2214
err = damon_sysfs_scheme_set_stats(scheme);
2215
if (err)
2216
goto put_filters_watermarks_quotas_access_pattern_out;
2217
err = damon_sysfs_scheme_set_tried_regions(scheme);
2218
if (err)
2219
goto put_tried_regions_out;
2220
return 0;
2221
2222
put_tried_regions_out:
2223
kobject_put(&scheme->tried_regions->kobj);
2224
scheme->tried_regions = NULL;
2225
put_filters_watermarks_quotas_access_pattern_out:
2226
kobject_put(&scheme->ops_filters->kobj);
2227
scheme->ops_filters = NULL;
2228
kobject_put(&scheme->core_filters->kobj);
2229
scheme->core_filters = NULL;
2230
kobject_put(&scheme->filters->kobj);
2231
scheme->filters = NULL;
2232
put_watermarks_quotas_access_pattern_out:
2233
kobject_put(&scheme->watermarks->kobj);
2234
scheme->watermarks = NULL;
2235
rmdir_put_quotas_access_pattern_out:
2236
damon_sysfs_quotas_rm_dirs(scheme->quotas);
2237
kobject_put(&scheme->quotas->kobj);
2238
scheme->quotas = NULL;
2239
put_dests_out:
2240
kobject_put(&scheme->dests->kobj);
2241
scheme->dests = NULL;
2242
rmdir_put_access_pattern_out:
2243
damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
2244
kobject_put(&scheme->access_pattern->kobj);
2245
scheme->access_pattern = NULL;
2246
return err;
2247
}
2248
2249
static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
2250
{
2251
damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
2252
kobject_put(&scheme->access_pattern->kobj);
2253
damos_sysfs_dests_rm_dirs(scheme->dests);
2254
kobject_put(&scheme->dests->kobj);
2255
damon_sysfs_quotas_rm_dirs(scheme->quotas);
2256
kobject_put(&scheme->quotas->kobj);
2257
kobject_put(&scheme->watermarks->kobj);
2258
damon_sysfs_scheme_filters_rm_dirs(scheme->filters);
2259
kobject_put(&scheme->filters->kobj);
2260
damon_sysfs_scheme_filters_rm_dirs(scheme->core_filters);
2261
kobject_put(&scheme->core_filters->kobj);
2262
damon_sysfs_scheme_filters_rm_dirs(scheme->ops_filters);
2263
kobject_put(&scheme->ops_filters->kobj);
2264
kobject_put(&scheme->stats->kobj);
2265
damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
2266
kobject_put(&scheme->tried_regions->kobj);
2267
}
2268
2269
static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
2270
char *buf)
2271
{
2272
struct damon_sysfs_scheme *scheme = container_of(kobj,
2273
struct damon_sysfs_scheme, kobj);
2274
int i;
2275
2276
for (i = 0; i < ARRAY_SIZE(damos_sysfs_action_names); i++) {
2277
struct damos_sysfs_action_name *action_name;
2278
2279
action_name = &damos_sysfs_action_names[i];
2280
if (action_name->action == scheme->action)
2281
return sysfs_emit(buf, "%s\n", action_name->name);
2282
}
2283
return -EINVAL;
2284
}
2285
2286
static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
2287
const char *buf, size_t count)
2288
{
2289
struct damon_sysfs_scheme *scheme = container_of(kobj,
2290
struct damon_sysfs_scheme, kobj);
2291
int i;
2292
2293
for (i = 0; i < ARRAY_SIZE(damos_sysfs_action_names); i++) {
2294
struct damos_sysfs_action_name *action_name;
2295
2296
action_name = &damos_sysfs_action_names[i];
2297
if (sysfs_streq(buf, action_name->name)) {
2298
scheme->action = action_name->action;
2299
return count;
2300
}
2301
}
2302
return -EINVAL;
2303
}
2304
2305
static ssize_t apply_interval_us_show(struct kobject *kobj,
2306
struct kobj_attribute *attr, char *buf)
2307
{
2308
struct damon_sysfs_scheme *scheme = container_of(kobj,
2309
struct damon_sysfs_scheme, kobj);
2310
2311
return sysfs_emit(buf, "%lu\n", scheme->apply_interval_us);
2312
}
2313
2314
static ssize_t apply_interval_us_store(struct kobject *kobj,
2315
struct kobj_attribute *attr, const char *buf, size_t count)
2316
{
2317
struct damon_sysfs_scheme *scheme = container_of(kobj,
2318
struct damon_sysfs_scheme, kobj);
2319
int err = kstrtoul(buf, 0, &scheme->apply_interval_us);
2320
2321
return err ? err : count;
2322
}
2323
2324
static ssize_t target_nid_show(struct kobject *kobj,
2325
struct kobj_attribute *attr, char *buf)
2326
{
2327
struct damon_sysfs_scheme *scheme = container_of(kobj,
2328
struct damon_sysfs_scheme, kobj);
2329
2330
return sysfs_emit(buf, "%d\n", scheme->target_nid);
2331
}
2332
2333
static ssize_t target_nid_store(struct kobject *kobj,
2334
struct kobj_attribute *attr, const char *buf, size_t count)
2335
{
2336
struct damon_sysfs_scheme *scheme = container_of(kobj,
2337
struct damon_sysfs_scheme, kobj);
2338
int err = 0;
2339
2340
err = kstrtoint(buf, 0, &scheme->target_nid);
2341
2342
return err ? err : count;
2343
}
2344
2345
static void damon_sysfs_scheme_release(struct kobject *kobj)
2346
{
2347
kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
2348
}
2349
2350
static struct kobj_attribute damon_sysfs_scheme_action_attr =
2351
__ATTR_RW_MODE(action, 0600);
2352
2353
static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
2354
__ATTR_RW_MODE(apply_interval_us, 0600);
2355
2356
static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =
2357
__ATTR_RW_MODE(target_nid, 0600);
2358
2359
static struct attribute *damon_sysfs_scheme_attrs[] = {
2360
&damon_sysfs_scheme_action_attr.attr,
2361
&damon_sysfs_scheme_apply_interval_us_attr.attr,
2362
&damon_sysfs_scheme_target_nid_attr.attr,
2363
NULL,
2364
};
2365
ATTRIBUTE_GROUPS(damon_sysfs_scheme);
2366
2367
static const struct kobj_type damon_sysfs_scheme_ktype = {
2368
.release = damon_sysfs_scheme_release,
2369
.sysfs_ops = &kobj_sysfs_ops,
2370
.default_groups = damon_sysfs_scheme_groups,
2371
};
2372
2373
/*
2374
* schemes directory
2375
*/
2376
2377
struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
2378
{
2379
return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
2380
}
2381
2382
void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
2383
{
2384
struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
2385
int i;
2386
2387
for (i = 0; i < schemes->nr; i++) {
2388
damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
2389
kobject_put(&schemes_arr[i]->kobj);
2390
}
2391
schemes->nr = 0;
2392
kfree(schemes_arr);
2393
schemes->schemes_arr = NULL;
2394
}
2395
2396
static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
2397
int nr_schemes)
2398
{
2399
struct damon_sysfs_scheme **schemes_arr, *scheme;
2400
int err, i;
2401
2402
damon_sysfs_schemes_rm_dirs(schemes);
2403
if (!nr_schemes)
2404
return 0;
2405
2406
schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
2407
GFP_KERNEL | __GFP_NOWARN);
2408
if (!schemes_arr)
2409
return -ENOMEM;
2410
schemes->schemes_arr = schemes_arr;
2411
2412
for (i = 0; i < nr_schemes; i++) {
2413
/*
2414
* apply_interval_us as 0 means same to aggregation interval
2415
* (same to before-apply_interval behavior)
2416
*/
2417
scheme = damon_sysfs_scheme_alloc(DAMOS_STAT, 0);
2418
if (!scheme) {
2419
damon_sysfs_schemes_rm_dirs(schemes);
2420
return -ENOMEM;
2421
}
2422
2423
err = kobject_init_and_add(&scheme->kobj,
2424
&damon_sysfs_scheme_ktype, &schemes->kobj,
2425
"%d", i);
2426
if (err)
2427
goto out;
2428
err = damon_sysfs_scheme_add_dirs(scheme);
2429
if (err)
2430
goto out;
2431
2432
schemes_arr[i] = scheme;
2433
schemes->nr++;
2434
}
2435
return 0;
2436
2437
out:
2438
damon_sysfs_schemes_rm_dirs(schemes);
2439
kobject_put(&scheme->kobj);
2440
return err;
2441
}
2442
2443
static ssize_t nr_schemes_show(struct kobject *kobj,
2444
struct kobj_attribute *attr, char *buf)
2445
{
2446
struct damon_sysfs_schemes *schemes = container_of(kobj,
2447
struct damon_sysfs_schemes, kobj);
2448
2449
return sysfs_emit(buf, "%d\n", schemes->nr);
2450
}
2451
2452
static ssize_t nr_schemes_store(struct kobject *kobj,
2453
struct kobj_attribute *attr, const char *buf, size_t count)
2454
{
2455
struct damon_sysfs_schemes *schemes;
2456
int nr, err = kstrtoint(buf, 0, &nr);
2457
2458
if (err)
2459
return err;
2460
if (nr < 0)
2461
return -EINVAL;
2462
2463
schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
2464
2465
if (!mutex_trylock(&damon_sysfs_lock))
2466
return -EBUSY;
2467
err = damon_sysfs_schemes_add_dirs(schemes, nr);
2468
mutex_unlock(&damon_sysfs_lock);
2469
if (err)
2470
return err;
2471
return count;
2472
}
2473
2474
static void damon_sysfs_schemes_release(struct kobject *kobj)
2475
{
2476
kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
2477
}
2478
2479
static struct kobj_attribute damon_sysfs_schemes_nr_attr =
2480
__ATTR_RW_MODE(nr_schemes, 0600);
2481
2482
static struct attribute *damon_sysfs_schemes_attrs[] = {
2483
&damon_sysfs_schemes_nr_attr.attr,
2484
NULL,
2485
};
2486
ATTRIBUTE_GROUPS(damon_sysfs_schemes);
2487
2488
const struct kobj_type damon_sysfs_schemes_ktype = {
2489
.release = damon_sysfs_schemes_release,
2490
.sysfs_ops = &kobj_sysfs_ops,
2491
.default_groups = damon_sysfs_schemes_groups,
2492
};
2493
2494
static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
2495
char *memcg_path_buf, char *path)
2496
{
2497
#ifdef CONFIG_MEMCG
2498
cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
2499
if (sysfs_streq(memcg_path_buf, path))
2500
return true;
2501
#endif /* CONFIG_MEMCG */
2502
return false;
2503
}
2504
2505
static int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
2506
{
2507
struct mem_cgroup *memcg;
2508
char *path;
2509
bool found = false;
2510
2511
if (!memcg_path)
2512
return -EINVAL;
2513
2514
path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
2515
if (!path)
2516
return -ENOMEM;
2517
2518
for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
2519
memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
2520
/* skip offlined memcg */
2521
if (!mem_cgroup_online(memcg))
2522
continue;
2523
if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
2524
*id = mem_cgroup_id(memcg);
2525
found = true;
2526
break;
2527
}
2528
}
2529
2530
kfree(path);
2531
return found ? 0 : -EINVAL;
2532
}
2533
2534
static int damon_sysfs_add_scheme_filters(struct damos *scheme,
2535
struct damon_sysfs_scheme_filters *sysfs_filters)
2536
{
2537
int i;
2538
2539
for (i = 0; i < sysfs_filters->nr; i++) {
2540
struct damon_sysfs_scheme_filter *sysfs_filter =
2541
sysfs_filters->filters_arr[i];
2542
struct damos_filter *filter =
2543
damos_new_filter(sysfs_filter->type,
2544
sysfs_filter->matching,
2545
sysfs_filter->allow);
2546
int err;
2547
2548
if (!filter)
2549
return -ENOMEM;
2550
if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
2551
err = damon_sysfs_memcg_path_to_id(
2552
sysfs_filter->memcg_path,
2553
&filter->memcg_id);
2554
if (err) {
2555
damos_destroy_filter(filter);
2556
return err;
2557
}
2558
} else if (filter->type == DAMOS_FILTER_TYPE_ADDR) {
2559
if (sysfs_filter->addr_range.end <
2560
sysfs_filter->addr_range.start) {
2561
damos_destroy_filter(filter);
2562
return -EINVAL;
2563
}
2564
filter->addr_range = sysfs_filter->addr_range;
2565
} else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
2566
filter->target_idx = sysfs_filter->target_idx;
2567
} else if (filter->type == DAMOS_FILTER_TYPE_HUGEPAGE_SIZE) {
2568
if (sysfs_filter->sz_range.min >
2569
sysfs_filter->sz_range.max) {
2570
damos_destroy_filter(filter);
2571
return -EINVAL;
2572
}
2573
filter->sz_range = sysfs_filter->sz_range;
2574
}
2575
2576
damos_add_filter(scheme, filter);
2577
}
2578
return 0;
2579
}
2580
2581
static int damos_sysfs_add_quota_score(
2582
struct damos_sysfs_quota_goals *sysfs_goals,
2583
struct damos_quota *quota)
2584
{
2585
struct damos_quota_goal *goal;
2586
int i, err;
2587
2588
for (i = 0; i < sysfs_goals->nr; i++) {
2589
struct damos_sysfs_quota_goal *sysfs_goal =
2590
sysfs_goals->goals_arr[i];
2591
2592
if (!sysfs_goal->target_value)
2593
continue;
2594
2595
goal = damos_new_quota_goal(sysfs_goal->metric,
2596
sysfs_goal->target_value);
2597
if (!goal)
2598
return -ENOMEM;
2599
switch (sysfs_goal->metric) {
2600
case DAMOS_QUOTA_USER_INPUT:
2601
goal->current_value = sysfs_goal->current_value;
2602
break;
2603
case DAMOS_QUOTA_NODE_MEM_USED_BP:
2604
case DAMOS_QUOTA_NODE_MEM_FREE_BP:
2605
goal->nid = sysfs_goal->nid;
2606
break;
2607
case DAMOS_QUOTA_NODE_MEMCG_USED_BP:
2608
case DAMOS_QUOTA_NODE_MEMCG_FREE_BP:
2609
err = damon_sysfs_memcg_path_to_id(
2610
sysfs_goal->path, &goal->memcg_id);
2611
if (err) {
2612
damos_destroy_quota_goal(goal);
2613
return err;
2614
}
2615
goal->nid = sysfs_goal->nid;
2616
break;
2617
default:
2618
break;
2619
}
2620
damos_add_quota_goal(quota, goal);
2621
}
2622
return 0;
2623
}
2624
2625
int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
2626
struct damon_ctx *ctx)
2627
{
2628
struct damos *scheme;
2629
struct damos_quota quota = {};
2630
int i = 0;
2631
2632
INIT_LIST_HEAD(&quota.goals);
2633
damon_for_each_scheme(scheme, ctx) {
2634
struct damon_sysfs_scheme *sysfs_scheme;
2635
struct damos_quota_goal *g, *g_next;
2636
int err;
2637
2638
/* user could have removed the scheme sysfs dir */
2639
if (i >= sysfs_schemes->nr)
2640
break;
2641
2642
sysfs_scheme = sysfs_schemes->schemes_arr[i];
2643
err = damos_sysfs_add_quota_score(sysfs_scheme->quotas->goals,
2644
&quota);
2645
if (err) {
2646
damos_for_each_quota_goal_safe(g, g_next, &quota)
2647
damos_destroy_quota_goal(g);
2648
return err;
2649
}
2650
err = damos_commit_quota_goals(&scheme->quota, &quota);
2651
damos_for_each_quota_goal_safe(g, g_next, &quota)
2652
damos_destroy_quota_goal(g);
2653
if (err)
2654
return err;
2655
i++;
2656
}
2657
return 0;
2658
}
2659
2660
void damos_sysfs_update_effective_quotas(
2661
struct damon_sysfs_schemes *sysfs_schemes,
2662
struct damon_ctx *ctx)
2663
{
2664
struct damos *scheme;
2665
int schemes_idx = 0;
2666
2667
damon_for_each_scheme(scheme, ctx) {
2668
struct damon_sysfs_quotas *sysfs_quotas;
2669
2670
/* user could have removed the scheme sysfs dir */
2671
if (schemes_idx >= sysfs_schemes->nr)
2672
break;
2673
2674
sysfs_quotas =
2675
sysfs_schemes->schemes_arr[schemes_idx++]->quotas;
2676
sysfs_quotas->effective_sz = scheme->quota.esz;
2677
}
2678
}
2679
2680
static int damos_sysfs_add_migrate_dest(struct damos *scheme,
2681
struct damos_sysfs_dests *sysfs_dests)
2682
{
2683
struct damos_migrate_dests *dests = &scheme->migrate_dests;
2684
int i;
2685
2686
dests->node_id_arr = kmalloc_array(sysfs_dests->nr,
2687
sizeof(*dests->node_id_arr), GFP_KERNEL);
2688
if (!dests->node_id_arr)
2689
return -ENOMEM;
2690
dests->weight_arr = kmalloc_array(sysfs_dests->nr,
2691
sizeof(*dests->weight_arr), GFP_KERNEL);
2692
if (!dests->weight_arr)
2693
/* ->node_id_arr will be freed by scheme destruction */
2694
return -ENOMEM;
2695
for (i = 0; i < sysfs_dests->nr; i++) {
2696
dests->node_id_arr[i] = sysfs_dests->dests_arr[i]->id;
2697
dests->weight_arr[i] = sysfs_dests->dests_arr[i]->weight;
2698
}
2699
dests->nr_dests = sysfs_dests->nr;
2700
return 0;
2701
}
2702
2703
static struct damos *damon_sysfs_mk_scheme(
2704
struct damon_sysfs_scheme *sysfs_scheme)
2705
{
2706
struct damon_sysfs_access_pattern *access_pattern =
2707
sysfs_scheme->access_pattern;
2708
struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
2709
struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
2710
struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
2711
struct damos *scheme;
2712
int err;
2713
2714
struct damos_access_pattern pattern = {
2715
.min_sz_region = access_pattern->sz->min,
2716
.max_sz_region = access_pattern->sz->max,
2717
.min_nr_accesses = access_pattern->nr_accesses->min,
2718
.max_nr_accesses = access_pattern->nr_accesses->max,
2719
.min_age_region = access_pattern->age->min,
2720
.max_age_region = access_pattern->age->max,
2721
};
2722
struct damos_quota quota = {
2723
.ms = sysfs_quotas->ms,
2724
.sz = sysfs_quotas->sz,
2725
.reset_interval = sysfs_quotas->reset_interval_ms,
2726
.weight_sz = sysfs_weights->sz,
2727
.weight_nr_accesses = sysfs_weights->nr_accesses,
2728
.weight_age = sysfs_weights->age,
2729
};
2730
struct damos_watermarks wmarks = {
2731
.metric = sysfs_wmarks->metric,
2732
.interval = sysfs_wmarks->interval_us,
2733
.high = sysfs_wmarks->high,
2734
.mid = sysfs_wmarks->mid,
2735
.low = sysfs_wmarks->low,
2736
};
2737
2738
scheme = damon_new_scheme(&pattern, sysfs_scheme->action,
2739
sysfs_scheme->apply_interval_us, &quota, &wmarks,
2740
sysfs_scheme->target_nid);
2741
if (!scheme)
2742
return NULL;
2743
2744
err = damos_sysfs_add_quota_score(sysfs_quotas->goals, &scheme->quota);
2745
if (err) {
2746
damon_destroy_scheme(scheme);
2747
return NULL;
2748
}
2749
2750
err = damon_sysfs_add_scheme_filters(scheme, sysfs_scheme->core_filters);
2751
if (err) {
2752
damon_destroy_scheme(scheme);
2753
return NULL;
2754
}
2755
err = damon_sysfs_add_scheme_filters(scheme, sysfs_scheme->ops_filters);
2756
if (err) {
2757
damon_destroy_scheme(scheme);
2758
return NULL;
2759
}
2760
err = damon_sysfs_add_scheme_filters(scheme, sysfs_scheme->filters);
2761
if (err) {
2762
damon_destroy_scheme(scheme);
2763
return NULL;
2764
}
2765
err = damos_sysfs_add_migrate_dest(scheme, sysfs_scheme->dests);
2766
if (err) {
2767
damon_destroy_scheme(scheme);
2768
return NULL;
2769
}
2770
scheme->max_nr_snapshots = sysfs_scheme->stats->max_nr_snapshots;
2771
return scheme;
2772
}
2773
2774
int damon_sysfs_add_schemes(struct damon_ctx *ctx,
2775
struct damon_sysfs_schemes *sysfs_schemes)
2776
{
2777
int i;
2778
2779
for (i = 0; i < sysfs_schemes->nr; i++) {
2780
struct damos *scheme, *next;
2781
2782
scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
2783
if (!scheme) {
2784
damon_for_each_scheme_safe(scheme, next, ctx)
2785
damon_destroy_scheme(scheme);
2786
return -ENOMEM;
2787
}
2788
damon_add_scheme(ctx, scheme);
2789
}
2790
return 0;
2791
}
2792
2793
void damon_sysfs_schemes_update_stats(
2794
struct damon_sysfs_schemes *sysfs_schemes,
2795
struct damon_ctx *ctx)
2796
{
2797
struct damos *scheme;
2798
int schemes_idx = 0;
2799
2800
damon_for_each_scheme(scheme, ctx) {
2801
struct damon_sysfs_stats *sysfs_stats;
2802
2803
/* user could have removed the scheme sysfs dir */
2804
if (schemes_idx >= sysfs_schemes->nr)
2805
break;
2806
2807
sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
2808
sysfs_stats->nr_tried = scheme->stat.nr_tried;
2809
sysfs_stats->sz_tried = scheme->stat.sz_tried;
2810
sysfs_stats->nr_applied = scheme->stat.nr_applied;
2811
sysfs_stats->sz_applied = scheme->stat.sz_applied;
2812
sysfs_stats->sz_ops_filter_passed =
2813
scheme->stat.sz_ops_filter_passed;
2814
sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
2815
sysfs_stats->nr_snapshots = scheme->stat.nr_snapshots;
2816
}
2817
}
2818
2819
/**
2820
* damos_sysfs_populate_region_dir() - Populate a schemes tried region dir.
2821
* @sysfs_schemes: Schemes directory to populate regions directory.
2822
* @ctx: Corresponding DAMON context.
2823
* @t: DAMON target of @r.
2824
* @r: DAMON region to populate the directory for.
2825
* @s: Corresponding scheme.
2826
* @total_bytes_only: Whether the request is for bytes update only.
2827
* @sz_filter_passed: Bytes of @r that passed filters of @s.
2828
*
2829
* Called from DAMOS walk callback while holding damon_sysfs_lock.
2830
*/
2831
void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes,
2832
struct damon_ctx *ctx, struct damon_target *t,
2833
struct damon_region *r, struct damos *s, bool total_bytes_only,
2834
unsigned long sz_filter_passed)
2835
{
2836
struct damos *scheme;
2837
struct damon_sysfs_scheme_regions *sysfs_regions;
2838
struct damon_sysfs_scheme_region *region;
2839
int schemes_idx = 0;
2840
2841
damon_for_each_scheme(scheme, ctx) {
2842
if (scheme == s)
2843
break;
2844
schemes_idx++;
2845
}
2846
2847
/* user could have removed the scheme sysfs dir */
2848
if (schemes_idx >= sysfs_schemes->nr)
2849
return;
2850
2851
sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
2852
sysfs_regions->total_bytes += r->ar.end - r->ar.start;
2853
if (total_bytes_only)
2854
return;
2855
2856
region = damon_sysfs_scheme_region_alloc(r);
2857
if (!region)
2858
return;
2859
region->sz_filter_passed = sz_filter_passed;
2860
list_add_tail(&region->list, &sysfs_regions->regions_list);
2861
sysfs_regions->nr_regions++;
2862
if (kobject_init_and_add(&region->kobj,
2863
&damon_sysfs_scheme_region_ktype,
2864
&sysfs_regions->kobj, "%d",
2865
sysfs_regions->nr_regions++)) {
2866
kobject_put(&region->kobj);
2867
}
2868
}
2869
2870
int damon_sysfs_schemes_clear_regions(
2871
struct damon_sysfs_schemes *sysfs_schemes)
2872
{
2873
int i;
2874
2875
for (i = 0; i < sysfs_schemes->nr; i++) {
2876
struct damon_sysfs_scheme *sysfs_scheme;
2877
2878
sysfs_scheme = sysfs_schemes->schemes_arr[i];
2879
damon_sysfs_scheme_regions_rm_dirs(
2880
sysfs_scheme->tried_regions);
2881
sysfs_scheme->tried_regions->total_bytes = 0;
2882
}
2883
return 0;
2884
}
2885
2886