Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/mm/damon/sysfs.c
29266 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/pid.h>
9
#include <linux/sched.h>
10
#include <linux/slab.h>
11
12
#include "sysfs-common.h"
13
14
/*
15
* init region directory
16
*/
17
18
struct damon_sysfs_region {
19
struct kobject kobj;
20
struct damon_addr_range ar;
21
};
22
23
static struct damon_sysfs_region *damon_sysfs_region_alloc(void)
24
{
25
return kzalloc(sizeof(struct damon_sysfs_region), GFP_KERNEL);
26
}
27
28
static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
29
char *buf)
30
{
31
struct damon_sysfs_region *region = container_of(kobj,
32
struct damon_sysfs_region, kobj);
33
34
return sysfs_emit(buf, "%lu\n", region->ar.start);
35
}
36
37
static ssize_t start_store(struct kobject *kobj, struct kobj_attribute *attr,
38
const char *buf, size_t count)
39
{
40
struct damon_sysfs_region *region = container_of(kobj,
41
struct damon_sysfs_region, kobj);
42
int err = kstrtoul(buf, 0, &region->ar.start);
43
44
return err ? err : count;
45
}
46
47
static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
48
char *buf)
49
{
50
struct damon_sysfs_region *region = container_of(kobj,
51
struct damon_sysfs_region, kobj);
52
53
return sysfs_emit(buf, "%lu\n", region->ar.end);
54
}
55
56
static ssize_t end_store(struct kobject *kobj, struct kobj_attribute *attr,
57
const char *buf, size_t count)
58
{
59
struct damon_sysfs_region *region = container_of(kobj,
60
struct damon_sysfs_region, kobj);
61
int err = kstrtoul(buf, 0, &region->ar.end);
62
63
return err ? err : count;
64
}
65
66
static void damon_sysfs_region_release(struct kobject *kobj)
67
{
68
kfree(container_of(kobj, struct damon_sysfs_region, kobj));
69
}
70
71
static struct kobj_attribute damon_sysfs_region_start_attr =
72
__ATTR_RW_MODE(start, 0600);
73
74
static struct kobj_attribute damon_sysfs_region_end_attr =
75
__ATTR_RW_MODE(end, 0600);
76
77
static struct attribute *damon_sysfs_region_attrs[] = {
78
&damon_sysfs_region_start_attr.attr,
79
&damon_sysfs_region_end_attr.attr,
80
NULL,
81
};
82
ATTRIBUTE_GROUPS(damon_sysfs_region);
83
84
static const struct kobj_type damon_sysfs_region_ktype = {
85
.release = damon_sysfs_region_release,
86
.sysfs_ops = &kobj_sysfs_ops,
87
.default_groups = damon_sysfs_region_groups,
88
};
89
90
/*
91
* init_regions directory
92
*/
93
94
struct damon_sysfs_regions {
95
struct kobject kobj;
96
struct damon_sysfs_region **regions_arr;
97
int nr;
98
};
99
100
static struct damon_sysfs_regions *damon_sysfs_regions_alloc(void)
101
{
102
return kzalloc(sizeof(struct damon_sysfs_regions), GFP_KERNEL);
103
}
104
105
static void damon_sysfs_regions_rm_dirs(struct damon_sysfs_regions *regions)
106
{
107
struct damon_sysfs_region **regions_arr = regions->regions_arr;
108
int i;
109
110
for (i = 0; i < regions->nr; i++)
111
kobject_put(&regions_arr[i]->kobj);
112
regions->nr = 0;
113
kfree(regions_arr);
114
regions->regions_arr = NULL;
115
}
116
117
static int damon_sysfs_regions_add_dirs(struct damon_sysfs_regions *regions,
118
int nr_regions)
119
{
120
struct damon_sysfs_region **regions_arr, *region;
121
int err, i;
122
123
damon_sysfs_regions_rm_dirs(regions);
124
if (!nr_regions)
125
return 0;
126
127
regions_arr = kmalloc_array(nr_regions, sizeof(*regions_arr),
128
GFP_KERNEL | __GFP_NOWARN);
129
if (!regions_arr)
130
return -ENOMEM;
131
regions->regions_arr = regions_arr;
132
133
for (i = 0; i < nr_regions; i++) {
134
region = damon_sysfs_region_alloc();
135
if (!region) {
136
damon_sysfs_regions_rm_dirs(regions);
137
return -ENOMEM;
138
}
139
140
err = kobject_init_and_add(&region->kobj,
141
&damon_sysfs_region_ktype, &regions->kobj,
142
"%d", i);
143
if (err) {
144
kobject_put(&region->kobj);
145
damon_sysfs_regions_rm_dirs(regions);
146
return err;
147
}
148
149
regions_arr[i] = region;
150
regions->nr++;
151
}
152
return 0;
153
}
154
155
static ssize_t nr_regions_show(struct kobject *kobj,
156
struct kobj_attribute *attr, char *buf)
157
{
158
struct damon_sysfs_regions *regions = container_of(kobj,
159
struct damon_sysfs_regions, kobj);
160
161
return sysfs_emit(buf, "%d\n", regions->nr);
162
}
163
164
static ssize_t nr_regions_store(struct kobject *kobj,
165
struct kobj_attribute *attr, const char *buf, size_t count)
166
{
167
struct damon_sysfs_regions *regions;
168
int nr, err = kstrtoint(buf, 0, &nr);
169
170
if (err)
171
return err;
172
if (nr < 0)
173
return -EINVAL;
174
175
regions = container_of(kobj, struct damon_sysfs_regions, kobj);
176
177
if (!mutex_trylock(&damon_sysfs_lock))
178
return -EBUSY;
179
err = damon_sysfs_regions_add_dirs(regions, nr);
180
mutex_unlock(&damon_sysfs_lock);
181
if (err)
182
return err;
183
184
return count;
185
}
186
187
static void damon_sysfs_regions_release(struct kobject *kobj)
188
{
189
kfree(container_of(kobj, struct damon_sysfs_regions, kobj));
190
}
191
192
static struct kobj_attribute damon_sysfs_regions_nr_attr =
193
__ATTR_RW_MODE(nr_regions, 0600);
194
195
static struct attribute *damon_sysfs_regions_attrs[] = {
196
&damon_sysfs_regions_nr_attr.attr,
197
NULL,
198
};
199
ATTRIBUTE_GROUPS(damon_sysfs_regions);
200
201
static const struct kobj_type damon_sysfs_regions_ktype = {
202
.release = damon_sysfs_regions_release,
203
.sysfs_ops = &kobj_sysfs_ops,
204
.default_groups = damon_sysfs_regions_groups,
205
};
206
207
/*
208
* target directory
209
*/
210
211
struct damon_sysfs_target {
212
struct kobject kobj;
213
struct damon_sysfs_regions *regions;
214
int pid;
215
};
216
217
static struct damon_sysfs_target *damon_sysfs_target_alloc(void)
218
{
219
return kzalloc(sizeof(struct damon_sysfs_target), GFP_KERNEL);
220
}
221
222
static int damon_sysfs_target_add_dirs(struct damon_sysfs_target *target)
223
{
224
struct damon_sysfs_regions *regions = damon_sysfs_regions_alloc();
225
int err;
226
227
if (!regions)
228
return -ENOMEM;
229
230
err = kobject_init_and_add(&regions->kobj, &damon_sysfs_regions_ktype,
231
&target->kobj, "regions");
232
if (err)
233
kobject_put(&regions->kobj);
234
else
235
target->regions = regions;
236
return err;
237
}
238
239
static void damon_sysfs_target_rm_dirs(struct damon_sysfs_target *target)
240
{
241
damon_sysfs_regions_rm_dirs(target->regions);
242
kobject_put(&target->regions->kobj);
243
}
244
245
static ssize_t pid_target_show(struct kobject *kobj,
246
struct kobj_attribute *attr, char *buf)
247
{
248
struct damon_sysfs_target *target = container_of(kobj,
249
struct damon_sysfs_target, kobj);
250
251
return sysfs_emit(buf, "%d\n", target->pid);
252
}
253
254
static ssize_t pid_target_store(struct kobject *kobj,
255
struct kobj_attribute *attr, const char *buf, size_t count)
256
{
257
struct damon_sysfs_target *target = container_of(kobj,
258
struct damon_sysfs_target, kobj);
259
int err = kstrtoint(buf, 0, &target->pid);
260
261
if (err)
262
return -EINVAL;
263
return count;
264
}
265
266
static void damon_sysfs_target_release(struct kobject *kobj)
267
{
268
kfree(container_of(kobj, struct damon_sysfs_target, kobj));
269
}
270
271
static struct kobj_attribute damon_sysfs_target_pid_attr =
272
__ATTR_RW_MODE(pid_target, 0600);
273
274
static struct attribute *damon_sysfs_target_attrs[] = {
275
&damon_sysfs_target_pid_attr.attr,
276
NULL,
277
};
278
ATTRIBUTE_GROUPS(damon_sysfs_target);
279
280
static const struct kobj_type damon_sysfs_target_ktype = {
281
.release = damon_sysfs_target_release,
282
.sysfs_ops = &kobj_sysfs_ops,
283
.default_groups = damon_sysfs_target_groups,
284
};
285
286
/*
287
* targets directory
288
*/
289
290
struct damon_sysfs_targets {
291
struct kobject kobj;
292
struct damon_sysfs_target **targets_arr;
293
int nr;
294
};
295
296
static struct damon_sysfs_targets *damon_sysfs_targets_alloc(void)
297
{
298
return kzalloc(sizeof(struct damon_sysfs_targets), GFP_KERNEL);
299
}
300
301
static void damon_sysfs_targets_rm_dirs(struct damon_sysfs_targets *targets)
302
{
303
struct damon_sysfs_target **targets_arr = targets->targets_arr;
304
int i;
305
306
for (i = 0; i < targets->nr; i++) {
307
damon_sysfs_target_rm_dirs(targets_arr[i]);
308
kobject_put(&targets_arr[i]->kobj);
309
}
310
targets->nr = 0;
311
kfree(targets_arr);
312
targets->targets_arr = NULL;
313
}
314
315
static int damon_sysfs_targets_add_dirs(struct damon_sysfs_targets *targets,
316
int nr_targets)
317
{
318
struct damon_sysfs_target **targets_arr, *target;
319
int err, i;
320
321
damon_sysfs_targets_rm_dirs(targets);
322
if (!nr_targets)
323
return 0;
324
325
targets_arr = kmalloc_array(nr_targets, sizeof(*targets_arr),
326
GFP_KERNEL | __GFP_NOWARN);
327
if (!targets_arr)
328
return -ENOMEM;
329
targets->targets_arr = targets_arr;
330
331
for (i = 0; i < nr_targets; i++) {
332
target = damon_sysfs_target_alloc();
333
if (!target) {
334
damon_sysfs_targets_rm_dirs(targets);
335
return -ENOMEM;
336
}
337
338
err = kobject_init_and_add(&target->kobj,
339
&damon_sysfs_target_ktype, &targets->kobj,
340
"%d", i);
341
if (err)
342
goto out;
343
344
err = damon_sysfs_target_add_dirs(target);
345
if (err)
346
goto out;
347
348
targets_arr[i] = target;
349
targets->nr++;
350
}
351
return 0;
352
353
out:
354
damon_sysfs_targets_rm_dirs(targets);
355
kobject_put(&target->kobj);
356
return err;
357
}
358
359
static ssize_t nr_targets_show(struct kobject *kobj,
360
struct kobj_attribute *attr, char *buf)
361
{
362
struct damon_sysfs_targets *targets = container_of(kobj,
363
struct damon_sysfs_targets, kobj);
364
365
return sysfs_emit(buf, "%d\n", targets->nr);
366
}
367
368
static ssize_t nr_targets_store(struct kobject *kobj,
369
struct kobj_attribute *attr, const char *buf, size_t count)
370
{
371
struct damon_sysfs_targets *targets;
372
int nr, err = kstrtoint(buf, 0, &nr);
373
374
if (err)
375
return err;
376
if (nr < 0)
377
return -EINVAL;
378
379
targets = container_of(kobj, struct damon_sysfs_targets, kobj);
380
381
if (!mutex_trylock(&damon_sysfs_lock))
382
return -EBUSY;
383
err = damon_sysfs_targets_add_dirs(targets, nr);
384
mutex_unlock(&damon_sysfs_lock);
385
if (err)
386
return err;
387
388
return count;
389
}
390
391
static void damon_sysfs_targets_release(struct kobject *kobj)
392
{
393
kfree(container_of(kobj, struct damon_sysfs_targets, kobj));
394
}
395
396
static struct kobj_attribute damon_sysfs_targets_nr_attr =
397
__ATTR_RW_MODE(nr_targets, 0600);
398
399
static struct attribute *damon_sysfs_targets_attrs[] = {
400
&damon_sysfs_targets_nr_attr.attr,
401
NULL,
402
};
403
ATTRIBUTE_GROUPS(damon_sysfs_targets);
404
405
static const struct kobj_type damon_sysfs_targets_ktype = {
406
.release = damon_sysfs_targets_release,
407
.sysfs_ops = &kobj_sysfs_ops,
408
.default_groups = damon_sysfs_targets_groups,
409
};
410
411
/*
412
* intervals goal directory
413
*/
414
415
struct damon_sysfs_intervals_goal {
416
struct kobject kobj;
417
unsigned long access_bp;
418
unsigned long aggrs;
419
unsigned long min_sample_us;
420
unsigned long max_sample_us;
421
};
422
423
static struct damon_sysfs_intervals_goal *damon_sysfs_intervals_goal_alloc(
424
unsigned long access_bp, unsigned long aggrs,
425
unsigned long min_sample_us, unsigned long max_sample_us)
426
{
427
struct damon_sysfs_intervals_goal *goal = kmalloc(sizeof(*goal),
428
GFP_KERNEL);
429
430
if (!goal)
431
return NULL;
432
433
goal->kobj = (struct kobject){};
434
goal->access_bp = access_bp;
435
goal->aggrs = aggrs;
436
goal->min_sample_us = min_sample_us;
437
goal->max_sample_us = max_sample_us;
438
return goal;
439
}
440
441
static ssize_t access_bp_show(struct kobject *kobj,
442
struct kobj_attribute *attr, char *buf)
443
{
444
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
445
struct damon_sysfs_intervals_goal, kobj);
446
447
return sysfs_emit(buf, "%lu\n", goal->access_bp);
448
}
449
450
static ssize_t access_bp_store(struct kobject *kobj,
451
struct kobj_attribute *attr, const char *buf, size_t count)
452
{
453
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
454
struct damon_sysfs_intervals_goal, kobj);
455
unsigned long nr;
456
int err = kstrtoul(buf, 0, &nr);
457
458
if (err)
459
return err;
460
461
goal->access_bp = nr;
462
return count;
463
}
464
465
static ssize_t aggrs_show(struct kobject *kobj,
466
struct kobj_attribute *attr, char *buf)
467
{
468
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
469
struct damon_sysfs_intervals_goal, kobj);
470
471
return sysfs_emit(buf, "%lu\n", goal->aggrs);
472
}
473
474
static ssize_t aggrs_store(struct kobject *kobj,
475
struct kobj_attribute *attr, const char *buf, size_t count)
476
{
477
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
478
struct damon_sysfs_intervals_goal, kobj);
479
unsigned long nr;
480
int err = kstrtoul(buf, 0, &nr);
481
482
if (err)
483
return err;
484
485
goal->aggrs = nr;
486
return count;
487
}
488
489
static ssize_t min_sample_us_show(struct kobject *kobj,
490
struct kobj_attribute *attr, char *buf)
491
{
492
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
493
struct damon_sysfs_intervals_goal, kobj);
494
495
return sysfs_emit(buf, "%lu\n", goal->min_sample_us);
496
}
497
498
static ssize_t min_sample_us_store(struct kobject *kobj,
499
struct kobj_attribute *attr, const char *buf, size_t count)
500
{
501
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
502
struct damon_sysfs_intervals_goal, kobj);
503
unsigned long nr;
504
int err = kstrtoul(buf, 0, &nr);
505
506
if (err)
507
return err;
508
509
goal->min_sample_us = nr;
510
return count;
511
}
512
513
static ssize_t max_sample_us_show(struct kobject *kobj,
514
struct kobj_attribute *attr, char *buf)
515
{
516
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
517
struct damon_sysfs_intervals_goal, kobj);
518
519
return sysfs_emit(buf, "%lu\n", goal->max_sample_us);
520
}
521
522
static ssize_t max_sample_us_store(struct kobject *kobj,
523
struct kobj_attribute *attr, const char *buf, size_t count)
524
{
525
struct damon_sysfs_intervals_goal *goal = container_of(kobj,
526
struct damon_sysfs_intervals_goal, kobj);
527
unsigned long nr;
528
int err = kstrtoul(buf, 0, &nr);
529
530
if (err)
531
return err;
532
533
goal->max_sample_us = nr;
534
return count;
535
}
536
537
static void damon_sysfs_intervals_goal_release(struct kobject *kobj)
538
{
539
kfree(container_of(kobj, struct damon_sysfs_intervals_goal, kobj));
540
}
541
542
static struct kobj_attribute damon_sysfs_intervals_goal_access_bp_attr =
543
__ATTR_RW_MODE(access_bp, 0600);
544
545
static struct kobj_attribute damon_sysfs_intervals_goal_aggrs_attr =
546
__ATTR_RW_MODE(aggrs, 0600);
547
548
static struct kobj_attribute damon_sysfs_intervals_goal_min_sample_us_attr =
549
__ATTR_RW_MODE(min_sample_us, 0600);
550
551
static struct kobj_attribute damon_sysfs_intervals_goal_max_sample_us_attr =
552
__ATTR_RW_MODE(max_sample_us, 0600);
553
554
static struct attribute *damon_sysfs_intervals_goal_attrs[] = {
555
&damon_sysfs_intervals_goal_access_bp_attr.attr,
556
&damon_sysfs_intervals_goal_aggrs_attr.attr,
557
&damon_sysfs_intervals_goal_min_sample_us_attr.attr,
558
&damon_sysfs_intervals_goal_max_sample_us_attr.attr,
559
NULL,
560
};
561
ATTRIBUTE_GROUPS(damon_sysfs_intervals_goal);
562
563
static const struct kobj_type damon_sysfs_intervals_goal_ktype = {
564
.release = damon_sysfs_intervals_goal_release,
565
.sysfs_ops = &kobj_sysfs_ops,
566
.default_groups = damon_sysfs_intervals_goal_groups,
567
};
568
569
/*
570
* intervals directory
571
*/
572
573
struct damon_sysfs_intervals {
574
struct kobject kobj;
575
unsigned long sample_us;
576
unsigned long aggr_us;
577
unsigned long update_us;
578
struct damon_sysfs_intervals_goal *intervals_goal;
579
};
580
581
static struct damon_sysfs_intervals *damon_sysfs_intervals_alloc(
582
unsigned long sample_us, unsigned long aggr_us,
583
unsigned long update_us)
584
{
585
struct damon_sysfs_intervals *intervals = kmalloc(sizeof(*intervals),
586
GFP_KERNEL);
587
588
if (!intervals)
589
return NULL;
590
591
intervals->kobj = (struct kobject){};
592
intervals->sample_us = sample_us;
593
intervals->aggr_us = aggr_us;
594
intervals->update_us = update_us;
595
return intervals;
596
}
597
598
static int damon_sysfs_intervals_add_dirs(struct damon_sysfs_intervals *intervals)
599
{
600
struct damon_sysfs_intervals_goal *goal;
601
int err;
602
603
goal = damon_sysfs_intervals_goal_alloc(0, 0, 0, 0);
604
if (!goal)
605
return -ENOMEM;
606
607
err = kobject_init_and_add(&goal->kobj,
608
&damon_sysfs_intervals_goal_ktype, &intervals->kobj,
609
"intervals_goal");
610
if (err) {
611
kobject_put(&goal->kobj);
612
intervals->intervals_goal = NULL;
613
return err;
614
}
615
intervals->intervals_goal = goal;
616
return 0;
617
}
618
619
static void damon_sysfs_intervals_rm_dirs(struct damon_sysfs_intervals *intervals)
620
{
621
kobject_put(&intervals->intervals_goal->kobj);
622
}
623
624
static ssize_t sample_us_show(struct kobject *kobj,
625
struct kobj_attribute *attr, char *buf)
626
{
627
struct damon_sysfs_intervals *intervals = container_of(kobj,
628
struct damon_sysfs_intervals, kobj);
629
630
return sysfs_emit(buf, "%lu\n", intervals->sample_us);
631
}
632
633
static ssize_t sample_us_store(struct kobject *kobj,
634
struct kobj_attribute *attr, const char *buf, size_t count)
635
{
636
struct damon_sysfs_intervals *intervals = container_of(kobj,
637
struct damon_sysfs_intervals, kobj);
638
unsigned long us;
639
int err = kstrtoul(buf, 0, &us);
640
641
if (err)
642
return err;
643
644
intervals->sample_us = us;
645
return count;
646
}
647
648
static ssize_t aggr_us_show(struct kobject *kobj, struct kobj_attribute *attr,
649
char *buf)
650
{
651
struct damon_sysfs_intervals *intervals = container_of(kobj,
652
struct damon_sysfs_intervals, kobj);
653
654
return sysfs_emit(buf, "%lu\n", intervals->aggr_us);
655
}
656
657
static ssize_t aggr_us_store(struct kobject *kobj, struct kobj_attribute *attr,
658
const char *buf, size_t count)
659
{
660
struct damon_sysfs_intervals *intervals = container_of(kobj,
661
struct damon_sysfs_intervals, kobj);
662
unsigned long us;
663
int err = kstrtoul(buf, 0, &us);
664
665
if (err)
666
return err;
667
668
intervals->aggr_us = us;
669
return count;
670
}
671
672
static ssize_t update_us_show(struct kobject *kobj,
673
struct kobj_attribute *attr, char *buf)
674
{
675
struct damon_sysfs_intervals *intervals = container_of(kobj,
676
struct damon_sysfs_intervals, kobj);
677
678
return sysfs_emit(buf, "%lu\n", intervals->update_us);
679
}
680
681
static ssize_t update_us_store(struct kobject *kobj,
682
struct kobj_attribute *attr, const char *buf, size_t count)
683
{
684
struct damon_sysfs_intervals *intervals = container_of(kobj,
685
struct damon_sysfs_intervals, kobj);
686
unsigned long us;
687
int err = kstrtoul(buf, 0, &us);
688
689
if (err)
690
return err;
691
692
intervals->update_us = us;
693
return count;
694
}
695
696
static void damon_sysfs_intervals_release(struct kobject *kobj)
697
{
698
kfree(container_of(kobj, struct damon_sysfs_intervals, kobj));
699
}
700
701
static struct kobj_attribute damon_sysfs_intervals_sample_us_attr =
702
__ATTR_RW_MODE(sample_us, 0600);
703
704
static struct kobj_attribute damon_sysfs_intervals_aggr_us_attr =
705
__ATTR_RW_MODE(aggr_us, 0600);
706
707
static struct kobj_attribute damon_sysfs_intervals_update_us_attr =
708
__ATTR_RW_MODE(update_us, 0600);
709
710
static struct attribute *damon_sysfs_intervals_attrs[] = {
711
&damon_sysfs_intervals_sample_us_attr.attr,
712
&damon_sysfs_intervals_aggr_us_attr.attr,
713
&damon_sysfs_intervals_update_us_attr.attr,
714
NULL,
715
};
716
ATTRIBUTE_GROUPS(damon_sysfs_intervals);
717
718
static const struct kobj_type damon_sysfs_intervals_ktype = {
719
.release = damon_sysfs_intervals_release,
720
.sysfs_ops = &kobj_sysfs_ops,
721
.default_groups = damon_sysfs_intervals_groups,
722
};
723
724
/*
725
* monitoring_attrs directory
726
*/
727
728
struct damon_sysfs_attrs {
729
struct kobject kobj;
730
struct damon_sysfs_intervals *intervals;
731
struct damon_sysfs_ul_range *nr_regions_range;
732
};
733
734
static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
735
{
736
struct damon_sysfs_attrs *attrs = kmalloc(sizeof(*attrs), GFP_KERNEL);
737
738
if (!attrs)
739
return NULL;
740
attrs->kobj = (struct kobject){};
741
return attrs;
742
}
743
744
static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
745
{
746
struct damon_sysfs_intervals *intervals;
747
struct damon_sysfs_ul_range *nr_regions_range;
748
int err;
749
750
intervals = damon_sysfs_intervals_alloc(5000, 100000, 60000000);
751
if (!intervals)
752
return -ENOMEM;
753
754
err = kobject_init_and_add(&intervals->kobj,
755
&damon_sysfs_intervals_ktype, &attrs->kobj,
756
"intervals");
757
if (err)
758
goto put_intervals_out;
759
err = damon_sysfs_intervals_add_dirs(intervals);
760
if (err)
761
goto put_intervals_out;
762
attrs->intervals = intervals;
763
764
nr_regions_range = damon_sysfs_ul_range_alloc(10, 1000);
765
if (!nr_regions_range) {
766
err = -ENOMEM;
767
goto put_intervals_out;
768
}
769
770
err = kobject_init_and_add(&nr_regions_range->kobj,
771
&damon_sysfs_ul_range_ktype, &attrs->kobj,
772
"nr_regions");
773
if (err)
774
goto put_nr_regions_intervals_out;
775
attrs->nr_regions_range = nr_regions_range;
776
return 0;
777
778
put_nr_regions_intervals_out:
779
kobject_put(&nr_regions_range->kobj);
780
attrs->nr_regions_range = NULL;
781
put_intervals_out:
782
kobject_put(&intervals->kobj);
783
attrs->intervals = NULL;
784
return err;
785
}
786
787
static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
788
{
789
kobject_put(&attrs->nr_regions_range->kobj);
790
damon_sysfs_intervals_rm_dirs(attrs->intervals);
791
kobject_put(&attrs->intervals->kobj);
792
}
793
794
static void damon_sysfs_attrs_release(struct kobject *kobj)
795
{
796
kfree(container_of(kobj, struct damon_sysfs_attrs, kobj));
797
}
798
799
static struct attribute *damon_sysfs_attrs_attrs[] = {
800
NULL,
801
};
802
ATTRIBUTE_GROUPS(damon_sysfs_attrs);
803
804
static const struct kobj_type damon_sysfs_attrs_ktype = {
805
.release = damon_sysfs_attrs_release,
806
.sysfs_ops = &kobj_sysfs_ops,
807
.default_groups = damon_sysfs_attrs_groups,
808
};
809
810
/*
811
* context directory
812
*/
813
814
struct damon_sysfs_ops_name {
815
enum damon_ops_id ops_id;
816
char *name;
817
};
818
819
static const struct damon_sysfs_ops_name damon_sysfs_ops_names[] = {
820
{
821
.ops_id = DAMON_OPS_VADDR,
822
.name = "vaddr",
823
},
824
{
825
.ops_id = DAMON_OPS_FVADDR,
826
.name = "fvaddr",
827
},
828
{
829
.ops_id = DAMON_OPS_PADDR,
830
.name = "paddr",
831
},
832
};
833
834
struct damon_sysfs_context {
835
struct kobject kobj;
836
enum damon_ops_id ops_id;
837
unsigned long addr_unit;
838
struct damon_sysfs_attrs *attrs;
839
struct damon_sysfs_targets *targets;
840
struct damon_sysfs_schemes *schemes;
841
};
842
843
static struct damon_sysfs_context *damon_sysfs_context_alloc(
844
enum damon_ops_id ops_id)
845
{
846
struct damon_sysfs_context *context = kmalloc(sizeof(*context),
847
GFP_KERNEL);
848
849
if (!context)
850
return NULL;
851
context->kobj = (struct kobject){};
852
context->ops_id = ops_id;
853
context->addr_unit = 1;
854
return context;
855
}
856
857
static int damon_sysfs_context_set_attrs(struct damon_sysfs_context *context)
858
{
859
struct damon_sysfs_attrs *attrs = damon_sysfs_attrs_alloc();
860
int err;
861
862
if (!attrs)
863
return -ENOMEM;
864
err = kobject_init_and_add(&attrs->kobj, &damon_sysfs_attrs_ktype,
865
&context->kobj, "monitoring_attrs");
866
if (err)
867
goto out;
868
err = damon_sysfs_attrs_add_dirs(attrs);
869
if (err)
870
goto out;
871
context->attrs = attrs;
872
return 0;
873
874
out:
875
kobject_put(&attrs->kobj);
876
return err;
877
}
878
879
static int damon_sysfs_context_set_targets(struct damon_sysfs_context *context)
880
{
881
struct damon_sysfs_targets *targets = damon_sysfs_targets_alloc();
882
int err;
883
884
if (!targets)
885
return -ENOMEM;
886
err = kobject_init_and_add(&targets->kobj, &damon_sysfs_targets_ktype,
887
&context->kobj, "targets");
888
if (err) {
889
kobject_put(&targets->kobj);
890
return err;
891
}
892
context->targets = targets;
893
return 0;
894
}
895
896
static int damon_sysfs_context_set_schemes(struct damon_sysfs_context *context)
897
{
898
struct damon_sysfs_schemes *schemes = damon_sysfs_schemes_alloc();
899
int err;
900
901
if (!schemes)
902
return -ENOMEM;
903
err = kobject_init_and_add(&schemes->kobj, &damon_sysfs_schemes_ktype,
904
&context->kobj, "schemes");
905
if (err) {
906
kobject_put(&schemes->kobj);
907
return err;
908
}
909
context->schemes = schemes;
910
return 0;
911
}
912
913
static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
914
{
915
int err;
916
917
err = damon_sysfs_context_set_attrs(context);
918
if (err)
919
return err;
920
921
err = damon_sysfs_context_set_targets(context);
922
if (err)
923
goto put_attrs_out;
924
925
err = damon_sysfs_context_set_schemes(context);
926
if (err)
927
goto put_targets_attrs_out;
928
return 0;
929
930
put_targets_attrs_out:
931
kobject_put(&context->targets->kobj);
932
context->targets = NULL;
933
put_attrs_out:
934
kobject_put(&context->attrs->kobj);
935
context->attrs = NULL;
936
return err;
937
}
938
939
static void damon_sysfs_context_rm_dirs(struct damon_sysfs_context *context)
940
{
941
damon_sysfs_attrs_rm_dirs(context->attrs);
942
kobject_put(&context->attrs->kobj);
943
damon_sysfs_targets_rm_dirs(context->targets);
944
kobject_put(&context->targets->kobj);
945
damon_sysfs_schemes_rm_dirs(context->schemes);
946
kobject_put(&context->schemes->kobj);
947
}
948
949
static ssize_t avail_operations_show(struct kobject *kobj,
950
struct kobj_attribute *attr, char *buf)
951
{
952
int len = 0;
953
int i;
954
955
for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
956
const struct damon_sysfs_ops_name *ops_name;
957
958
ops_name = &damon_sysfs_ops_names[i];
959
if (!damon_is_registered_ops(ops_name->ops_id))
960
continue;
961
len += sysfs_emit_at(buf, len, "%s\n", ops_name->name);
962
}
963
return len;
964
}
965
966
static ssize_t operations_show(struct kobject *kobj,
967
struct kobj_attribute *attr, char *buf)
968
{
969
struct damon_sysfs_context *context = container_of(kobj,
970
struct damon_sysfs_context, kobj);
971
int i;
972
973
for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
974
const struct damon_sysfs_ops_name *ops_name;
975
976
ops_name = &damon_sysfs_ops_names[i];
977
if (ops_name->ops_id == context->ops_id)
978
return sysfs_emit(buf, "%s\n", ops_name->name);
979
}
980
return -EINVAL;
981
}
982
983
static ssize_t operations_store(struct kobject *kobj,
984
struct kobj_attribute *attr, const char *buf, size_t count)
985
{
986
struct damon_sysfs_context *context = container_of(kobj,
987
struct damon_sysfs_context, kobj);
988
int i;
989
990
for (i = 0; i < ARRAY_SIZE(damon_sysfs_ops_names); i++) {
991
const struct damon_sysfs_ops_name *ops_name;
992
993
ops_name = &damon_sysfs_ops_names[i];
994
if (sysfs_streq(buf, ops_name->name)) {
995
context->ops_id = ops_name->ops_id;
996
return count;
997
}
998
}
999
return -EINVAL;
1000
}
1001
1002
static ssize_t addr_unit_show(struct kobject *kobj,
1003
struct kobj_attribute *attr, char *buf)
1004
{
1005
struct damon_sysfs_context *context = container_of(kobj,
1006
struct damon_sysfs_context, kobj);
1007
1008
return sysfs_emit(buf, "%lu\n", context->addr_unit);
1009
}
1010
1011
static ssize_t addr_unit_store(struct kobject *kobj,
1012
struct kobj_attribute *attr, const char *buf, size_t count)
1013
{
1014
struct damon_sysfs_context *context = container_of(kobj,
1015
struct damon_sysfs_context, kobj);
1016
unsigned long input_addr_unit;
1017
int err = kstrtoul(buf, 0, &input_addr_unit);
1018
1019
if (err)
1020
return err;
1021
if (!input_addr_unit)
1022
return -EINVAL;
1023
1024
context->addr_unit = input_addr_unit;
1025
return count;
1026
}
1027
1028
static void damon_sysfs_context_release(struct kobject *kobj)
1029
{
1030
kfree(container_of(kobj, struct damon_sysfs_context, kobj));
1031
}
1032
1033
static struct kobj_attribute damon_sysfs_context_avail_operations_attr =
1034
__ATTR_RO_MODE(avail_operations, 0400);
1035
1036
static struct kobj_attribute damon_sysfs_context_operations_attr =
1037
__ATTR_RW_MODE(operations, 0600);
1038
1039
static struct kobj_attribute damon_sysfs_context_addr_unit_attr =
1040
__ATTR_RW_MODE(addr_unit, 0600);
1041
1042
static struct attribute *damon_sysfs_context_attrs[] = {
1043
&damon_sysfs_context_avail_operations_attr.attr,
1044
&damon_sysfs_context_operations_attr.attr,
1045
&damon_sysfs_context_addr_unit_attr.attr,
1046
NULL,
1047
};
1048
ATTRIBUTE_GROUPS(damon_sysfs_context);
1049
1050
static const struct kobj_type damon_sysfs_context_ktype = {
1051
.release = damon_sysfs_context_release,
1052
.sysfs_ops = &kobj_sysfs_ops,
1053
.default_groups = damon_sysfs_context_groups,
1054
};
1055
1056
/*
1057
* contexts directory
1058
*/
1059
1060
struct damon_sysfs_contexts {
1061
struct kobject kobj;
1062
struct damon_sysfs_context **contexts_arr;
1063
int nr;
1064
};
1065
1066
static struct damon_sysfs_contexts *damon_sysfs_contexts_alloc(void)
1067
{
1068
return kzalloc(sizeof(struct damon_sysfs_contexts), GFP_KERNEL);
1069
}
1070
1071
static void damon_sysfs_contexts_rm_dirs(struct damon_sysfs_contexts *contexts)
1072
{
1073
struct damon_sysfs_context **contexts_arr = contexts->contexts_arr;
1074
int i;
1075
1076
for (i = 0; i < contexts->nr; i++) {
1077
damon_sysfs_context_rm_dirs(contexts_arr[i]);
1078
kobject_put(&contexts_arr[i]->kobj);
1079
}
1080
contexts->nr = 0;
1081
kfree(contexts_arr);
1082
contexts->contexts_arr = NULL;
1083
}
1084
1085
static int damon_sysfs_contexts_add_dirs(struct damon_sysfs_contexts *contexts,
1086
int nr_contexts)
1087
{
1088
struct damon_sysfs_context **contexts_arr, *context;
1089
int err, i;
1090
1091
damon_sysfs_contexts_rm_dirs(contexts);
1092
if (!nr_contexts)
1093
return 0;
1094
1095
contexts_arr = kmalloc_array(nr_contexts, sizeof(*contexts_arr),
1096
GFP_KERNEL | __GFP_NOWARN);
1097
if (!contexts_arr)
1098
return -ENOMEM;
1099
contexts->contexts_arr = contexts_arr;
1100
1101
for (i = 0; i < nr_contexts; i++) {
1102
context = damon_sysfs_context_alloc(DAMON_OPS_VADDR);
1103
if (!context) {
1104
damon_sysfs_contexts_rm_dirs(contexts);
1105
return -ENOMEM;
1106
}
1107
1108
err = kobject_init_and_add(&context->kobj,
1109
&damon_sysfs_context_ktype, &contexts->kobj,
1110
"%d", i);
1111
if (err)
1112
goto out;
1113
1114
err = damon_sysfs_context_add_dirs(context);
1115
if (err)
1116
goto out;
1117
1118
contexts_arr[i] = context;
1119
contexts->nr++;
1120
}
1121
return 0;
1122
1123
out:
1124
damon_sysfs_contexts_rm_dirs(contexts);
1125
kobject_put(&context->kobj);
1126
return err;
1127
}
1128
1129
static ssize_t nr_contexts_show(struct kobject *kobj,
1130
struct kobj_attribute *attr, char *buf)
1131
{
1132
struct damon_sysfs_contexts *contexts = container_of(kobj,
1133
struct damon_sysfs_contexts, kobj);
1134
1135
return sysfs_emit(buf, "%d\n", contexts->nr);
1136
}
1137
1138
static ssize_t nr_contexts_store(struct kobject *kobj,
1139
struct kobj_attribute *attr, const char *buf, size_t count)
1140
{
1141
struct damon_sysfs_contexts *contexts;
1142
int nr, err;
1143
1144
err = kstrtoint(buf, 0, &nr);
1145
if (err)
1146
return err;
1147
/* TODO: support multiple contexts per kdamond */
1148
if (nr < 0 || 1 < nr)
1149
return -EINVAL;
1150
1151
contexts = container_of(kobj, struct damon_sysfs_contexts, kobj);
1152
if (!mutex_trylock(&damon_sysfs_lock))
1153
return -EBUSY;
1154
err = damon_sysfs_contexts_add_dirs(contexts, nr);
1155
mutex_unlock(&damon_sysfs_lock);
1156
if (err)
1157
return err;
1158
1159
return count;
1160
}
1161
1162
static void damon_sysfs_contexts_release(struct kobject *kobj)
1163
{
1164
kfree(container_of(kobj, struct damon_sysfs_contexts, kobj));
1165
}
1166
1167
static struct kobj_attribute damon_sysfs_contexts_nr_attr
1168
= __ATTR_RW_MODE(nr_contexts, 0600);
1169
1170
static struct attribute *damon_sysfs_contexts_attrs[] = {
1171
&damon_sysfs_contexts_nr_attr.attr,
1172
NULL,
1173
};
1174
ATTRIBUTE_GROUPS(damon_sysfs_contexts);
1175
1176
static const struct kobj_type damon_sysfs_contexts_ktype = {
1177
.release = damon_sysfs_contexts_release,
1178
.sysfs_ops = &kobj_sysfs_ops,
1179
.default_groups = damon_sysfs_contexts_groups,
1180
};
1181
1182
/*
1183
* kdamond directory
1184
*/
1185
1186
struct damon_sysfs_kdamond {
1187
struct kobject kobj;
1188
struct damon_sysfs_contexts *contexts;
1189
struct damon_ctx *damon_ctx;
1190
unsigned int refresh_ms;
1191
};
1192
1193
static struct damon_sysfs_kdamond *damon_sysfs_kdamond_alloc(void)
1194
{
1195
return kzalloc(sizeof(struct damon_sysfs_kdamond), GFP_KERNEL);
1196
}
1197
1198
static int damon_sysfs_kdamond_add_dirs(struct damon_sysfs_kdamond *kdamond)
1199
{
1200
struct damon_sysfs_contexts *contexts;
1201
int err;
1202
1203
contexts = damon_sysfs_contexts_alloc();
1204
if (!contexts)
1205
return -ENOMEM;
1206
1207
err = kobject_init_and_add(&contexts->kobj,
1208
&damon_sysfs_contexts_ktype, &kdamond->kobj,
1209
"contexts");
1210
if (err) {
1211
kobject_put(&contexts->kobj);
1212
return err;
1213
}
1214
kdamond->contexts = contexts;
1215
1216
return err;
1217
}
1218
1219
static void damon_sysfs_kdamond_rm_dirs(struct damon_sysfs_kdamond *kdamond)
1220
{
1221
damon_sysfs_contexts_rm_dirs(kdamond->contexts);
1222
kobject_put(&kdamond->contexts->kobj);
1223
}
1224
1225
/*
1226
* enum damon_sysfs_cmd - Commands for a specific kdamond.
1227
*/
1228
enum damon_sysfs_cmd {
1229
/* @DAMON_SYSFS_CMD_ON: Turn the kdamond on. */
1230
DAMON_SYSFS_CMD_ON,
1231
/* @DAMON_SYSFS_CMD_OFF: Turn the kdamond off. */
1232
DAMON_SYSFS_CMD_OFF,
1233
/* @DAMON_SYSFS_CMD_COMMIT: Update kdamond inputs. */
1234
DAMON_SYSFS_CMD_COMMIT,
1235
/*
1236
* @DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS: Commit the quota goals
1237
* to DAMON.
1238
*/
1239
DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS,
1240
/*
1241
* @DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS: Update scheme stats sysfs
1242
* files.
1243
*/
1244
DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS,
1245
/*
1246
* @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES: Update
1247
* tried_regions/total_bytes sysfs files for each scheme.
1248
*/
1249
DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES,
1250
/*
1251
* @DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS: Update schemes tried
1252
* regions
1253
*/
1254
DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS,
1255
/*
1256
* @DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS: Clear schemes tried
1257
* regions
1258
*/
1259
DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS,
1260
/*
1261
* @DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS: Update the
1262
* effective size quota of the scheme in bytes.
1263
*/
1264
DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS,
1265
/*
1266
* @DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS: Update the tuned monitoring
1267
* intevals.
1268
*/
1269
DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS,
1270
/*
1271
* @NR_DAMON_SYSFS_CMDS: Total number of DAMON sysfs commands.
1272
*/
1273
NR_DAMON_SYSFS_CMDS,
1274
};
1275
1276
/* Should match with enum damon_sysfs_cmd */
1277
static const char * const damon_sysfs_cmd_strs[] = {
1278
"on",
1279
"off",
1280
"commit",
1281
"commit_schemes_quota_goals",
1282
"update_schemes_stats",
1283
"update_schemes_tried_bytes",
1284
"update_schemes_tried_regions",
1285
"clear_schemes_tried_regions",
1286
"update_schemes_effective_quotas",
1287
"update_tuned_intervals",
1288
};
1289
1290
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
1291
char *buf)
1292
{
1293
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1294
struct damon_sysfs_kdamond, kobj);
1295
struct damon_ctx *ctx;
1296
bool running = false;
1297
1298
if (!mutex_trylock(&damon_sysfs_lock))
1299
return -EBUSY;
1300
1301
ctx = kdamond->damon_ctx;
1302
if (ctx)
1303
running = damon_is_running(ctx);
1304
1305
mutex_unlock(&damon_sysfs_lock);
1306
1307
return sysfs_emit(buf, "%s\n", running ?
1308
damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_ON] :
1309
damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_OFF]);
1310
}
1311
1312
static int damon_sysfs_set_attrs(struct damon_ctx *ctx,
1313
struct damon_sysfs_attrs *sys_attrs)
1314
{
1315
struct damon_sysfs_intervals *sys_intervals = sys_attrs->intervals;
1316
struct damon_sysfs_intervals_goal *sys_goal =
1317
sys_intervals->intervals_goal;
1318
struct damon_sysfs_ul_range *sys_nr_regions =
1319
sys_attrs->nr_regions_range;
1320
struct damon_attrs attrs = {
1321
.sample_interval = sys_intervals->sample_us,
1322
.aggr_interval = sys_intervals->aggr_us,
1323
.intervals_goal = {
1324
.access_bp = sys_goal->access_bp,
1325
.aggrs = sys_goal->aggrs,
1326
.min_sample_us = sys_goal->min_sample_us,
1327
.max_sample_us = sys_goal->max_sample_us},
1328
.ops_update_interval = sys_intervals->update_us,
1329
.min_nr_regions = sys_nr_regions->min,
1330
.max_nr_regions = sys_nr_regions->max,
1331
};
1332
return damon_set_attrs(ctx, &attrs);
1333
}
1334
1335
static int damon_sysfs_set_regions(struct damon_target *t,
1336
struct damon_sysfs_regions *sysfs_regions,
1337
unsigned long min_sz_region)
1338
{
1339
struct damon_addr_range *ranges = kmalloc_array(sysfs_regions->nr,
1340
sizeof(*ranges), GFP_KERNEL | __GFP_NOWARN);
1341
int i, err = -EINVAL;
1342
1343
if (!ranges)
1344
return -ENOMEM;
1345
for (i = 0; i < sysfs_regions->nr; i++) {
1346
struct damon_sysfs_region *sys_region =
1347
sysfs_regions->regions_arr[i];
1348
1349
if (sys_region->ar.start > sys_region->ar.end)
1350
goto out;
1351
1352
ranges[i].start = sys_region->ar.start;
1353
ranges[i].end = sys_region->ar.end;
1354
if (i == 0)
1355
continue;
1356
if (ranges[i - 1].end > ranges[i].start)
1357
goto out;
1358
}
1359
err = damon_set_regions(t, ranges, sysfs_regions->nr, min_sz_region);
1360
out:
1361
kfree(ranges);
1362
return err;
1363
1364
}
1365
1366
static int damon_sysfs_add_target(struct damon_sysfs_target *sys_target,
1367
struct damon_ctx *ctx)
1368
{
1369
struct damon_target *t = damon_new_target();
1370
1371
if (!t)
1372
return -ENOMEM;
1373
damon_add_target(ctx, t);
1374
if (damon_target_has_pid(ctx)) {
1375
t->pid = find_get_pid(sys_target->pid);
1376
if (!t->pid)
1377
/* caller will destroy targets */
1378
return -EINVAL;
1379
}
1380
return damon_sysfs_set_regions(t, sys_target->regions, ctx->min_sz_region);
1381
}
1382
1383
static int damon_sysfs_add_targets(struct damon_ctx *ctx,
1384
struct damon_sysfs_targets *sysfs_targets)
1385
{
1386
int i, err;
1387
1388
/* Multiple physical address space monitoring targets makes no sense */
1389
if (ctx->ops.id == DAMON_OPS_PADDR && sysfs_targets->nr > 1)
1390
return -EINVAL;
1391
1392
for (i = 0; i < sysfs_targets->nr; i++) {
1393
struct damon_sysfs_target *st = sysfs_targets->targets_arr[i];
1394
1395
err = damon_sysfs_add_target(st, ctx);
1396
if (err)
1397
return err;
1398
}
1399
return 0;
1400
}
1401
1402
/*
1403
* damon_sysfs_upd_schemes_stats() - Update schemes stats sysfs files.
1404
* @data: The kobject wrapper that associated to the kdamond thread.
1405
*
1406
* This function reads the schemes stats of specific kdamond and update the
1407
* related values for sysfs files. This function should be called from DAMON
1408
* worker thread,to safely access the DAMON contexts-internal data. Caller
1409
* should also ensure holding ``damon_syfs_lock``, and ->damon_ctx of @data is
1410
* not NULL but a valid pointer, to safely access DAMON sysfs variables.
1411
*/
1412
static int damon_sysfs_upd_schemes_stats(void *data)
1413
{
1414
struct damon_sysfs_kdamond *kdamond = data;
1415
struct damon_ctx *ctx = kdamond->damon_ctx;
1416
1417
damon_sysfs_schemes_update_stats(
1418
kdamond->contexts->contexts_arr[0]->schemes, ctx);
1419
return 0;
1420
}
1421
1422
static inline bool damon_sysfs_kdamond_running(
1423
struct damon_sysfs_kdamond *kdamond)
1424
{
1425
return kdamond->damon_ctx &&
1426
damon_is_running(kdamond->damon_ctx);
1427
}
1428
1429
static int damon_sysfs_apply_inputs(struct damon_ctx *ctx,
1430
struct damon_sysfs_context *sys_ctx)
1431
{
1432
int err;
1433
1434
err = damon_select_ops(ctx, sys_ctx->ops_id);
1435
if (err)
1436
return err;
1437
ctx->addr_unit = sys_ctx->addr_unit;
1438
/* addr_unit is respected by only DAMON_OPS_PADDR */
1439
if (sys_ctx->ops_id == DAMON_OPS_PADDR)
1440
ctx->min_sz_region = max(
1441
DAMON_MIN_REGION / sys_ctx->addr_unit, 1);
1442
err = damon_sysfs_set_attrs(ctx, sys_ctx->attrs);
1443
if (err)
1444
return err;
1445
err = damon_sysfs_add_targets(ctx, sys_ctx->targets);
1446
if (err)
1447
return err;
1448
return damon_sysfs_add_schemes(ctx, sys_ctx->schemes);
1449
}
1450
1451
static struct damon_ctx *damon_sysfs_build_ctx(
1452
struct damon_sysfs_context *sys_ctx);
1453
1454
/*
1455
* damon_sysfs_commit_input() - Commit user inputs to a running kdamond.
1456
* @kdamond: The kobject wrapper for the associated kdamond.
1457
*
1458
* Returns error if the sysfs input is wrong.
1459
*/
1460
static int damon_sysfs_commit_input(void *data)
1461
{
1462
struct damon_sysfs_kdamond *kdamond = data;
1463
struct damon_ctx *param_ctx, *test_ctx;
1464
int err;
1465
1466
if (!damon_sysfs_kdamond_running(kdamond))
1467
return -EINVAL;
1468
/* TODO: Support multiple contexts per kdamond */
1469
if (kdamond->contexts->nr != 1)
1470
return -EINVAL;
1471
1472
param_ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
1473
if (IS_ERR(param_ctx))
1474
return PTR_ERR(param_ctx);
1475
test_ctx = damon_new_ctx();
1476
err = damon_commit_ctx(test_ctx, param_ctx);
1477
if (err) {
1478
damon_destroy_ctx(test_ctx);
1479
goto out;
1480
}
1481
err = damon_commit_ctx(kdamond->damon_ctx, param_ctx);
1482
out:
1483
damon_destroy_ctx(param_ctx);
1484
return err;
1485
}
1486
1487
static int damon_sysfs_commit_schemes_quota_goals(void *data)
1488
{
1489
struct damon_sysfs_kdamond *sysfs_kdamond = data;
1490
struct damon_ctx *ctx;
1491
struct damon_sysfs_context *sysfs_ctx;
1492
1493
if (!damon_sysfs_kdamond_running(sysfs_kdamond))
1494
return -EINVAL;
1495
/* TODO: Support multiple contexts per kdamond */
1496
if (sysfs_kdamond->contexts->nr != 1)
1497
return -EINVAL;
1498
1499
ctx = sysfs_kdamond->damon_ctx;
1500
sysfs_ctx = sysfs_kdamond->contexts->contexts_arr[0];
1501
return damos_sysfs_set_quota_scores(sysfs_ctx->schemes, ctx);
1502
}
1503
1504
/*
1505
* damon_sysfs_upd_schemes_effective_quotas() - Update schemes effective quotas
1506
* sysfs files.
1507
* @data: The kobject wrapper that associated to the kdamond thread.
1508
*
1509
* This function reads the schemes' effective quotas of specific kdamond and
1510
* update the related values for sysfs files. This function should be called
1511
* from DAMON callbacks while holding ``damon_syfs_lock``, to safely access the
1512
* DAMON contexts-internal data and DAMON sysfs variables.
1513
*/
1514
static int damon_sysfs_upd_schemes_effective_quotas(void *data)
1515
{
1516
struct damon_sysfs_kdamond *kdamond = data;
1517
struct damon_ctx *ctx = kdamond->damon_ctx;
1518
1519
damos_sysfs_update_effective_quotas(
1520
kdamond->contexts->contexts_arr[0]->schemes, ctx);
1521
return 0;
1522
}
1523
1524
static int damon_sysfs_upd_tuned_intervals(void *data)
1525
{
1526
struct damon_sysfs_kdamond *kdamond = data;
1527
struct damon_ctx *ctx = kdamond->damon_ctx;
1528
1529
kdamond->contexts->contexts_arr[0]->attrs->intervals->sample_us =
1530
ctx->attrs.sample_interval;
1531
kdamond->contexts->contexts_arr[0]->attrs->intervals->aggr_us =
1532
ctx->attrs.aggr_interval;
1533
return 0;
1534
}
1535
1536
static struct damon_ctx *damon_sysfs_build_ctx(
1537
struct damon_sysfs_context *sys_ctx)
1538
{
1539
struct damon_ctx *ctx = damon_new_ctx();
1540
int err;
1541
1542
if (!ctx)
1543
return ERR_PTR(-ENOMEM);
1544
1545
err = damon_sysfs_apply_inputs(ctx, sys_ctx);
1546
if (err) {
1547
damon_destroy_ctx(ctx);
1548
return ERR_PTR(err);
1549
}
1550
1551
return ctx;
1552
}
1553
1554
static int damon_sysfs_repeat_call_fn(void *data)
1555
{
1556
struct damon_sysfs_kdamond *sysfs_kdamond = data;
1557
static unsigned long next_update_jiffies;
1558
1559
if (!sysfs_kdamond->refresh_ms)
1560
return 0;
1561
if (time_before(jiffies, next_update_jiffies))
1562
return 0;
1563
next_update_jiffies = jiffies +
1564
msecs_to_jiffies(sysfs_kdamond->refresh_ms);
1565
1566
if (!mutex_trylock(&damon_sysfs_lock))
1567
return 0;
1568
damon_sysfs_upd_tuned_intervals(sysfs_kdamond);
1569
damon_sysfs_upd_schemes_stats(sysfs_kdamond);
1570
damon_sysfs_upd_schemes_effective_quotas(sysfs_kdamond);
1571
mutex_unlock(&damon_sysfs_lock);
1572
return 0;
1573
}
1574
1575
static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
1576
{
1577
struct damon_ctx *ctx;
1578
struct damon_call_control *repeat_call_control;
1579
int err;
1580
1581
if (damon_sysfs_kdamond_running(kdamond))
1582
return -EBUSY;
1583
/* TODO: support multiple contexts per kdamond */
1584
if (kdamond->contexts->nr != 1)
1585
return -EINVAL;
1586
1587
if (kdamond->damon_ctx)
1588
damon_destroy_ctx(kdamond->damon_ctx);
1589
kdamond->damon_ctx = NULL;
1590
1591
repeat_call_control = kmalloc(sizeof(*repeat_call_control),
1592
GFP_KERNEL);
1593
if (!repeat_call_control)
1594
return -ENOMEM;
1595
1596
ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
1597
if (IS_ERR(ctx)) {
1598
kfree(repeat_call_control);
1599
return PTR_ERR(ctx);
1600
}
1601
err = damon_start(&ctx, 1, false);
1602
if (err) {
1603
kfree(repeat_call_control);
1604
damon_destroy_ctx(ctx);
1605
return err;
1606
}
1607
kdamond->damon_ctx = ctx;
1608
1609
repeat_call_control->fn = damon_sysfs_repeat_call_fn;
1610
repeat_call_control->data = kdamond;
1611
repeat_call_control->repeat = true;
1612
repeat_call_control->dealloc_on_cancel = true;
1613
damon_call(ctx, repeat_call_control);
1614
return err;
1615
}
1616
1617
static int damon_sysfs_turn_damon_off(struct damon_sysfs_kdamond *kdamond)
1618
{
1619
if (!kdamond->damon_ctx)
1620
return -EINVAL;
1621
return damon_stop(&kdamond->damon_ctx, 1);
1622
/*
1623
* To allow users show final monitoring results of already turned-off
1624
* DAMON, we free kdamond->damon_ctx in next
1625
* damon_sysfs_turn_damon_on(), or kdamonds_nr_store()
1626
*/
1627
}
1628
1629
static int damon_sysfs_damon_call(int (*fn)(void *data),
1630
struct damon_sysfs_kdamond *kdamond)
1631
{
1632
struct damon_call_control call_control = {};
1633
int err;
1634
1635
if (!kdamond->damon_ctx)
1636
return -EINVAL;
1637
call_control.fn = fn;
1638
call_control.data = kdamond;
1639
err = damon_call(kdamond->damon_ctx, &call_control);
1640
return err ? err : call_control.return_code;
1641
}
1642
1643
struct damon_sysfs_schemes_walk_data {
1644
struct damon_sysfs_kdamond *sysfs_kdamond;
1645
bool total_bytes_only;
1646
};
1647
1648
/* populate the region directory */
1649
static void damon_sysfs_schemes_tried_regions_upd_one(void *data, struct damon_ctx *ctx,
1650
struct damon_target *t, struct damon_region *r,
1651
struct damos *s, unsigned long sz_filter_passed)
1652
{
1653
struct damon_sysfs_schemes_walk_data *walk_data = data;
1654
struct damon_sysfs_kdamond *sysfs_kdamond = walk_data->sysfs_kdamond;
1655
1656
damos_sysfs_populate_region_dir(
1657
sysfs_kdamond->contexts->contexts_arr[0]->schemes,
1658
ctx, t, r, s, walk_data->total_bytes_only,
1659
sz_filter_passed);
1660
}
1661
1662
static int damon_sysfs_update_schemes_tried_regions(
1663
struct damon_sysfs_kdamond *sysfs_kdamond, bool total_bytes_only)
1664
{
1665
struct damon_sysfs_schemes_walk_data walk_data = {
1666
.sysfs_kdamond = sysfs_kdamond,
1667
.total_bytes_only = total_bytes_only,
1668
};
1669
struct damos_walk_control control = {
1670
.walk_fn = damon_sysfs_schemes_tried_regions_upd_one,
1671
.data = &walk_data,
1672
};
1673
struct damon_ctx *ctx = sysfs_kdamond->damon_ctx;
1674
1675
if (!ctx)
1676
return -EINVAL;
1677
1678
damon_sysfs_schemes_clear_regions(
1679
sysfs_kdamond->contexts->contexts_arr[0]->schemes);
1680
return damos_walk(ctx, &control);
1681
}
1682
1683
/*
1684
* damon_sysfs_handle_cmd() - Handle a command for a specific kdamond.
1685
* @cmd: The command to handle.
1686
* @kdamond: The kobject wrapper for the associated kdamond.
1687
*
1688
* This function handles a DAMON sysfs command for a kdamond.
1689
*
1690
* Return: 0 on success, negative error code otherwise.
1691
*/
1692
static int damon_sysfs_handle_cmd(enum damon_sysfs_cmd cmd,
1693
struct damon_sysfs_kdamond *kdamond)
1694
{
1695
switch (cmd) {
1696
case DAMON_SYSFS_CMD_ON:
1697
return damon_sysfs_turn_damon_on(kdamond);
1698
case DAMON_SYSFS_CMD_OFF:
1699
return damon_sysfs_turn_damon_off(kdamond);
1700
case DAMON_SYSFS_CMD_COMMIT:
1701
return damon_sysfs_damon_call(
1702
damon_sysfs_commit_input, kdamond);
1703
case DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS:
1704
return damon_sysfs_damon_call(
1705
damon_sysfs_commit_schemes_quota_goals,
1706
kdamond);
1707
case DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS:
1708
return damon_sysfs_damon_call(
1709
damon_sysfs_upd_schemes_stats, kdamond);
1710
case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES:
1711
return damon_sysfs_update_schemes_tried_regions(kdamond, true);
1712
case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_REGIONS:
1713
return damon_sysfs_update_schemes_tried_regions(kdamond, false);
1714
case DAMON_SYSFS_CMD_CLEAR_SCHEMES_TRIED_REGIONS:
1715
return damon_sysfs_schemes_clear_regions(
1716
kdamond->contexts->contexts_arr[0]->schemes);
1717
case DAMON_SYSFS_CMD_UPDATE_SCHEMES_EFFECTIVE_QUOTAS:
1718
return damon_sysfs_damon_call(
1719
damon_sysfs_upd_schemes_effective_quotas,
1720
kdamond);
1721
case DAMON_SYSFS_CMD_UPDATE_TUNED_INTERVALS:
1722
return damon_sysfs_damon_call(
1723
damon_sysfs_upd_tuned_intervals, kdamond);
1724
default:
1725
return -EINVAL;
1726
}
1727
}
1728
1729
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
1730
const char *buf, size_t count)
1731
{
1732
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1733
struct damon_sysfs_kdamond, kobj);
1734
enum damon_sysfs_cmd cmd;
1735
ssize_t ret = -EINVAL;
1736
1737
if (!mutex_trylock(&damon_sysfs_lock))
1738
return -EBUSY;
1739
for (cmd = 0; cmd < NR_DAMON_SYSFS_CMDS; cmd++) {
1740
if (sysfs_streq(buf, damon_sysfs_cmd_strs[cmd])) {
1741
ret = damon_sysfs_handle_cmd(cmd, kdamond);
1742
break;
1743
}
1744
}
1745
mutex_unlock(&damon_sysfs_lock);
1746
if (!ret)
1747
ret = count;
1748
return ret;
1749
}
1750
1751
static ssize_t pid_show(struct kobject *kobj,
1752
struct kobj_attribute *attr, char *buf)
1753
{
1754
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1755
struct damon_sysfs_kdamond, kobj);
1756
struct damon_ctx *ctx;
1757
int pid = -1;
1758
1759
if (!mutex_trylock(&damon_sysfs_lock))
1760
return -EBUSY;
1761
ctx = kdamond->damon_ctx;
1762
if (!ctx)
1763
goto out;
1764
1765
mutex_lock(&ctx->kdamond_lock);
1766
if (ctx->kdamond)
1767
pid = ctx->kdamond->pid;
1768
mutex_unlock(&ctx->kdamond_lock);
1769
out:
1770
mutex_unlock(&damon_sysfs_lock);
1771
return sysfs_emit(buf, "%d\n", pid);
1772
}
1773
1774
static ssize_t refresh_ms_show(struct kobject *kobj,
1775
struct kobj_attribute *attr, char *buf)
1776
{
1777
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1778
struct damon_sysfs_kdamond, kobj);
1779
1780
return sysfs_emit(buf, "%u\n", kdamond->refresh_ms);
1781
}
1782
1783
static ssize_t refresh_ms_store(struct kobject *kobj,
1784
struct kobj_attribute *attr, const char *buf, size_t count)
1785
{
1786
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1787
struct damon_sysfs_kdamond, kobj);
1788
unsigned int nr;
1789
int err = kstrtouint(buf, 0, &nr);
1790
1791
if (err)
1792
return err;
1793
1794
kdamond->refresh_ms = nr;
1795
return count;
1796
}
1797
1798
static void damon_sysfs_kdamond_release(struct kobject *kobj)
1799
{
1800
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
1801
struct damon_sysfs_kdamond, kobj);
1802
1803
if (kdamond->damon_ctx)
1804
damon_destroy_ctx(kdamond->damon_ctx);
1805
kfree(kdamond);
1806
}
1807
1808
static struct kobj_attribute damon_sysfs_kdamond_state_attr =
1809
__ATTR_RW_MODE(state, 0600);
1810
1811
static struct kobj_attribute damon_sysfs_kdamond_pid_attr =
1812
__ATTR_RO_MODE(pid, 0400);
1813
1814
static struct kobj_attribute damon_sysfs_kdamond_refresh_ms_attr =
1815
__ATTR_RW_MODE(refresh_ms, 0600);
1816
1817
static struct attribute *damon_sysfs_kdamond_attrs[] = {
1818
&damon_sysfs_kdamond_state_attr.attr,
1819
&damon_sysfs_kdamond_pid_attr.attr,
1820
&damon_sysfs_kdamond_refresh_ms_attr.attr,
1821
NULL,
1822
};
1823
ATTRIBUTE_GROUPS(damon_sysfs_kdamond);
1824
1825
static const struct kobj_type damon_sysfs_kdamond_ktype = {
1826
.release = damon_sysfs_kdamond_release,
1827
.sysfs_ops = &kobj_sysfs_ops,
1828
.default_groups = damon_sysfs_kdamond_groups,
1829
};
1830
1831
/*
1832
* kdamonds directory
1833
*/
1834
1835
struct damon_sysfs_kdamonds {
1836
struct kobject kobj;
1837
struct damon_sysfs_kdamond **kdamonds_arr;
1838
int nr;
1839
};
1840
1841
static struct damon_sysfs_kdamonds *damon_sysfs_kdamonds_alloc(void)
1842
{
1843
return kzalloc(sizeof(struct damon_sysfs_kdamonds), GFP_KERNEL);
1844
}
1845
1846
static void damon_sysfs_kdamonds_rm_dirs(struct damon_sysfs_kdamonds *kdamonds)
1847
{
1848
struct damon_sysfs_kdamond **kdamonds_arr = kdamonds->kdamonds_arr;
1849
int i;
1850
1851
for (i = 0; i < kdamonds->nr; i++) {
1852
damon_sysfs_kdamond_rm_dirs(kdamonds_arr[i]);
1853
kobject_put(&kdamonds_arr[i]->kobj);
1854
}
1855
kdamonds->nr = 0;
1856
kfree(kdamonds_arr);
1857
kdamonds->kdamonds_arr = NULL;
1858
}
1859
1860
static bool damon_sysfs_kdamonds_busy(struct damon_sysfs_kdamond **kdamonds,
1861
int nr_kdamonds)
1862
{
1863
int i;
1864
1865
for (i = 0; i < nr_kdamonds; i++) {
1866
if (damon_sysfs_kdamond_running(kdamonds[i]))
1867
return true;
1868
}
1869
1870
return false;
1871
}
1872
1873
static int damon_sysfs_kdamonds_add_dirs(struct damon_sysfs_kdamonds *kdamonds,
1874
int nr_kdamonds)
1875
{
1876
struct damon_sysfs_kdamond **kdamonds_arr, *kdamond;
1877
int err, i;
1878
1879
if (damon_sysfs_kdamonds_busy(kdamonds->kdamonds_arr, kdamonds->nr))
1880
return -EBUSY;
1881
1882
damon_sysfs_kdamonds_rm_dirs(kdamonds);
1883
if (!nr_kdamonds)
1884
return 0;
1885
1886
kdamonds_arr = kmalloc_array(nr_kdamonds, sizeof(*kdamonds_arr),
1887
GFP_KERNEL | __GFP_NOWARN);
1888
if (!kdamonds_arr)
1889
return -ENOMEM;
1890
kdamonds->kdamonds_arr = kdamonds_arr;
1891
1892
for (i = 0; i < nr_kdamonds; i++) {
1893
kdamond = damon_sysfs_kdamond_alloc();
1894
if (!kdamond) {
1895
damon_sysfs_kdamonds_rm_dirs(kdamonds);
1896
return -ENOMEM;
1897
}
1898
1899
err = kobject_init_and_add(&kdamond->kobj,
1900
&damon_sysfs_kdamond_ktype, &kdamonds->kobj,
1901
"%d", i);
1902
if (err)
1903
goto out;
1904
1905
err = damon_sysfs_kdamond_add_dirs(kdamond);
1906
if (err)
1907
goto out;
1908
1909
kdamonds_arr[i] = kdamond;
1910
kdamonds->nr++;
1911
}
1912
return 0;
1913
1914
out:
1915
damon_sysfs_kdamonds_rm_dirs(kdamonds);
1916
kobject_put(&kdamond->kobj);
1917
return err;
1918
}
1919
1920
static ssize_t nr_kdamonds_show(struct kobject *kobj,
1921
struct kobj_attribute *attr, char *buf)
1922
{
1923
struct damon_sysfs_kdamonds *kdamonds = container_of(kobj,
1924
struct damon_sysfs_kdamonds, kobj);
1925
1926
return sysfs_emit(buf, "%d\n", kdamonds->nr);
1927
}
1928
1929
static ssize_t nr_kdamonds_store(struct kobject *kobj,
1930
struct kobj_attribute *attr, const char *buf, size_t count)
1931
{
1932
struct damon_sysfs_kdamonds *kdamonds;
1933
int nr, err;
1934
1935
err = kstrtoint(buf, 0, &nr);
1936
if (err)
1937
return err;
1938
if (nr < 0)
1939
return -EINVAL;
1940
1941
kdamonds = container_of(kobj, struct damon_sysfs_kdamonds, kobj);
1942
1943
if (!mutex_trylock(&damon_sysfs_lock))
1944
return -EBUSY;
1945
err = damon_sysfs_kdamonds_add_dirs(kdamonds, nr);
1946
mutex_unlock(&damon_sysfs_lock);
1947
if (err)
1948
return err;
1949
1950
return count;
1951
}
1952
1953
static void damon_sysfs_kdamonds_release(struct kobject *kobj)
1954
{
1955
kfree(container_of(kobj, struct damon_sysfs_kdamonds, kobj));
1956
}
1957
1958
static struct kobj_attribute damon_sysfs_kdamonds_nr_attr =
1959
__ATTR_RW_MODE(nr_kdamonds, 0600);
1960
1961
static struct attribute *damon_sysfs_kdamonds_attrs[] = {
1962
&damon_sysfs_kdamonds_nr_attr.attr,
1963
NULL,
1964
};
1965
ATTRIBUTE_GROUPS(damon_sysfs_kdamonds);
1966
1967
static const struct kobj_type damon_sysfs_kdamonds_ktype = {
1968
.release = damon_sysfs_kdamonds_release,
1969
.sysfs_ops = &kobj_sysfs_ops,
1970
.default_groups = damon_sysfs_kdamonds_groups,
1971
};
1972
1973
/*
1974
* damon user interface directory
1975
*/
1976
1977
struct damon_sysfs_ui_dir {
1978
struct kobject kobj;
1979
struct damon_sysfs_kdamonds *kdamonds;
1980
};
1981
1982
static struct damon_sysfs_ui_dir *damon_sysfs_ui_dir_alloc(void)
1983
{
1984
return kzalloc(sizeof(struct damon_sysfs_ui_dir), GFP_KERNEL);
1985
}
1986
1987
static int damon_sysfs_ui_dir_add_dirs(struct damon_sysfs_ui_dir *ui_dir)
1988
{
1989
struct damon_sysfs_kdamonds *kdamonds;
1990
int err;
1991
1992
kdamonds = damon_sysfs_kdamonds_alloc();
1993
if (!kdamonds)
1994
return -ENOMEM;
1995
1996
err = kobject_init_and_add(&kdamonds->kobj,
1997
&damon_sysfs_kdamonds_ktype, &ui_dir->kobj,
1998
"kdamonds");
1999
if (err) {
2000
kobject_put(&kdamonds->kobj);
2001
return err;
2002
}
2003
ui_dir->kdamonds = kdamonds;
2004
return err;
2005
}
2006
2007
static void damon_sysfs_ui_dir_release(struct kobject *kobj)
2008
{
2009
kfree(container_of(kobj, struct damon_sysfs_ui_dir, kobj));
2010
}
2011
2012
static struct attribute *damon_sysfs_ui_dir_attrs[] = {
2013
NULL,
2014
};
2015
ATTRIBUTE_GROUPS(damon_sysfs_ui_dir);
2016
2017
static const struct kobj_type damon_sysfs_ui_dir_ktype = {
2018
.release = damon_sysfs_ui_dir_release,
2019
.sysfs_ops = &kobj_sysfs_ops,
2020
.default_groups = damon_sysfs_ui_dir_groups,
2021
};
2022
2023
static int __init damon_sysfs_init(void)
2024
{
2025
struct kobject *damon_sysfs_root;
2026
struct damon_sysfs_ui_dir *admin;
2027
int err;
2028
2029
damon_sysfs_root = kobject_create_and_add("damon", mm_kobj);
2030
if (!damon_sysfs_root)
2031
return -ENOMEM;
2032
2033
admin = damon_sysfs_ui_dir_alloc();
2034
if (!admin) {
2035
kobject_put(damon_sysfs_root);
2036
return -ENOMEM;
2037
}
2038
err = kobject_init_and_add(&admin->kobj, &damon_sysfs_ui_dir_ktype,
2039
damon_sysfs_root, "admin");
2040
if (err)
2041
goto out;
2042
err = damon_sysfs_ui_dir_add_dirs(admin);
2043
if (err)
2044
goto out;
2045
return 0;
2046
2047
out:
2048
kobject_put(&admin->kobj);
2049
kobject_put(damon_sysfs_root);
2050
return err;
2051
}
2052
subsys_initcall(damon_sysfs_init);
2053
2054
#include "tests/sysfs-kunit.h"
2055
2056