1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Common Code for DAMON Sysfs Interface 4 * 5 * Author: SeongJae Park <sj@kernel.org> 6 */ 7 8 #include <linux/slab.h> 9 10 #include "sysfs-common.h" 11 12 DEFINE_MUTEX(damon_sysfs_lock); 13 14 /* 15 * unsigned long range directory 16 */ 17 18 struct damon_sysfs_ul_range *damon_sysfs_ul_range_alloc( 19 unsigned long min, 20 unsigned long max) 21 { 22 struct damon_sysfs_ul_range *range = kmalloc_obj(*range); 23 24 if (!range) 25 return NULL; 26 range->kobj = (struct kobject){}; 27 range->min = min; 28 range->max = max; 29 30 return range; 31 } 32 33 static ssize_t min_show(struct kobject *kobj, struct kobj_attribute *attr, 34 char *buf) 35 { 36 struct damon_sysfs_ul_range *range = container_of(kobj, 37 struct damon_sysfs_ul_range, kobj); 38 39 return sysfs_emit(buf, "%lu\n", range->min); 40 } 41 42 static ssize_t min_store(struct kobject *kobj, struct kobj_attribute *attr, 43 const char *buf, size_t count) 44 { 45 struct damon_sysfs_ul_range *range = container_of(kobj, 46 struct damon_sysfs_ul_range, kobj); 47 unsigned long min; 48 int err; 49 50 err = kstrtoul(buf, 0, &min); 51 if (err) 52 return err; 53 54 range->min = min; 55 return count; 56 } 57 58 static ssize_t max_show(struct kobject *kobj, struct kobj_attribute *attr, 59 char *buf) 60 { 61 struct damon_sysfs_ul_range *range = container_of(kobj, 62 struct damon_sysfs_ul_range, kobj); 63 64 return sysfs_emit(buf, "%lu\n", range->max); 65 } 66 67 static ssize_t max_store(struct kobject *kobj, struct kobj_attribute *attr, 68 const char *buf, size_t count) 69 { 70 struct damon_sysfs_ul_range *range = container_of(kobj, 71 struct damon_sysfs_ul_range, kobj); 72 unsigned long max; 73 int err; 74 75 err = kstrtoul(buf, 0, &max); 76 if (err) 77 return err; 78 79 range->max = max; 80 return count; 81 } 82 83 void damon_sysfs_ul_range_release(struct kobject *kobj) 84 { 85 kfree(container_of(kobj, struct damon_sysfs_ul_range, kobj)); 86 } 87 88 static struct kobj_attribute damon_sysfs_ul_range_min_attr = 89 __ATTR_RW_MODE(min, 0600); 90 91 static struct kobj_attribute damon_sysfs_ul_range_max_attr = 92 __ATTR_RW_MODE(max, 0600); 93 94 static struct attribute *damon_sysfs_ul_range_attrs[] = { 95 &damon_sysfs_ul_range_min_attr.attr, 96 &damon_sysfs_ul_range_max_attr.attr, 97 NULL, 98 }; 99 ATTRIBUTE_GROUPS(damon_sysfs_ul_range); 100 101 const struct kobj_type damon_sysfs_ul_range_ktype = { 102 .release = damon_sysfs_ul_range_release, 103 .sysfs_ops = &kobj_sysfs_ops, 104 .default_groups = damon_sysfs_ul_range_groups, 105 }; 106 107 108 static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg, 109 char *memcg_path_buf, char *path) 110 { 111 #ifdef CONFIG_MEMCG 112 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX); 113 if (sysfs_streq(memcg_path_buf, path)) 114 return true; 115 #endif /* CONFIG_MEMCG */ 116 return false; 117 } 118 119 int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id) 120 { 121 struct mem_cgroup *memcg; 122 char *path; 123 bool found = false; 124 125 if (!memcg_path) 126 return -EINVAL; 127 128 path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL); 129 if (!path) 130 return -ENOMEM; 131 132 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg; 133 memcg = mem_cgroup_iter(NULL, memcg, NULL)) { 134 /* skip offlined memcg */ 135 if (!mem_cgroup_online(memcg)) 136 continue; 137 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) { 138 *id = mem_cgroup_id(memcg); 139 found = true; 140 mem_cgroup_iter_break(NULL, memcg); 141 break; 142 } 143 } 144 145 kfree(path); 146 return found ? 0 : -EINVAL; 147 } 148