Skip to content

Commit 2031b14

Browse files
sjp38torvalds
authored andcommitted
mm/damon/sysfs: support the physical address space monitoring
This commit makes DAMON sysfs interface supports the physical address space monitoring. Specifically, this commit adds support of the initial monitoring regions set feature by adding 'regions' directory under each target directory and makes context operations file to receive 'paddr' in addition to 'vaddr'. As a result, the files hierarchy becomes as below: /sys/kernel/mm/damon/admin │ kdamonds/nr_kdamonds │ │ 0/state,pid │ │ │ contexts/nr_contexts │ │ │ │ 0/operations │ │ │ │ │ monitoring_attrs/ │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us │ │ │ │ │ │ nr_regions/min,max │ │ │ │ │ targets/nr_targets │ │ │ │ │ │ 0/pid_target │ │ │ │ │ │ │ regions/nr_regions <- NEW DIRECTORY │ │ │ │ │ │ │ │ 0/start,end │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ ... │ │ │ │ ... │ │ ... Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: SeongJae Park <[email protected]> Cc: David Rientjes <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Xin Hao <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent a61ea56 commit 2031b14

File tree

1 file changed

+271
-5
lines changed

1 file changed

+271
-5
lines changed

mm/damon/sysfs.c

Lines changed: 271 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,220 @@ static struct kobj_type damon_sysfs_ul_range_ktype = {
113113
.default_groups = damon_sysfs_ul_range_groups,
114114
};
115115

116+
/*
117+
* init region directory
118+
*/
119+
120+
struct damon_sysfs_region {
121+
struct kobject kobj;
122+
unsigned long start;
123+
unsigned long end;
124+
};
125+
126+
static struct damon_sysfs_region *damon_sysfs_region_alloc(
127+
unsigned long start,
128+
unsigned long end)
129+
{
130+
struct damon_sysfs_region *region = kmalloc(sizeof(*region),
131+
GFP_KERNEL);
132+
133+
if (!region)
134+
return NULL;
135+
region->kobj = (struct kobject){};
136+
region->start = start;
137+
region->end = end;
138+
return region;
139+
}
140+
141+
static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
142+
char *buf)
143+
{
144+
struct damon_sysfs_region *region = container_of(kobj,
145+
struct damon_sysfs_region, kobj);
146+
147+
return sysfs_emit(buf, "%lu\n", region->start);
148+
}
149+
150+
static ssize_t start_store(struct kobject *kobj, struct kobj_attribute *attr,
151+
const char *buf, size_t count)
152+
{
153+
struct damon_sysfs_region *region = container_of(kobj,
154+
struct damon_sysfs_region, kobj);
155+
int err = kstrtoul(buf, 0, &region->start);
156+
157+
if (err)
158+
return -EINVAL;
159+
return count;
160+
}
161+
162+
static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
163+
char *buf)
164+
{
165+
struct damon_sysfs_region *region = container_of(kobj,
166+
struct damon_sysfs_region, kobj);
167+
168+
return sysfs_emit(buf, "%lu\n", region->end);
169+
}
170+
171+
static ssize_t end_store(struct kobject *kobj, struct kobj_attribute *attr,
172+
const char *buf, size_t count)
173+
{
174+
struct damon_sysfs_region *region = container_of(kobj,
175+
struct damon_sysfs_region, kobj);
176+
int err = kstrtoul(buf, 0, &region->end);
177+
178+
if (err)
179+
return -EINVAL;
180+
return count;
181+
}
182+
183+
static void damon_sysfs_region_release(struct kobject *kobj)
184+
{
185+
kfree(container_of(kobj, struct damon_sysfs_region, kobj));
186+
}
187+
188+
static struct kobj_attribute damon_sysfs_region_start_attr =
189+
__ATTR_RW_MODE(start, 0600);
190+
191+
static struct kobj_attribute damon_sysfs_region_end_attr =
192+
__ATTR_RW_MODE(end, 0600);
193+
194+
static struct attribute *damon_sysfs_region_attrs[] = {
195+
&damon_sysfs_region_start_attr.attr,
196+
&damon_sysfs_region_end_attr.attr,
197+
NULL,
198+
};
199+
ATTRIBUTE_GROUPS(damon_sysfs_region);
200+
201+
static struct kobj_type damon_sysfs_region_ktype = {
202+
.release = damon_sysfs_region_release,
203+
.sysfs_ops = &kobj_sysfs_ops,
204+
.default_groups = damon_sysfs_region_groups,
205+
};
206+
207+
/*
208+
* init_regions directory
209+
*/
210+
211+
struct damon_sysfs_regions {
212+
struct kobject kobj;
213+
struct damon_sysfs_region **regions_arr;
214+
int nr;
215+
};
216+
217+
static struct damon_sysfs_regions *damon_sysfs_regions_alloc(void)
218+
{
219+
return kzalloc(sizeof(struct damon_sysfs_regions), GFP_KERNEL);
220+
}
221+
222+
static void damon_sysfs_regions_rm_dirs(struct damon_sysfs_regions *regions)
223+
{
224+
struct damon_sysfs_region **regions_arr = regions->regions_arr;
225+
int i;
226+
227+
for (i = 0; i < regions->nr; i++)
228+
kobject_put(&regions_arr[i]->kobj);
229+
regions->nr = 0;
230+
kfree(regions_arr);
231+
regions->regions_arr = NULL;
232+
}
233+
234+
static int damon_sysfs_regions_add_dirs(struct damon_sysfs_regions *regions,
235+
int nr_regions)
236+
{
237+
struct damon_sysfs_region **regions_arr, *region;
238+
int err, i;
239+
240+
damon_sysfs_regions_rm_dirs(regions);
241+
if (!nr_regions)
242+
return 0;
243+
244+
regions_arr = kmalloc_array(nr_regions, sizeof(*regions_arr),
245+
GFP_KERNEL | __GFP_NOWARN);
246+
if (!regions_arr)
247+
return -ENOMEM;
248+
regions->regions_arr = regions_arr;
249+
250+
for (i = 0; i < nr_regions; i++) {
251+
region = damon_sysfs_region_alloc(0, 0);
252+
if (!region) {
253+
damon_sysfs_regions_rm_dirs(regions);
254+
return -ENOMEM;
255+
}
256+
257+
err = kobject_init_and_add(&region->kobj,
258+
&damon_sysfs_region_ktype, &regions->kobj,
259+
"%d", i);
260+
if (err) {
261+
kobject_put(&region->kobj);
262+
damon_sysfs_regions_rm_dirs(regions);
263+
return err;
264+
}
265+
266+
regions_arr[i] = region;
267+
regions->nr++;
268+
}
269+
return 0;
270+
}
271+
272+
static ssize_t nr_regions_show(struct kobject *kobj,
273+
struct kobj_attribute *attr, char *buf)
274+
{
275+
struct damon_sysfs_regions *regions = container_of(kobj,
276+
struct damon_sysfs_regions, kobj);
277+
278+
return sysfs_emit(buf, "%d\n", regions->nr);
279+
}
280+
281+
static ssize_t nr_regions_store(struct kobject *kobj,
282+
struct kobj_attribute *attr, const char *buf, size_t count)
283+
{
284+
struct damon_sysfs_regions *regions = container_of(kobj,
285+
struct damon_sysfs_regions, kobj);
286+
int nr, err = kstrtoint(buf, 0, &nr);
287+
288+
if (err)
289+
return err;
290+
if (nr < 0)
291+
return -EINVAL;
292+
293+
if (!mutex_trylock(&damon_sysfs_lock))
294+
return -EBUSY;
295+
err = damon_sysfs_regions_add_dirs(regions, nr);
296+
mutex_unlock(&damon_sysfs_lock);
297+
if (err)
298+
return err;
299+
300+
return count;
301+
}
302+
303+
static void damon_sysfs_regions_release(struct kobject *kobj)
304+
{
305+
kfree(container_of(kobj, struct damon_sysfs_regions, kobj));
306+
}
307+
308+
static struct kobj_attribute damon_sysfs_regions_nr_attr =
309+
__ATTR_RW_MODE(nr_regions, 0600);
310+
311+
static struct attribute *damon_sysfs_regions_attrs[] = {
312+
&damon_sysfs_regions_nr_attr.attr,
313+
NULL,
314+
};
315+
ATTRIBUTE_GROUPS(damon_sysfs_regions);
316+
317+
static struct kobj_type damon_sysfs_regions_ktype = {
318+
.release = damon_sysfs_regions_release,
319+
.sysfs_ops = &kobj_sysfs_ops,
320+
.default_groups = damon_sysfs_regions_groups,
321+
};
322+
116323
/*
117324
* target directory
118325
*/
119326

120327
struct damon_sysfs_target {
121328
struct kobject kobj;
329+
struct damon_sysfs_regions *regions;
122330
int pid;
123331
};
124332

@@ -127,6 +335,29 @@ static struct damon_sysfs_target *damon_sysfs_target_alloc(void)
127335
return kzalloc(sizeof(struct damon_sysfs_target), GFP_KERNEL);
128336
}
129337

338+
static int damon_sysfs_target_add_dirs(struct damon_sysfs_target *target)
339+
{
340+
struct damon_sysfs_regions *regions = damon_sysfs_regions_alloc();
341+
int err;
342+
343+
if (!regions)
344+
return -ENOMEM;
345+
346+
err = kobject_init_and_add(&regions->kobj, &damon_sysfs_regions_ktype,
347+
&target->kobj, "regions");
348+
if (err)
349+
kobject_put(&regions->kobj);
350+
else
351+
target->regions = regions;
352+
return err;
353+
}
354+
355+
static void damon_sysfs_target_rm_dirs(struct damon_sysfs_target *target)
356+
{
357+
damon_sysfs_regions_rm_dirs(target->regions);
358+
kobject_put(&target->regions->kobj);
359+
}
360+
130361
static ssize_t pid_target_show(struct kobject *kobj,
131362
struct kobj_attribute *attr, char *buf)
132363
{
@@ -188,8 +419,10 @@ static void damon_sysfs_targets_rm_dirs(struct damon_sysfs_targets *targets)
188419
struct damon_sysfs_target **targets_arr = targets->targets_arr;
189420
int i;
190421

191-
for (i = 0; i < targets->nr; i++)
422+
for (i = 0; i < targets->nr; i++) {
423+
damon_sysfs_target_rm_dirs(targets_arr[i]);
192424
kobject_put(&targets_arr[i]->kobj);
425+
}
193426
targets->nr = 0;
194427
kfree(targets_arr);
195428
targets->targets_arr = NULL;
@@ -224,6 +457,10 @@ static int damon_sysfs_targets_add_dirs(struct damon_sysfs_targets *targets,
224457
if (err)
225458
goto out;
226459

460+
err = damon_sysfs_target_add_dirs(target);
461+
if (err)
462+
goto out;
463+
227464
targets_arr[i] = target;
228465
targets->nr++;
229466
}
@@ -610,9 +847,6 @@ static ssize_t operations_store(struct kobject *kobj,
610847

611848
for (id = 0; id < NR_DAMON_OPS; id++) {
612849
if (sysfs_streq(buf, damon_sysfs_ops_strs[id])) {
613-
/* Support only vaddr */
614-
if (id != DAMON_OPS_VADDR)
615-
return -EINVAL;
616850
context->ops_id = id;
617851
return count;
618852
}
@@ -857,10 +1091,37 @@ static void damon_sysfs_destroy_targets(struct damon_ctx *ctx)
8571091
}
8581092
}
8591093

1094+
static int damon_sysfs_set_regions(struct damon_target *t,
1095+
struct damon_sysfs_regions *sysfs_regions)
1096+
{
1097+
int i;
1098+
1099+
for (i = 0; i < sysfs_regions->nr; i++) {
1100+
struct damon_sysfs_region *sys_region =
1101+
sysfs_regions->regions_arr[i];
1102+
struct damon_region *prev, *r;
1103+
1104+
if (sys_region->start > sys_region->end)
1105+
return -EINVAL;
1106+
r = damon_new_region(sys_region->start, sys_region->end);
1107+
if (!r)
1108+
return -ENOMEM;
1109+
damon_add_region(r, t);
1110+
if (damon_nr_regions(t) > 1) {
1111+
prev = damon_prev_region(r);
1112+
if (prev->ar.end > r->ar.start) {
1113+
damon_destroy_region(r, t);
1114+
return -EINVAL;
1115+
}
1116+
}
1117+
}
1118+
return 0;
1119+
}
1120+
8601121
static int damon_sysfs_set_targets(struct damon_ctx *ctx,
8611122
struct damon_sysfs_targets *sysfs_targets)
8621123
{
863-
int i;
1124+
int i, err;
8641125

8651126
for (i = 0; i < sysfs_targets->nr; i++) {
8661127
struct damon_sysfs_target *sys_target =
@@ -879,6 +1140,11 @@ static int damon_sysfs_set_targets(struct damon_ctx *ctx,
8791140
}
8801141
}
8811142
damon_add_target(ctx, t);
1143+
err = damon_sysfs_set_regions(t, sys_target->regions);
1144+
if (err) {
1145+
damon_sysfs_destroy_targets(ctx);
1146+
return err;
1147+
}
8821148
}
8831149
return 0;
8841150
}

0 commit comments

Comments
 (0)