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