mm/damon/sysfs-schemes: implement filter directory
authorSeongJae Park <sj@kernel.org>
Mon, 5 Dec 2022 23:08:25 +0000 (23:08 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 19 Jan 2023 01:12:43 +0000 (17:12 -0800)
Implement DAMOS filter directory which will be located under the filters
directory.  The directory provides three files, namely type, matching, and
memcg_path.  'type' and 'matching' will be directly connected to the
fields of 'struct damos_filter' having same name.  'memcg_path' will
receive the path of the memory cgroup of the interest and later converted
to memcg id when it's committed.

Link: https://lkml.kernel.org/r/20221205230830.144349-7-sj@kernel.org
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/damon/sysfs-schemes.c

index 50c8148cb474c65990082e10ce507bcb28a6097e..afbfc55a8e8424af476592db4ea39d698013ec69 100644 (file)
@@ -258,6 +258,134 @@ static struct kobj_type damon_sysfs_stats_ktype = {
        .default_groups = damon_sysfs_stats_groups,
 };
 
+/*
+ * filter directory
+ */
+
+struct damon_sysfs_scheme_filter {
+       struct kobject kobj;
+       enum damos_filter_type type;
+       bool matching;
+       char *memcg_path;
+};
+
+/* Should match with enum damos_filter_type */
+static const char * const damon_sysfs_scheme_filter_type_strs[] = {
+       "anon",
+       "memcg",
+};
+
+static ssize_t type_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+
+       return sysfs_emit(buf, "%s\n",
+                       damon_sysfs_scheme_filter_type_strs[filter->type]);
+}
+
+static ssize_t type_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+       enum damos_filter_type type;
+       ssize_t ret = -EINVAL;
+
+       for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) {
+               if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[
+                                       type])) {
+                       filter->type = type;
+                       ret = count;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static ssize_t matching_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+
+       return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
+}
+
+static ssize_t matching_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+       bool matching;
+       int err = kstrtobool(buf, &matching);
+
+       if (err)
+               return err;
+
+       filter->matching = matching;
+       return count;
+}
+
+static ssize_t memcg_path_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+
+       return sysfs_emit(buf, "%s\n",
+                       filter->memcg_path ? filter->memcg_path : "");
+}
+
+static ssize_t memcg_path_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+       char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL);
+
+       if (!path)
+               return -ENOMEM;
+
+       strncpy(path, buf, count);
+       path[count] = '\0';
+       filter->memcg_path = path;
+       return count;
+}
+
+static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
+{
+       struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+                       struct damon_sysfs_scheme_filter, kobj);
+
+       kfree(filter->memcg_path);
+       kfree(filter);
+}
+
+static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
+               __ATTR_RW_MODE(type, 0600);
+
+static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
+               __ATTR_RW_MODE(matching, 0600);
+
+static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
+               __ATTR_RW_MODE(memcg_path, 0600);
+
+static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
+       &damon_sysfs_scheme_filter_type_attr.attr,
+       &damon_sysfs_scheme_filter_matching_attr.attr,
+       &damon_sysfs_scheme_filter_memcg_path_attr.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
+
+static struct kobj_type damon_sysfs_scheme_filter_ktype = {
+       .release = damon_sysfs_scheme_filter_release,
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_groups = damon_sysfs_scheme_filter_groups,
+};
+
 /*
  * filters directory
  */