// SPDX-License-Identifier: GPL-2.0 /* * Common Code for DAMON Sysfs Interface * * Author: SeongJae Park */ #include #include "sysfs-common.h" DEFINE_MUTEX(damon_sysfs_lock); /* * unsigned long range directory */ struct damon_sysfs_ul_range *damon_sysfs_ul_range_alloc( unsigned long min, unsigned long max) { struct damon_sysfs_ul_range *range = kmalloc_obj(*range); if (!range) return NULL; range->kobj = (struct kobject){}; range->min = min; range->max = max; return range; } static ssize_t min_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct damon_sysfs_ul_range *range = container_of(kobj, struct damon_sysfs_ul_range, kobj); return sysfs_emit(buf, "%lu\n", range->min); } static ssize_t min_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct damon_sysfs_ul_range *range = container_of(kobj, struct damon_sysfs_ul_range, kobj); unsigned long min; int err; err = kstrtoul(buf, 0, &min); if (err) return err; range->min = min; return count; } static ssize_t max_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct damon_sysfs_ul_range *range = container_of(kobj, struct damon_sysfs_ul_range, kobj); return sysfs_emit(buf, "%lu\n", range->max); } static ssize_t max_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct damon_sysfs_ul_range *range = container_of(kobj, struct damon_sysfs_ul_range, kobj); unsigned long max; int err; err = kstrtoul(buf, 0, &max); if (err) return err; range->max = max; return count; } void damon_sysfs_ul_range_release(struct kobject *kobj) { kfree(container_of(kobj, struct damon_sysfs_ul_range, kobj)); } static struct kobj_attribute damon_sysfs_ul_range_min_attr = __ATTR_RW_MODE(min, 0600); static struct kobj_attribute damon_sysfs_ul_range_max_attr = __ATTR_RW_MODE(max, 0600); static struct attribute *damon_sysfs_ul_range_attrs[] = { &damon_sysfs_ul_range_min_attr.attr, &damon_sysfs_ul_range_max_attr.attr, NULL, }; ATTRIBUTE_GROUPS(damon_sysfs_ul_range); const struct kobj_type damon_sysfs_ul_range_ktype = { .release = damon_sysfs_ul_range_release, .sysfs_ops = &kobj_sysfs_ops, .default_groups = damon_sysfs_ul_range_groups, }; static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg, char *memcg_path_buf, char *path) { #ifdef CONFIG_MEMCG cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX); if (sysfs_streq(memcg_path_buf, path)) return true; #endif /* CONFIG_MEMCG */ return false; } int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id) { struct mem_cgroup *memcg; char *path; bool found = false; if (!memcg_path) return -EINVAL; path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL); if (!path) return -ENOMEM; for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg; memcg = mem_cgroup_iter(NULL, memcg, NULL)) { /* skip offlined memcg */ if (!mem_cgroup_online(memcg)) continue; if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) { *id = mem_cgroup_id(memcg); found = true; mem_cgroup_iter_break(NULL, memcg); break; } } kfree(path); return found ? 0 : -EINVAL; }