Commit 9bbb820a authored by SeongJae Park's avatar SeongJae Park Committed by Linus Torvalds

mm/damon/sysfs: support DAMOS quotas

This commit makes DAMON sysfs interface supports the DAMOS quotas feature.
Specifically, this commit adds 'quotas' directory under each scheme
directory and makes kdamond 'state' file writing respects the contents in
the directory.

As a result, the files hierarchy becomes as below:

    /sys/kernel/mm/damon/admin
    │ kdamonds/nr_kdamonds
    │ │ 0/state,pid
    │ │ │ contexts/nr_contexts
    │ │ │ │ 0/operations
    │ │ │ │ │ monitoring_attrs/intervals/sample_us,aggr_us,update_us
    │ │ │ │ │ │ nr_regions/min,max
    │ │ │ │ │ targets/nr_targets
    │ │ │ │ │ │ 0/pid_target
    │ │ │ │ │ │ │ regions/nr_regions
    │ │ │ │ │ │ │ │ 0/start,end
    │ │ │ │ │ │ │ │ ...
    │ │ │ │ │ │ ...
    │ │ │ │ │ schemes/nr_schemes
    │ │ │ │ │ │ 0/action
    │ │ │ │ │ │ │ access_pattern/
    │ │ │ │ │ │ │ │ sz/min,max
    │ │ │ │ │ │ │ │ nr_accesses/min,max
    │ │ │ │ │ │ │ │ age/min,max
    │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms    <- NEW DIRECTORY
    │ │ │ │ │ │ ...
    │ │ │ │ ...
    │ │ ...

Link: https://lkml.kernel.org/r/20220228081314.5770-8-sj@kernel.orgSigned-off-by: default avatarSeongJae Park <sj@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Xin Hao <xhao@linux.alibaba.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7e84b1f8
...@@ -113,6 +113,113 @@ static struct kobj_type damon_sysfs_ul_range_ktype = { ...@@ -113,6 +113,113 @@ static struct kobj_type damon_sysfs_ul_range_ktype = {
.default_groups = damon_sysfs_ul_range_groups, .default_groups = damon_sysfs_ul_range_groups,
}; };
/*
* quotas directory
*/
struct damon_sysfs_quotas {
struct kobject kobj;
unsigned long ms;
unsigned long sz;
unsigned long reset_interval_ms;
};
static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
{
return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
}
static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
return sysfs_emit(buf, "%lu\n", quotas->ms);
}
static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
int err = kstrtoul(buf, 0, &quotas->ms);
if (err)
return -EINVAL;
return count;
}
static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
return sysfs_emit(buf, "%lu\n", quotas->sz);
}
static ssize_t bytes_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
int err = kstrtoul(buf, 0, &quotas->sz);
if (err)
return -EINVAL;
return count;
}
static ssize_t reset_interval_ms_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
}
static ssize_t reset_interval_ms_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
struct damon_sysfs_quotas *quotas = container_of(kobj,
struct damon_sysfs_quotas, kobj);
int err = kstrtoul(buf, 0, &quotas->reset_interval_ms);
if (err)
return -EINVAL;
return count;
}
static void damon_sysfs_quotas_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
}
static struct kobj_attribute damon_sysfs_quotas_ms_attr =
__ATTR_RW_MODE(ms, 0600);
static struct kobj_attribute damon_sysfs_quotas_sz_attr =
__ATTR_RW_MODE(bytes, 0600);
static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
__ATTR_RW_MODE(reset_interval_ms, 0600);
static struct attribute *damon_sysfs_quotas_attrs[] = {
&damon_sysfs_quotas_ms_attr.attr,
&damon_sysfs_quotas_sz_attr.attr,
&damon_sysfs_quotas_reset_interval_ms_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_quotas);
static struct kobj_type damon_sysfs_quotas_ktype = {
.release = damon_sysfs_quotas_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = damon_sysfs_quotas_groups,
};
/* /*
* access_pattern directory * access_pattern directory
*/ */
...@@ -220,6 +327,7 @@ struct damon_sysfs_scheme { ...@@ -220,6 +327,7 @@ struct damon_sysfs_scheme {
struct kobject kobj; struct kobject kobj;
enum damos_action action; enum damos_action action;
struct damon_sysfs_access_pattern *access_pattern; struct damon_sysfs_access_pattern *access_pattern;
struct damon_sysfs_quotas *quotas;
}; };
/* This should match with enum damos_action */ /* This should match with enum damos_action */
...@@ -270,6 +378,25 @@ static int damon_sysfs_scheme_set_access_pattern( ...@@ -270,6 +378,25 @@ static int damon_sysfs_scheme_set_access_pattern(
return err; return err;
} }
static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
{
struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
int err;
if (!quotas)
return -ENOMEM;
err = kobject_init_and_add(&quotas->kobj, &damon_sysfs_quotas_ktype,
&scheme->kobj, "quotas");
if (err)
goto out;
scheme->quotas = quotas;
return 0;
out:
kobject_put(&quotas->kobj);
return err;
}
static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
{ {
int err; int err;
...@@ -277,13 +404,22 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) ...@@ -277,13 +404,22 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
err = damon_sysfs_scheme_set_access_pattern(scheme); err = damon_sysfs_scheme_set_access_pattern(scheme);
if (err) if (err)
return err; return err;
err = damon_sysfs_scheme_set_quotas(scheme);
if (err)
goto put_access_pattern_out;
return 0; return 0;
put_access_pattern_out:
kobject_put(&scheme->access_pattern->kobj);
scheme->access_pattern = NULL;
return err;
} }
static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme) static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
{ {
damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
kobject_put(&scheme->access_pattern->kobj); kobject_put(&scheme->access_pattern->kobj);
kobject_put(&scheme->quotas->kobj);
} }
static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
...@@ -1522,7 +1658,15 @@ static struct damos *damon_sysfs_mk_scheme( ...@@ -1522,7 +1658,15 @@ static struct damos *damon_sysfs_mk_scheme(
{ {
struct damon_sysfs_access_pattern *pattern = struct damon_sysfs_access_pattern *pattern =
sysfs_scheme->access_pattern; sysfs_scheme->access_pattern;
struct damos_quota quota = (struct damos_quota){}; struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
struct damos_quota quota = {
.ms = sysfs_quotas->ms,
.sz = sysfs_quotas->sz,
.reset_interval = sysfs_quotas->reset_interval_ms,
.weight_sz = 1000,
.weight_nr_accesses = 1000,
.weight_age = 1000,
};
struct damos_watermarks wmarks = { struct damos_watermarks wmarks = {
.metric = DAMOS_WMARK_NONE, .metric = DAMOS_WMARK_NONE,
.interval = 0, .interval = 0,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment