]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cgroup/cpuset: record DL BW alloc CPU for attach rollback
authorGuopeng Zhang <zhangguopeng@kylinos.cn>
Fri, 17 Apr 2026 03:37:41 +0000 (11:37 +0800)
committerTejun Heo <tj@kernel.org>
Fri, 17 Apr 2026 18:57:37 +0000 (08:57 -1000)
cpuset_can_attach() allocates DL bandwidth only when migrating
deadline tasks to a disjoint CPU mask, but cpuset_cancel_attach()
rolls back based only on nr_migrate_dl_tasks. This makes the DL
bandwidth alloc/free paths asymmetric: rollback can call dl_bw_free()
even when no dl_bw_alloc() was done.

Rollback also needs to undo the reservation against the same CPU/root
domain that was charged. Record the CPU used by dl_bw_alloc() and use
that state in cpuset_cancel_attach(). If no allocation happened,
dl_bw_cpu stays at -1 and rollback skips dl_bw_free(). If allocation
did happen, bandwidth is returned to the same CPU/root domain.

Successful attach paths are unchanged. This only fixes failed attach
rollback accounting.

Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Reviewed-by: Waiman Long <longman@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/cgroup/cpuset-internal.h
kernel/cgroup/cpuset.c

index fd7d19842ded7d95bd29aa5dc55e76f963acc805..bb4e692bea300cb09ff298af5ba4043dea149a7b 100644 (file)
@@ -168,6 +168,11 @@ struct cpuset {
        int nr_deadline_tasks;
        int nr_migrate_dl_tasks;
        u64 sum_migrate_dl_bw;
+       /*
+        * CPU used for temporary DL bandwidth allocation during attach;
+        * -1 if no DL bandwidth was allocated in the current attach.
+        */
+       int dl_bw_cpu;
 
        /* Invalid partition error code, not lock protected */
        enum prs_errcode prs_err;
index 1335e437098e8071d70e9b4df620fb115baa849b..e3a081a07c6d5166e475ad66f72ae0fc6920f027 100644 (file)
@@ -288,6 +288,7 @@ struct cpuset top_cpuset = {
        .flags = BIT(CS_CPU_EXCLUSIVE) |
                 BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE),
        .partition_root_state = PRS_ROOT,
+       .dl_bw_cpu = -1,
 };
 
 /**
@@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs)
        if (!trial)
                return NULL;
 
+       trial->dl_bw_cpu = -1;
+
        /* Setup cpumask pointer array */
        cpumask_var_t *pmask[4] = {
                &trial->cpus_allowed,
@@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs)
 {
        cs->nr_migrate_dl_tasks = 0;
        cs->sum_migrate_dl_bw = 0;
+       cs->dl_bw_cpu = -1;
 }
 
 /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
@@ -3056,6 +3060,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
                        reset_migrate_dl_data(cs);
                        goto out_unlock;
                }
+
+               cs->dl_bw_cpu = cpu;
        }
 
 out_success:
@@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset)
        mutex_lock(&cpuset_mutex);
        dec_attach_in_progress_locked(cs);
 
-       if (cs->nr_migrate_dl_tasks) {
-               int cpu = cpumask_any(cs->effective_cpus);
+       if (cs->dl_bw_cpu >= 0)
+               dl_bw_free(cs->dl_bw_cpu, cs->sum_migrate_dl_bw);
 
-               dl_bw_free(cpu, cs->sum_migrate_dl_bw);
+       if (cs->nr_migrate_dl_tasks)
                reset_migrate_dl_data(cs);
-       }
 
        mutex_unlock(&cpuset_mutex);
 }