[PATCH v2 2/3] cgroup/dmem: accept a single region when writing to attributes
From: Thadeu Lima de Souza Cascardo
Date: Thu Mar 19 2026 - 17:25:42 EST
When writing to dmem.{min,low,max}, if multiple lines are given, one of
them might succeed while the next one fails, but an error is returned. That
is, there is no atomicity where either all changes succeed or all of them
fail.
Only accept a single region instead of trying to parse multiple lines and
process multiple regions at the same write.
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@xxxxxxxxxx>
---
kernel/cgroup/dmem.c | 69 +++++++++++++++++++++++-----------------------------
1 file changed, 30 insertions(+), 39 deletions(-)
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 1ab1fb47f2711ecc60dd13e611a8a4920b48f3e9..695d2b7516081256da030c80b54ec1c5fcd6ca16 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -729,56 +729,47 @@ static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
{
struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));
int err = 0;
+ struct dmem_cgroup_pool_state *pool = NULL;
+ char *region_name;
+ struct dmem_cgroup_region *region;
+ u64 new_limit;
- while (buf && !err) {
- struct dmem_cgroup_pool_state *pool = NULL;
- char *options, *region_name;
- struct dmem_cgroup_region *region;
- u64 new_limit;
-
- options = buf;
- buf = strchr(buf, '\n');
- if (buf)
- *buf++ = '\0';
-
- options = strstrip(options);
+ buf = strstrip(buf);
+ if (!buf[0])
+ return -EINVAL;
- /* eat empty lines */
- if (!options[0])
- continue;
+ region_name = strsep(&buf, " \t");
+ if (!region_name[0])
+ return -EINVAL;
- region_name = strsep(&options, " \t");
- if (!region_name[0])
- continue;
+ if (!buf || !*buf)
+ return -EINVAL;
- if (!options || !*options)
- return -EINVAL;
+ buf = skip_spaces(buf);
- rcu_read_lock();
- region = dmemcg_get_region_by_name(region_name);
- rcu_read_unlock();
+ err = dmemcg_parse_limit(buf, &new_limit);
+ if (err < 0)
+ return -EINVAL;
- if (!region)
- return -EINVAL;
+ rcu_read_lock();
+ region = dmemcg_get_region_by_name(region_name);
+ rcu_read_unlock();
- err = dmemcg_parse_limit(options, &new_limit);
- if (err < 0)
- goto out_put;
+ if (!region)
+ return -EINVAL;
- pool = get_cg_pool_unlocked(dmemcs, region);
- if (IS_ERR(pool)) {
- err = PTR_ERR(pool);
- goto out_put;
- }
+ pool = get_cg_pool_unlocked(dmemcs, region);
+ if (IS_ERR(pool)) {
+ err = PTR_ERR(pool);
+ goto out_put;
+ }
- /* And commit */
- apply(pool, new_limit);
- dmemcg_pool_put(pool);
+ /* And commit */
+ apply(pool, new_limit);
+ dmemcg_pool_put(pool);
out_put:
- kref_put(®ion->ref, dmemcg_free_region);
- }
-
+ kref_put(®ion->ref, dmemcg_free_region);
return err ?: nbytes;
}
--
2.47.3