@@ -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
120327struct 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+
130361static 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+
8601121static 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