~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/mm/damon/dbgfs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * DAMON Debugfs Interface
  4  *
  5  * Author: SeongJae Park <sj@kernel.org>
  6  */
  7 
  8 #define pr_fmt(fmt) "damon-dbgfs: " fmt
  9 
 10 #include <linux/damon.h>
 11 #include <linux/debugfs.h>
 12 #include <linux/file.h>
 13 #include <linux/mm.h>
 14 #include <linux/module.h>
 15 #include <linux/page_idle.h>
 16 #include <linux/slab.h>
 17 
 18 #define DAMON_DBGFS_DEPRECATION_NOTICE                                  \
 19         "DAMON debugfs interface is deprecated, so users should move "  \
 20         "to DAMON_SYSFS. If you cannot, please report your usecase to " \
 21         "damon@lists.linux.dev and linux-mm@kvack.org.\n"
 22 
 23 static struct damon_ctx **dbgfs_ctxs;
 24 static int dbgfs_nr_ctxs;
 25 static struct dentry **dbgfs_dirs;
 26 static DEFINE_MUTEX(damon_dbgfs_lock);
 27 
 28 static void damon_dbgfs_warn_deprecation(void)
 29 {
 30         pr_warn_once(DAMON_DBGFS_DEPRECATION_NOTICE);
 31 }
 32 
 33 /*
 34  * Returns non-empty string on success, negative error code otherwise.
 35  */
 36 static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos)
 37 {
 38         char *kbuf;
 39         ssize_t ret;
 40 
 41         /* We do not accept continuous write */
 42         if (*ppos)
 43                 return ERR_PTR(-EINVAL);
 44 
 45         kbuf = kmalloc(count + 1, GFP_KERNEL | __GFP_NOWARN);
 46         if (!kbuf)
 47                 return ERR_PTR(-ENOMEM);
 48 
 49         ret = simple_write_to_buffer(kbuf, count + 1, ppos, buf, count);
 50         if (ret != count) {
 51                 kfree(kbuf);
 52                 return ERR_PTR(-EIO);
 53         }
 54         kbuf[ret] = '\0';
 55 
 56         return kbuf;
 57 }
 58 
 59 static ssize_t dbgfs_attrs_read(struct file *file,
 60                 char __user *buf, size_t count, loff_t *ppos)
 61 {
 62         struct damon_ctx *ctx = file->private_data;
 63         char kbuf[128];
 64         int ret;
 65 
 66         mutex_lock(&ctx->kdamond_lock);
 67         ret = scnprintf(kbuf, ARRAY_SIZE(kbuf), "%lu %lu %lu %lu %lu\n",
 68                         ctx->attrs.sample_interval, ctx->attrs.aggr_interval,
 69                         ctx->attrs.ops_update_interval,
 70                         ctx->attrs.min_nr_regions, ctx->attrs.max_nr_regions);
 71         mutex_unlock(&ctx->kdamond_lock);
 72 
 73         return simple_read_from_buffer(buf, count, ppos, kbuf, ret);
 74 }
 75 
 76 static ssize_t dbgfs_attrs_write(struct file *file,
 77                 const char __user *buf, size_t count, loff_t *ppos)
 78 {
 79         struct damon_ctx *ctx = file->private_data;
 80         struct damon_attrs attrs;
 81         char *kbuf;
 82         ssize_t ret;
 83 
 84         kbuf = user_input_str(buf, count, ppos);
 85         if (IS_ERR(kbuf))
 86                 return PTR_ERR(kbuf);
 87 
 88         if (sscanf(kbuf, "%lu %lu %lu %lu %lu",
 89                                 &attrs.sample_interval, &attrs.aggr_interval,
 90                                 &attrs.ops_update_interval,
 91                                 &attrs.min_nr_regions,
 92                                 &attrs.max_nr_regions) != 5) {
 93                 ret = -EINVAL;
 94                 goto out;
 95         }
 96 
 97         mutex_lock(&ctx->kdamond_lock);
 98         if (ctx->kdamond) {
 99                 ret = -EBUSY;
100                 goto unlock_out;
101         }
102 
103         ret = damon_set_attrs(ctx, &attrs);
104         if (!ret)
105                 ret = count;
106 unlock_out:
107         mutex_unlock(&ctx->kdamond_lock);
108 out:
109         kfree(kbuf);
110         return ret;
111 }
112 
113 /*
114  * Return corresponding dbgfs' scheme action value (int) for the given
115  * damos_action if the given damos_action value is valid and supported by
116  * dbgfs, negative error code otherwise.
117  */
118 static int damos_action_to_dbgfs_scheme_action(enum damos_action action)
119 {
120         switch (action) {
121         case DAMOS_WILLNEED:
122                 return 0;
123         case DAMOS_COLD:
124                 return 1;
125         case DAMOS_PAGEOUT:
126                 return 2;
127         case DAMOS_HUGEPAGE:
128                 return 3;
129         case DAMOS_NOHUGEPAGE:
130                 return 4;
131         case DAMOS_STAT:
132                 return 5;
133         default:
134                 return -EINVAL;
135         }
136 }
137 
138 static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len)
139 {
140         struct damos *s;
141         int written = 0;
142         int rc;
143 
144         damon_for_each_scheme(s, c) {
145                 rc = scnprintf(&buf[written], len - written,
146                                 "%lu %lu %u %u %u %u %d %lu %lu %lu %u %u %u %d %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
147                                 s->pattern.min_sz_region,
148                                 s->pattern.max_sz_region,
149                                 s->pattern.min_nr_accesses,
150                                 s->pattern.max_nr_accesses,
151                                 s->pattern.min_age_region,
152                                 s->pattern.max_age_region,
153                                 damos_action_to_dbgfs_scheme_action(s->action),
154                                 s->quota.ms, s->quota.sz,
155                                 s->quota.reset_interval,
156                                 s->quota.weight_sz,
157                                 s->quota.weight_nr_accesses,
158                                 s->quota.weight_age,
159                                 s->wmarks.metric, s->wmarks.interval,
160                                 s->wmarks.high, s->wmarks.mid, s->wmarks.low,
161                                 s->stat.nr_tried, s->stat.sz_tried,
162                                 s->stat.nr_applied, s->stat.sz_applied,
163                                 s->stat.qt_exceeds);
164                 if (!rc)
165                         return -ENOMEM;
166 
167                 written += rc;
168         }
169         return written;
170 }
171 
172 static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf,
173                 size_t count, loff_t *ppos)
174 {
175         struct damon_ctx *ctx = file->private_data;
176         char *kbuf;
177         ssize_t len;
178 
179         kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
180         if (!kbuf)
181                 return -ENOMEM;
182 
183         mutex_lock(&ctx->kdamond_lock);
184         len = sprint_schemes(ctx, kbuf, count);
185         mutex_unlock(&ctx->kdamond_lock);
186         if (len < 0)
187                 goto out;
188         len = simple_read_from_buffer(buf, count, ppos, kbuf, len);
189 
190 out:
191         kfree(kbuf);
192         return len;
193 }
194 
195 static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes)
196 {
197         ssize_t i;
198 
199         for (i = 0; i < nr_schemes; i++)
200                 kfree(schemes[i]);
201         kfree(schemes);
202 }
203 
204 /*
205  * Return corresponding damos_action for the given dbgfs input for a scheme
206  * action if the input is valid, negative error code otherwise.
207  */
208 static enum damos_action dbgfs_scheme_action_to_damos_action(int dbgfs_action)
209 {
210         switch (dbgfs_action) {
211         case 0:
212                 return DAMOS_WILLNEED;
213         case 1:
214                 return DAMOS_COLD;
215         case 2:
216                 return DAMOS_PAGEOUT;
217         case 3:
218                 return DAMOS_HUGEPAGE;
219         case 4:
220                 return DAMOS_NOHUGEPAGE;
221         case 5:
222                 return DAMOS_STAT;
223         default:
224                 return -EINVAL;
225         }
226 }
227 
228 /*
229  * Converts a string into an array of struct damos pointers
230  *
231  * Returns an array of struct damos pointers that converted if the conversion
232  * success, or NULL otherwise.
233  */
234 static struct damos **str_to_schemes(const char *str, ssize_t len,
235                                 ssize_t *nr_schemes)
236 {
237         struct damos *scheme, **schemes;
238         const int max_nr_schemes = 256;
239         int pos = 0, parsed, ret;
240         unsigned int action_input;
241         enum damos_action action;
242 
243         schemes = kmalloc_array(max_nr_schemes, sizeof(scheme),
244                         GFP_KERNEL);
245         if (!schemes)
246                 return NULL;
247 
248         *nr_schemes = 0;
249         while (pos < len && *nr_schemes < max_nr_schemes) {
250                 struct damos_access_pattern pattern = {};
251                 struct damos_quota quota = {};
252                 struct damos_watermarks wmarks;
253 
254                 ret = sscanf(&str[pos],
255                                 "%lu %lu %u %u %u %u %u %lu %lu %lu %u %u %u %u %lu %lu %lu %lu%n",
256                                 &pattern.min_sz_region, &pattern.max_sz_region,
257                                 &pattern.min_nr_accesses,
258                                 &pattern.max_nr_accesses,
259                                 &pattern.min_age_region,
260                                 &pattern.max_age_region,
261                                 &action_input, &quota.ms,
262                                 &quota.sz, &quota.reset_interval,
263                                 &quota.weight_sz, &quota.weight_nr_accesses,
264                                 &quota.weight_age, &wmarks.metric,
265                                 &wmarks.interval, &wmarks.high, &wmarks.mid,
266                                 &wmarks.low, &parsed);
267                 if (ret != 18)
268                         break;
269                 action = dbgfs_scheme_action_to_damos_action(action_input);
270                 if ((int)action < 0)
271                         goto fail;
272 
273                 if (pattern.min_sz_region > pattern.max_sz_region ||
274                     pattern.min_nr_accesses > pattern.max_nr_accesses ||
275                     pattern.min_age_region > pattern.max_age_region)
276                         goto fail;
277 
278                 if (wmarks.high < wmarks.mid || wmarks.high < wmarks.low ||
279                     wmarks.mid <  wmarks.low)
280                         goto fail;
281 
282                 pos += parsed;
283                 scheme = damon_new_scheme(&pattern, action, 0, &quota,
284                                 &wmarks, NUMA_NO_NODE);
285                 if (!scheme)
286                         goto fail;
287 
288                 schemes[*nr_schemes] = scheme;
289                 *nr_schemes += 1;
290         }
291         return schemes;
292 fail:
293         free_schemes_arr(schemes, *nr_schemes);
294         return NULL;
295 }
296 
297 static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf,
298                 size_t count, loff_t *ppos)
299 {
300         struct damon_ctx *ctx = file->private_data;
301         char *kbuf;
302         struct damos **schemes;
303         ssize_t nr_schemes = 0, ret;
304 
305         kbuf = user_input_str(buf, count, ppos);
306         if (IS_ERR(kbuf))
307                 return PTR_ERR(kbuf);
308 
309         schemes = str_to_schemes(kbuf, count, &nr_schemes);
310         if (!schemes) {
311                 ret = -EINVAL;
312                 goto out;
313         }
314 
315         mutex_lock(&ctx->kdamond_lock);
316         if (ctx->kdamond) {
317                 ret = -EBUSY;
318                 goto unlock_out;
319         }
320 
321         damon_set_schemes(ctx, schemes, nr_schemes);
322         ret = count;
323         nr_schemes = 0;
324 
325 unlock_out:
326         mutex_unlock(&ctx->kdamond_lock);
327         free_schemes_arr(schemes, nr_schemes);
328 out:
329         kfree(kbuf);
330         return ret;
331 }
332 
333 static ssize_t sprint_target_ids(struct damon_ctx *ctx, char *buf, ssize_t len)
334 {
335         struct damon_target *t;
336         int id;
337         int written = 0;
338         int rc;
339 
340         damon_for_each_target(t, ctx) {
341                 if (damon_target_has_pid(ctx))
342                         /* Show pid numbers to debugfs users */
343                         id = pid_vnr(t->pid);
344                 else
345                         /* Show 42 for physical address space, just for fun */
346                         id = 42;
347 
348                 rc = scnprintf(&buf[written], len - written, "%d ", id);
349                 if (!rc)
350                         return -ENOMEM;
351                 written += rc;
352         }
353         if (written)
354                 written -= 1;
355         written += scnprintf(&buf[written], len - written, "\n");
356         return written;
357 }
358 
359 static ssize_t dbgfs_target_ids_read(struct file *file,
360                 char __user *buf, size_t count, loff_t *ppos)
361 {
362         struct damon_ctx *ctx = file->private_data;
363         ssize_t len;
364         char ids_buf[320];
365 
366         mutex_lock(&ctx->kdamond_lock);
367         len = sprint_target_ids(ctx, ids_buf, 320);
368         mutex_unlock(&ctx->kdamond_lock);
369         if (len < 0)
370                 return len;
371 
372         return simple_read_from_buffer(buf, count, ppos, ids_buf, len);
373 }
374 
375 /*
376  * Converts a string into an integers array
377  *
378  * Returns an array of integers array if the conversion success, or NULL
379  * otherwise.
380  */
381 static int *str_to_ints(const char *str, ssize_t len, ssize_t *nr_ints)
382 {
383         int *array;
384         const int max_nr_ints = 32;
385         int nr;
386         int pos = 0, parsed, ret;
387 
388         *nr_ints = 0;
389         array = kmalloc_array(max_nr_ints, sizeof(*array), GFP_KERNEL);
390         if (!array)
391                 return NULL;
392         while (*nr_ints < max_nr_ints && pos < len) {
393                 ret = sscanf(&str[pos], "%d%n", &nr, &parsed);
394                 pos += parsed;
395                 if (ret != 1)
396                         break;
397                 array[*nr_ints] = nr;
398                 *nr_ints += 1;
399         }
400 
401         return array;
402 }
403 
404 static void dbgfs_put_pids(struct pid **pids, int nr_pids)
405 {
406         int i;
407 
408         for (i = 0; i < nr_pids; i++)
409                 put_pid(pids[i]);
410 }
411 
412 /*
413  * Converts a string into an struct pid pointers array
414  *
415  * Returns an array of struct pid pointers if the conversion success, or NULL
416  * otherwise.
417  */
418 static struct pid **str_to_pids(const char *str, ssize_t len, ssize_t *nr_pids)
419 {
420         int *ints;
421         ssize_t nr_ints;
422         struct pid **pids;
423 
424         *nr_pids = 0;
425 
426         ints = str_to_ints(str, len, &nr_ints);
427         if (!ints)
428                 return NULL;
429 
430         pids = kmalloc_array(nr_ints, sizeof(*pids), GFP_KERNEL);
431         if (!pids)
432                 goto out;
433 
434         for (; *nr_pids < nr_ints; (*nr_pids)++) {
435                 pids[*nr_pids] = find_get_pid(ints[*nr_pids]);
436                 if (!pids[*nr_pids]) {
437                         dbgfs_put_pids(pids, *nr_pids);
438                         kfree(ints);
439                         kfree(pids);
440                         return NULL;
441                 }
442         }
443 
444 out:
445         kfree(ints);
446         return pids;
447 }
448 
449 /*
450  * dbgfs_set_targets() - Set monitoring targets.
451  * @ctx:        monitoring context
452  * @nr_targets: number of targets
453  * @pids:       array of target pids (size is same to @nr_targets)
454  *
455  * This function should not be called while the kdamond is running.  @pids is
456  * ignored if the context is not configured to have pid in each target.  On
457  * failure, reference counts of all pids in @pids are decremented.
458  *
459  * Return: 0 on success, negative error code otherwise.
460  */
461 static int dbgfs_set_targets(struct damon_ctx *ctx, ssize_t nr_targets,
462                 struct pid **pids)
463 {
464         ssize_t i;
465         struct damon_target *t, *next;
466 
467         damon_for_each_target_safe(t, next, ctx) {
468                 if (damon_target_has_pid(ctx))
469                         put_pid(t->pid);
470                 damon_destroy_target(t);
471         }
472 
473         for (i = 0; i < nr_targets; i++) {
474                 t = damon_new_target();
475                 if (!t) {
476                         damon_for_each_target_safe(t, next, ctx)
477                                 damon_destroy_target(t);
478                         if (damon_target_has_pid(ctx))
479                                 dbgfs_put_pids(pids, nr_targets);
480                         return -ENOMEM;
481                 }
482                 if (damon_target_has_pid(ctx))
483                         t->pid = pids[i];
484                 damon_add_target(ctx, t);
485         }
486 
487         return 0;
488 }
489 
490 static ssize_t dbgfs_target_ids_write(struct file *file,
491                 const char __user *buf, size_t count, loff_t *ppos)
492 {
493         struct damon_ctx *ctx = file->private_data;
494         bool id_is_pid = true;
495         char *kbuf;
496         struct pid **target_pids = NULL;
497         ssize_t nr_targets;
498         ssize_t ret;
499 
500         kbuf = user_input_str(buf, count, ppos);
501         if (IS_ERR(kbuf))
502                 return PTR_ERR(kbuf);
503 
504         if (!strncmp(kbuf, "paddr\n", count)) {
505                 id_is_pid = false;
506                 nr_targets = 1;
507         }
508 
509         if (id_is_pid) {
510                 target_pids = str_to_pids(kbuf, count, &nr_targets);
511                 if (!target_pids) {
512                         ret = -ENOMEM;
513                         goto out;
514                 }
515         }
516 
517         mutex_lock(&ctx->kdamond_lock);
518         if (ctx->kdamond) {
519                 if (id_is_pid)
520                         dbgfs_put_pids(target_pids, nr_targets);
521                 ret = -EBUSY;
522                 goto unlock_out;
523         }
524 
525         /* remove previously set targets */
526         dbgfs_set_targets(ctx, 0, NULL);
527         if (!nr_targets) {
528                 ret = count;
529                 goto unlock_out;
530         }
531 
532         /* Configure the context for the address space type */
533         if (id_is_pid)
534                 ret = damon_select_ops(ctx, DAMON_OPS_VADDR);
535         else
536                 ret = damon_select_ops(ctx, DAMON_OPS_PADDR);
537         if (ret)
538                 goto unlock_out;
539 
540         ret = dbgfs_set_targets(ctx, nr_targets, target_pids);
541         if (!ret)
542                 ret = count;
543 
544 unlock_out:
545         mutex_unlock(&ctx->kdamond_lock);
546         kfree(target_pids);
547 out:
548         kfree(kbuf);
549         return ret;
550 }
551 
552 static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len)
553 {
554         struct damon_target *t;
555         struct damon_region *r;
556         int target_idx = 0;
557         int written = 0;
558         int rc;
559 
560         damon_for_each_target(t, c) {
561                 damon_for_each_region(r, t) {
562                         rc = scnprintf(&buf[written], len - written,
563                                         "%d %lu %lu\n",
564                                         target_idx, r->ar.start, r->ar.end);
565                         if (!rc)
566                                 return -ENOMEM;
567                         written += rc;
568                 }
569                 target_idx++;
570         }
571         return written;
572 }
573 
574 static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf,
575                 size_t count, loff_t *ppos)
576 {
577         struct damon_ctx *ctx = file->private_data;
578         char *kbuf;
579         ssize_t len;
580 
581         kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
582         if (!kbuf)
583                 return -ENOMEM;
584 
585         mutex_lock(&ctx->kdamond_lock);
586         if (ctx->kdamond) {
587                 mutex_unlock(&ctx->kdamond_lock);
588                 len = -EBUSY;
589                 goto out;
590         }
591 
592         len = sprint_init_regions(ctx, kbuf, count);
593         mutex_unlock(&ctx->kdamond_lock);
594         if (len < 0)
595                 goto out;
596         len = simple_read_from_buffer(buf, count, ppos, kbuf, len);
597 
598 out:
599         kfree(kbuf);
600         return len;
601 }
602 
603 static int add_init_region(struct damon_ctx *c, int target_idx,
604                 struct damon_addr_range *ar)
605 {
606         struct damon_target *t;
607         struct damon_region *r, *prev;
608         unsigned long idx = 0;
609         int rc = -EINVAL;
610 
611         if (ar->start >= ar->end)
612                 return -EINVAL;
613 
614         damon_for_each_target(t, c) {
615                 if (idx++ == target_idx) {
616                         r = damon_new_region(ar->start, ar->end);
617                         if (!r)
618                                 return -ENOMEM;
619                         damon_add_region(r, t);
620                         if (damon_nr_regions(t) > 1) {
621                                 prev = damon_prev_region(r);
622                                 if (prev->ar.end > r->ar.start) {
623                                         damon_destroy_region(r, t);
624                                         return -EINVAL;
625                                 }
626                         }
627                         rc = 0;
628                 }
629         }
630         return rc;
631 }
632 
633 static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len)
634 {
635         struct damon_target *t;
636         struct damon_region *r, *next;
637         int pos = 0, parsed, ret;
638         int target_idx;
639         struct damon_addr_range ar;
640         int err;
641 
642         damon_for_each_target(t, c) {
643                 damon_for_each_region_safe(r, next, t)
644                         damon_destroy_region(r, t);
645         }
646 
647         while (pos < len) {
648                 ret = sscanf(&str[pos], "%d %lu %lu%n",
649                                 &target_idx, &ar.start, &ar.end, &parsed);
650                 if (ret != 3)
651                         break;
652                 err = add_init_region(c, target_idx, &ar);
653                 if (err)
654                         goto fail;
655                 pos += parsed;
656         }
657 
658         return 0;
659 
660 fail:
661         damon_for_each_target(t, c) {
662                 damon_for_each_region_safe(r, next, t)
663                         damon_destroy_region(r, t);
664         }
665         return err;
666 }
667 
668 static ssize_t dbgfs_init_regions_write(struct file *file,
669                                           const char __user *buf, size_t count,
670                                           loff_t *ppos)
671 {
672         struct damon_ctx *ctx = file->private_data;
673         char *kbuf;
674         ssize_t ret = count;
675         int err;
676 
677         kbuf = user_input_str(buf, count, ppos);
678         if (IS_ERR(kbuf))
679                 return PTR_ERR(kbuf);
680 
681         mutex_lock(&ctx->kdamond_lock);
682         if (ctx->kdamond) {
683                 ret = -EBUSY;
684                 goto unlock_out;
685         }
686 
687         err = set_init_regions(ctx, kbuf, ret);
688         if (err)
689                 ret = err;
690 
691 unlock_out:
692         mutex_unlock(&ctx->kdamond_lock);
693         kfree(kbuf);
694         return ret;
695 }
696 
697 static ssize_t dbgfs_kdamond_pid_read(struct file *file,
698                 char __user *buf, size_t count, loff_t *ppos)
699 {
700         struct damon_ctx *ctx = file->private_data;
701         char *kbuf;
702         ssize_t len;
703 
704         kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
705         if (!kbuf)
706                 return -ENOMEM;
707 
708         mutex_lock(&ctx->kdamond_lock);
709         if (ctx->kdamond)
710                 len = scnprintf(kbuf, count, "%d\n", ctx->kdamond->pid);
711         else
712                 len = scnprintf(kbuf, count, "none\n");
713         mutex_unlock(&ctx->kdamond_lock);
714         if (!len)
715                 goto out;
716         len = simple_read_from_buffer(buf, count, ppos, kbuf, len);
717 
718 out:
719         kfree(kbuf);
720         return len;
721 }
722 
723 static int damon_dbgfs_open(struct inode *inode, struct file *file)
724 {
725         damon_dbgfs_warn_deprecation();
726 
727         file->private_data = inode->i_private;
728 
729         return nonseekable_open(inode, file);
730 }
731 
732 static const struct file_operations attrs_fops = {
733         .open = damon_dbgfs_open,
734         .read = dbgfs_attrs_read,
735         .write = dbgfs_attrs_write,
736 };
737 
738 static const struct file_operations schemes_fops = {
739         .open = damon_dbgfs_open,
740         .read = dbgfs_schemes_read,
741         .write = dbgfs_schemes_write,
742 };
743 
744 static const struct file_operations target_ids_fops = {
745         .open = damon_dbgfs_open,
746         .read = dbgfs_target_ids_read,
747         .write = dbgfs_target_ids_write,
748 };
749 
750 static const struct file_operations init_regions_fops = {
751         .open = damon_dbgfs_open,
752         .read = dbgfs_init_regions_read,
753         .write = dbgfs_init_regions_write,
754 };
755 
756 static const struct file_operations kdamond_pid_fops = {
757         .open = damon_dbgfs_open,
758         .read = dbgfs_kdamond_pid_read,
759 };
760 
761 static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx)
762 {
763         const char * const file_names[] = {"attrs", "schemes", "target_ids",
764                 "init_regions", "kdamond_pid"};
765         const struct file_operations *fops[] = {&attrs_fops, &schemes_fops,
766                 &target_ids_fops, &init_regions_fops, &kdamond_pid_fops};
767         int i;
768 
769         for (i = 0; i < ARRAY_SIZE(file_names); i++)
770                 debugfs_create_file(file_names[i], 0600, dir, ctx, fops[i]);
771 }
772 
773 static void dbgfs_before_terminate(struct damon_ctx *ctx)
774 {
775         struct damon_target *t, *next;
776 
777         if (!damon_target_has_pid(ctx))
778                 return;
779 
780         mutex_lock(&ctx->kdamond_lock);
781         damon_for_each_target_safe(t, next, ctx) {
782                 put_pid(t->pid);
783                 damon_destroy_target(t);
784         }
785         mutex_unlock(&ctx->kdamond_lock);
786 }
787 
788 static struct damon_ctx *dbgfs_new_ctx(void)
789 {
790         struct damon_ctx *ctx;
791 
792         ctx = damon_new_ctx();
793         if (!ctx)
794                 return NULL;
795 
796         if (damon_select_ops(ctx, DAMON_OPS_VADDR) &&
797                         damon_select_ops(ctx, DAMON_OPS_PADDR)) {
798                 damon_destroy_ctx(ctx);
799                 return NULL;
800         }
801         ctx->callback.before_terminate = dbgfs_before_terminate;
802         return ctx;
803 }
804 
805 static void dbgfs_destroy_ctx(struct damon_ctx *ctx)
806 {
807         damon_destroy_ctx(ctx);
808 }
809 
810 static ssize_t damon_dbgfs_deprecated_read(struct file *file,
811                 char __user *buf, size_t count, loff_t *ppos)
812 {
813         static const char kbuf[512] = DAMON_DBGFS_DEPRECATION_NOTICE;
814 
815         return simple_read_from_buffer(buf, count, ppos, kbuf, strlen(kbuf));
816 }
817 
818 /*
819  * Make a context of @name and create a debugfs directory for it.
820  *
821  * This function should be called while holding damon_dbgfs_lock.
822  *
823  * Returns 0 on success, negative error code otherwise.
824  */
825 static int dbgfs_mk_context(char *name)
826 {
827         struct dentry *root, **new_dirs, *new_dir;
828         struct damon_ctx **new_ctxs, *new_ctx;
829 
830         if (damon_nr_running_ctxs())
831                 return -EBUSY;
832 
833         new_ctxs = krealloc(dbgfs_ctxs, sizeof(*dbgfs_ctxs) *
834                         (dbgfs_nr_ctxs + 1), GFP_KERNEL);
835         if (!new_ctxs)
836                 return -ENOMEM;
837         dbgfs_ctxs = new_ctxs;
838 
839         new_dirs = krealloc(dbgfs_dirs, sizeof(*dbgfs_dirs) *
840                         (dbgfs_nr_ctxs + 1), GFP_KERNEL);
841         if (!new_dirs)
842                 return -ENOMEM;
843         dbgfs_dirs = new_dirs;
844 
845         root = dbgfs_dirs[0];
846         if (!root)
847                 return -ENOENT;
848 
849         new_dir = debugfs_create_dir(name, root);
850         /* Below check is required for a potential duplicated name case */
851         if (IS_ERR(new_dir))
852                 return PTR_ERR(new_dir);
853         dbgfs_dirs[dbgfs_nr_ctxs] = new_dir;
854 
855         new_ctx = dbgfs_new_ctx();
856         if (!new_ctx) {
857                 debugfs_remove(new_dir);
858                 dbgfs_dirs[dbgfs_nr_ctxs] = NULL;
859                 return -ENOMEM;
860         }
861 
862         dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx;
863         dbgfs_fill_ctx_dir(dbgfs_dirs[dbgfs_nr_ctxs],
864                         dbgfs_ctxs[dbgfs_nr_ctxs]);
865         dbgfs_nr_ctxs++;
866 
867         return 0;
868 }
869 
870 static ssize_t dbgfs_mk_context_write(struct file *file,
871                 const char __user *buf, size_t count, loff_t *ppos)
872 {
873         char *kbuf;
874         char *ctx_name;
875         ssize_t ret;
876 
877         kbuf = user_input_str(buf, count, ppos);
878         if (IS_ERR(kbuf))
879                 return PTR_ERR(kbuf);
880         ctx_name = kmalloc(count + 1, GFP_KERNEL);
881         if (!ctx_name) {
882                 kfree(kbuf);
883                 return -ENOMEM;
884         }
885 
886         /* Trim white space */
887         if (sscanf(kbuf, "%s", ctx_name) != 1) {
888                 ret = -EINVAL;
889                 goto out;
890         }
891 
892         mutex_lock(&damon_dbgfs_lock);
893         ret = dbgfs_mk_context(ctx_name);
894         if (!ret)
895                 ret = count;
896         mutex_unlock(&damon_dbgfs_lock);
897 
898 out:
899         kfree(kbuf);
900         kfree(ctx_name);
901         return ret;
902 }
903 
904 /*
905  * Remove a context of @name and its debugfs directory.
906  *
907  * This function should be called while holding damon_dbgfs_lock.
908  *
909  * Return 0 on success, negative error code otherwise.
910  */
911 static int dbgfs_rm_context(char *name)
912 {
913         struct dentry *root, *dir, **new_dirs;
914         struct inode *inode;
915         struct damon_ctx **new_ctxs;
916         int i, j;
917         int ret = 0;
918 
919         if (damon_nr_running_ctxs())
920                 return -EBUSY;
921 
922         root = dbgfs_dirs[0];
923         if (!root)
924                 return -ENOENT;
925 
926         dir = debugfs_lookup(name, root);
927         if (!dir)
928                 return -ENOENT;
929 
930         inode = d_inode(dir);
931         if (!S_ISDIR(inode->i_mode)) {
932                 ret = -EINVAL;
933                 goto out_dput;
934         }
935 
936         new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs),
937                         GFP_KERNEL);
938         if (!new_dirs) {
939                 ret = -ENOMEM;
940                 goto out_dput;
941         }
942 
943         new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs),
944                         GFP_KERNEL);
945         if (!new_ctxs) {
946                 ret = -ENOMEM;
947                 goto out_new_dirs;
948         }
949 
950         for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) {
951                 if (dbgfs_dirs[i] == dir) {
952                         debugfs_remove(dbgfs_dirs[i]);
953                         dbgfs_destroy_ctx(dbgfs_ctxs[i]);
954                         continue;
955                 }
956                 new_dirs[j] = dbgfs_dirs[i];
957                 new_ctxs[j++] = dbgfs_ctxs[i];
958         }
959 
960         kfree(dbgfs_dirs);
961         kfree(dbgfs_ctxs);
962 
963         dbgfs_dirs = new_dirs;
964         dbgfs_ctxs = new_ctxs;
965         dbgfs_nr_ctxs--;
966 
967         goto out_dput;
968 
969 out_new_dirs:
970         kfree(new_dirs);
971 out_dput:
972         dput(dir);
973         return ret;
974 }
975 
976 static ssize_t dbgfs_rm_context_write(struct file *file,
977                 const char __user *buf, size_t count, loff_t *ppos)
978 {
979         char *kbuf;
980         ssize_t ret;
981         char *ctx_name;
982 
983         kbuf = user_input_str(buf, count, ppos);
984         if (IS_ERR(kbuf))
985                 return PTR_ERR(kbuf);
986         ctx_name = kmalloc(count + 1, GFP_KERNEL);
987         if (!ctx_name) {
988                 kfree(kbuf);
989                 return -ENOMEM;
990         }
991 
992         /* Trim white space */
993         if (sscanf(kbuf, "%s", ctx_name) != 1) {
994                 ret = -EINVAL;
995                 goto out;
996         }
997 
998         mutex_lock(&damon_dbgfs_lock);
999         ret = dbgfs_rm_context(ctx_name);
1000         if (!ret)
1001                 ret = count;
1002         mutex_unlock(&damon_dbgfs_lock);
1003 
1004 out:
1005         kfree(kbuf);
1006         kfree(ctx_name);
1007         return ret;
1008 }
1009 
1010 static ssize_t dbgfs_monitor_on_read(struct file *file,
1011                 char __user *buf, size_t count, loff_t *ppos)
1012 {
1013         char monitor_on_buf[5];
1014         bool monitor_on = damon_nr_running_ctxs() != 0;
1015         int len;
1016 
1017         len = scnprintf(monitor_on_buf, 5, monitor_on ? "on\n" : "off\n");
1018 
1019         return simple_read_from_buffer(buf, count, ppos, monitor_on_buf, len);
1020 }
1021 
1022 static ssize_t dbgfs_monitor_on_write(struct file *file,
1023                 const char __user *buf, size_t count, loff_t *ppos)
1024 {
1025         ssize_t ret;
1026         char *kbuf;
1027 
1028         kbuf = user_input_str(buf, count, ppos);
1029         if (IS_ERR(kbuf))
1030                 return PTR_ERR(kbuf);
1031 
1032         /* Remove white space */
1033         if (sscanf(kbuf, "%s", kbuf) != 1) {
1034                 kfree(kbuf);
1035                 return -EINVAL;
1036         }
1037 
1038         mutex_lock(&damon_dbgfs_lock);
1039         if (!strncmp(kbuf, "on", count)) {
1040                 int i;
1041 
1042                 for (i = 0; i < dbgfs_nr_ctxs; i++) {
1043                         if (damon_targets_empty(dbgfs_ctxs[i])) {
1044                                 kfree(kbuf);
1045                                 mutex_unlock(&damon_dbgfs_lock);
1046                                 return -EINVAL;
1047                         }
1048                 }
1049                 ret = damon_start(dbgfs_ctxs, dbgfs_nr_ctxs, true);
1050         } else if (!strncmp(kbuf, "off", count)) {
1051                 ret = damon_stop(dbgfs_ctxs, dbgfs_nr_ctxs);
1052         } else {
1053                 ret = -EINVAL;
1054         }
1055         mutex_unlock(&damon_dbgfs_lock);
1056 
1057         if (!ret)
1058                 ret = count;
1059         kfree(kbuf);
1060         return ret;
1061 }
1062 
1063 static int damon_dbgfs_static_file_open(struct inode *inode, struct file *file)
1064 {
1065         damon_dbgfs_warn_deprecation();
1066         return nonseekable_open(inode, file);
1067 }
1068 
1069 static const struct file_operations deprecated_fops = {
1070         .read = damon_dbgfs_deprecated_read,
1071 };
1072 
1073 static const struct file_operations mk_contexts_fops = {
1074         .open = damon_dbgfs_static_file_open,
1075         .write = dbgfs_mk_context_write,
1076 };
1077 
1078 static const struct file_operations rm_contexts_fops = {
1079         .open = damon_dbgfs_static_file_open,
1080         .write = dbgfs_rm_context_write,
1081 };
1082 
1083 static const struct file_operations monitor_on_fops = {
1084         .open = damon_dbgfs_static_file_open,
1085         .read = dbgfs_monitor_on_read,
1086         .write = dbgfs_monitor_on_write,
1087 };
1088 
1089 static int __init __damon_dbgfs_init(void)
1090 {
1091         struct dentry *dbgfs_root;
1092         const char * const file_names[] = {"mk_contexts", "rm_contexts",
1093                 "monitor_on_DEPRECATED", "DEPRECATED"};
1094         const struct file_operations *fops[] = {&mk_contexts_fops,
1095                 &rm_contexts_fops, &monitor_on_fops, &deprecated_fops};
1096         int i;
1097 
1098         dbgfs_root = debugfs_create_dir("damon", NULL);
1099 
1100         for (i = 0; i < ARRAY_SIZE(file_names); i++)
1101                 debugfs_create_file(file_names[i], 0600, dbgfs_root, NULL,
1102                                 fops[i]);
1103         dbgfs_fill_ctx_dir(dbgfs_root, dbgfs_ctxs[0]);
1104 
1105         dbgfs_dirs = kmalloc(sizeof(dbgfs_root), GFP_KERNEL);
1106         if (!dbgfs_dirs) {
1107                 debugfs_remove(dbgfs_root);
1108                 return -ENOMEM;
1109         }
1110         dbgfs_dirs[0] = dbgfs_root;
1111 
1112         return 0;
1113 }
1114 
1115 /*
1116  * Functions for the initialization
1117  */
1118 
1119 static int __init damon_dbgfs_init(void)
1120 {
1121         int rc = -ENOMEM;
1122 
1123         mutex_lock(&damon_dbgfs_lock);
1124         dbgfs_ctxs = kmalloc(sizeof(*dbgfs_ctxs), GFP_KERNEL);
1125         if (!dbgfs_ctxs)
1126                 goto out;
1127         dbgfs_ctxs[0] = dbgfs_new_ctx();
1128         if (!dbgfs_ctxs[0]) {
1129                 kfree(dbgfs_ctxs);
1130                 goto out;
1131         }
1132         dbgfs_nr_ctxs = 1;
1133 
1134         rc = __damon_dbgfs_init();
1135         if (rc) {
1136                 kfree(dbgfs_ctxs[0]);
1137                 kfree(dbgfs_ctxs);
1138                 pr_err("%s: dbgfs init failed\n", __func__);
1139         }
1140 
1141 out:
1142         mutex_unlock(&damon_dbgfs_lock);
1143         return rc;
1144 }
1145 
1146 module_init(damon_dbgfs_init);
1147 
1148 #include "dbgfs-test.h"
1149 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php