* [PATCH v3 0/2] cgroup/cpuset: fix DL attach accounting
From: Guopeng Zhang @ 2026-05-09 10:20 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Michal Koutný, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Chen Ridong
Cc: Johannes Weiner, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Gabriele Monaco, Will Deacon, linux-kernel,
cgroups, Guopeng Zhang
Hi,
This v3 series contains two cpuset fixes for SCHED_DEADLINE attach
accounting.
Patch 1 fixes an internal cpuset_can_attach() failure path where
temporary DL migration state can be left behind if a later per-task
check fails before cpuset marks attach_in_progress.
Patch 2 keeps cpuset DL bandwidth reservation aligned with the condition
used by set_cpus_allowed_dl() for source-side bandwidth removal. It keeps
counting all migrating DL tasks for cpuset task accounting, but reserves
destination DL bandwidth only for tasks that actually need a root-domain
bandwidth move.
Guopeng Zhang (2):
cgroup/cpuset: reset DL migration state on can_attach() failure
cgroup/cpuset: reserve DL bandwidth only for root-domain moves
include/linux/sched/deadline.h | 9 ++++++++
kernel/cgroup/cpuset-internal.h | 1 +
kernel/cgroup/cpuset.c | 39 ++++++++++++++++++---------------
kernel/sched/deadline.c | 13 ++++++++---
4 files changed, 41 insertions(+), 21 deletions(-)
---
Changes in v3:
- Patch 1: use common ret != 0 cleanup in cpuset_can_attach(), as
suggested by Waiman Long and Chen Ridong.
- Patch 2: drop task_cpu_possible_mask() / attach-target-mask handling
as suggested by Waiman Long.
- Patch 2: keep the change limited to reserving DL bandwidth only for
tasks that need a root-domain bandwidth move.
- Leave the broader can_attach()/attach() transaction model unchanged.
Changes in v2:
- Split the original change into two patches.
- Add a separate fix for resetting pending DL migration state on
cpuset_can_attach() failure.
- Clarify that nr_migrate_dl_tasks counts all migrating DL tasks for
cpuset task accounting, while sum_migrate_dl_bw only tracks bandwidth
needing destination root-domain reservation.
v2:
https://lore.kernel.org/all/20260507103310.35849-1-zhangguopeng@kylinos.cn/
v1:
https://lore.kernel.org/all/20260421083449.95750-1-zhangguopeng@kylinos.cn
--
2.43.0
^ permalink raw reply
* [PATCH v3 1/2] cgroup/cpuset: reset DL migration state on can_attach() failure
From: Guopeng Zhang @ 2026-05-09 10:20 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Michal Koutný, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Chen Ridong
Cc: Johannes Weiner, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Gabriele Monaco, Will Deacon, linux-kernel,
cgroups, Guopeng Zhang
In-Reply-To: <20260509102031.97608-1-zhangguopeng@kylinos.cn>
cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration
state in the destination cpuset while walking the taskset.
If a later task_can_attach() or security_task_setscheduler() check
fails, cgroup_migrate_execute() treats cpuset as the failing subsystem
and does not call cpuset_cancel_attach() for it. The partially
accumulated state is then left behind and can be consumed by a later
attach, corrupting cpuset DL task accounting and pending DL bandwidth
accounting.
Reset the pending DL migration state from the common error exit when
ret is non-zero. Successful can_attach() keeps the state for
cpuset_attach() or cpuset_cancel_attach().
Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
kernel/cgroup/cpuset.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index e3a081a07c6d..b9c839538900 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3050,16 +3050,13 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
if (unlikely(cpu >= nr_cpu_ids)) {
- reset_migrate_dl_data(cs);
ret = -EINVAL;
goto out_unlock;
}
ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
- if (ret) {
- reset_migrate_dl_data(cs);
+ if (ret)
goto out_unlock;
- }
cs->dl_bw_cpu = cpu;
}
@@ -3070,7 +3067,10 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
* changes which zero cpus/mems_allowed.
*/
cs->attach_in_progress++;
+
out_unlock:
+ if (ret)
+ reset_migrate_dl_data(cs);
mutex_unlock(&cpuset_mutex);
return ret;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v3 2/2] cgroup/cpuset: reserve DL bandwidth only for root-domain moves
From: Guopeng Zhang @ 2026-05-09 10:20 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Michal Koutný, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Chen Ridong
Cc: Johannes Weiner, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Gabriele Monaco, Will Deacon, linux-kernel,
cgroups, Guopeng Zhang
In-Reply-To: <20260509102031.97608-1-zhangguopeng@kylinos.cn>
cpuset_can_attach() currently adds the bandwidth of all migrating
SCHED_DEADLINE tasks to sum_migrate_dl_bw. If the source and destination
cpuset effective CPU masks do not overlap, the whole sum is then
reserved in the destination root domain.
set_cpus_allowed_dl(), however, subtracts bandwidth from the source
root domain only when the affinity change really moves the task between
root domains. A DL task can move between cpusets that are still in the
same root domain, so including that task in sum_migrate_dl_bw can reserve
destination bandwidth without a matching source-side subtraction.
Share the root-domain move test with set_cpus_allowed_dl(). Keep
nr_migrate_dl_tasks counting all migrating deadline tasks for cpuset DL
task accounting, but add to sum_migrate_dl_bw only for tasks that need a
root-domain bandwidth move. Keep using the destination cpuset effective
CPU mask and leave the broader can_attach()/attach() transaction model
unchanged.
Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
include/linux/sched/deadline.h | 9 +++++++++
kernel/cgroup/cpuset-internal.h | 1 +
kernel/cgroup/cpuset.c | 33 ++++++++++++++++++---------------
kernel/sched/deadline.c | 13 ++++++++++---
4 files changed, 38 insertions(+), 18 deletions(-)
diff --git a/include/linux/sched/deadline.h b/include/linux/sched/deadline.h
index 1198138cb839..273538200a44 100644
--- a/include/linux/sched/deadline.h
+++ b/include/linux/sched/deadline.h
@@ -33,6 +33,15 @@ struct root_domain;
extern void dl_add_task_root_domain(struct task_struct *p);
extern void dl_clear_root_domain(struct root_domain *rd);
extern void dl_clear_root_domain_cpu(int cpu);
+/*
+ * Return whether moving DL task @p to @new_mask requires moving DL
+ * bandwidth accounting between root domains. This helper is specific to
+ * DL bandwidth move accounting semantics and is shared by
+ * cpuset_can_attach() and set_cpus_allowed_dl() so both paths use the
+ * same source root-domain test.
+ */
+extern bool dl_task_needs_bw_move(struct task_struct *p,
+ const struct cpumask *new_mask);
extern u64 dl_cookie;
extern bool dl_bw_visited(int cpu, u64 cookie);
diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
index bb4e692bea30..f7aaf01f7cd5 100644
--- a/kernel/cgroup/cpuset-internal.h
+++ b/kernel/cgroup/cpuset-internal.h
@@ -167,6 +167,7 @@ struct cpuset {
*/
int nr_deadline_tasks;
int nr_migrate_dl_tasks;
+ /* DL bandwidth that needs destination reservation for this attach. */
u64 sum_migrate_dl_bw;
/*
* CPU used for temporary DL bandwidth allocation during attach;
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b9c839538900..23abfbbb4686 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2993,7 +2993,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
struct cpuset *cs, *oldcs;
struct task_struct *task;
bool setsched_check;
- int ret;
+ int cpu, ret;
/* used later by cpuset_attach() */
cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css));
@@ -3038,28 +3038,31 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
}
if (dl_task(task)) {
+ /*
+ * Count all migrating DL tasks for cpuset task accounting.
+ * Only tasks that need a root-domain bandwidth move
+ * contribute to sum_migrate_dl_bw.
+ */
cs->nr_migrate_dl_tasks++;
- cs->sum_migrate_dl_bw += task->dl.dl_bw;
+ if (dl_task_needs_bw_move(task, cs->effective_cpus))
+ cs->sum_migrate_dl_bw += task->dl.dl_bw;
}
}
- if (!cs->nr_migrate_dl_tasks)
+ if (!cs->sum_migrate_dl_bw)
goto out_success;
- if (!cpumask_intersects(oldcs->effective_cpus, cs->effective_cpus)) {
- int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
-
- if (unlikely(cpu >= nr_cpu_ids)) {
- ret = -EINVAL;
- goto out_unlock;
- }
+ cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
+ if (unlikely(cpu >= nr_cpu_ids)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
- ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
- if (ret)
- goto out_unlock;
+ ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
+ if (ret)
+ goto out_unlock;
- cs->dl_bw_cpu = cpu;
- }
+ cs->dl_bw_cpu = cpu;
out_success:
/*
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index edca7849b165..7db4c87df83b 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -3107,20 +3107,18 @@ static void task_woken_dl(struct rq *rq, struct task_struct *p)
static void set_cpus_allowed_dl(struct task_struct *p,
struct affinity_context *ctx)
{
- struct root_domain *src_rd;
struct rq *rq;
WARN_ON_ONCE(!dl_task(p));
rq = task_rq(p);
- src_rd = rq->rd;
/*
* Migrating a SCHED_DEADLINE task between exclusive
* cpusets (different root_domains) entails a bandwidth
* update. We already made space for us in the destination
* domain (see cpuset_can_attach()).
*/
- if (!cpumask_intersects(src_rd->span, ctx->new_mask)) {
+ if (dl_task_needs_bw_move(p, ctx->new_mask)) {
struct dl_bw *src_dl_b;
src_dl_b = dl_bw_of(cpu_of(rq));
@@ -3137,6 +3135,15 @@ static void set_cpus_allowed_dl(struct task_struct *p,
set_cpus_allowed_common(p, ctx);
}
+bool dl_task_needs_bw_move(struct task_struct *p,
+ const struct cpumask *new_mask)
+{
+ if (!dl_task(p))
+ return false;
+
+ return !cpumask_intersects(task_rq(p)->rd->span, new_mask);
+}
+
/* Assumes rq->lock is held */
static void rq_online_dl(struct rq *rq)
{
--
2.43.0
^ permalink raw reply related
* [tj-cgroup:for-next] BUILD SUCCESS 22583369fc44382eae031fd25321967cda2d93eb
From: kernel test robot @ 2026-05-09 14:51 UTC (permalink / raw)
To: Tejun Heo; +Cc: cgroups
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git for-next
branch HEAD: 22583369fc44382eae031fd25321967cda2d93eb Merge branch 'for-7.2' into for-next
elapsed time: 726m
configs tested: 263
configs skipped: 55
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc allyesconfig gcc-15.2.0
arc defconfig gcc-15.2.0
arc randconfig-001 gcc-8.5.0
arc randconfig-001-20260509 gcc-8.5.0
arc randconfig-001-20260509 gcc-9.5.0
arc randconfig-002 gcc-8.5.0
arc randconfig-002-20260509 gcc-8.5.0
arc randconfig-002-20260509 gcc-9.5.0
arm allnoconfig clang-23
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm allyesconfig gcc-15.2.0
arm defconfig gcc-15.2.0
arm randconfig-001 gcc-8.5.0
arm randconfig-001-20260509 gcc-8.5.0
arm randconfig-001-20260509 gcc-9.5.0
arm randconfig-002 gcc-8.5.0
arm randconfig-002-20260509 gcc-8.5.0
arm randconfig-002-20260509 gcc-9.5.0
arm randconfig-003 gcc-8.5.0
arm randconfig-003-20260509 gcc-8.5.0
arm randconfig-003-20260509 gcc-9.5.0
arm randconfig-004 gcc-8.5.0
arm randconfig-004-20260509 gcc-8.5.0
arm randconfig-004-20260509 gcc-9.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260509 gcc-10.5.0
arm64 randconfig-002-20260509 gcc-10.5.0
arm64 randconfig-003-20260509 gcc-10.5.0
arm64 randconfig-004-20260509 gcc-10.5.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260509 gcc-10.5.0
csky randconfig-002-20260509 gcc-10.5.0
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260509 clang-17
hexagon randconfig-001-20260509 gcc-11.5.0
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260509 clang-17
hexagon randconfig-002-20260509 gcc-11.5.0
i386 allmodconfig clang-20
i386 allnoconfig gcc-14
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260509 gcc-14
i386 buildonly-randconfig-002-20260509 gcc-14
i386 buildonly-randconfig-003-20260509 gcc-14
i386 buildonly-randconfig-004-20260509 gcc-14
i386 buildonly-randconfig-005-20260509 gcc-14
i386 buildonly-randconfig-006-20260509 gcc-14
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260509 clang-20
i386 randconfig-002 gcc-14
i386 randconfig-002-20260509 clang-20
i386 randconfig-003 gcc-14
i386 randconfig-003-20260509 clang-20
i386 randconfig-004-20260509 clang-20
i386 randconfig-005 gcc-14
i386 randconfig-005-20260509 clang-20
i386 randconfig-006 gcc-14
i386 randconfig-006-20260509 clang-20
i386 randconfig-007 gcc-14
i386 randconfig-007-20260509 clang-20
i386 randconfig-007-20260509 gcc-14
i386 randconfig-011-20260509 gcc-14
i386 randconfig-012-20260509 gcc-14
i386 randconfig-013-20260509 gcc-14
i386 randconfig-014-20260509 gcc-14
i386 randconfig-015-20260509 gcc-14
i386 randconfig-016-20260509 gcc-14
i386 randconfig-017-20260509 gcc-14
loongarch allmodconfig clang-23
loongarch allnoconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260509 clang-17
loongarch randconfig-001-20260509 gcc-11.5.0
loongarch randconfig-001-20260509 gcc-15.2.0
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260509 clang-17
loongarch randconfig-002-20260509 gcc-11.5.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k allyesconfig gcc-15.2.0
m68k defconfig clang-19
m68k m5407c3_defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
mips ip32_defconfig clang-23
mips maltaup_xpa_defconfig gcc-15.2.0
nios2 allmodconfig clang-23
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-19
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260509 clang-17
nios2 randconfig-001-20260509 gcc-11.5.0
nios2 randconfig-001-20260509 gcc-15.2.0
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260509 clang-17
nios2 randconfig-002-20260509 gcc-11.5.0
nios2 randconfig-002-20260509 gcc-15.2.0
openrisc allmodconfig clang-23
openrisc allmodconfig gcc-11.5.0
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-15.2.0
parisc allyesconfig clang-19
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
parisc randconfig-001 gcc-11.5.0
parisc randconfig-001-20260509 gcc-11.5.0
parisc randconfig-002 gcc-11.5.0
parisc randconfig-002-20260509 gcc-11.5.0
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-15.2.0
powerpc eiger_defconfig clang-23
powerpc ppc64e_defconfig gcc-15.2.0
powerpc randconfig-001 gcc-11.5.0
powerpc randconfig-001-20260509 gcc-11.5.0
powerpc randconfig-002 gcc-11.5.0
powerpc randconfig-002-20260509 gcc-11.5.0
powerpc64 randconfig-001 gcc-11.5.0
powerpc64 randconfig-001-20260509 gcc-11.5.0
powerpc64 randconfig-002 gcc-11.5.0
powerpc64 randconfig-002-20260509 gcc-11.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001-20260509 clang-23
riscv randconfig-002-20260509 clang-23
s390 allmodconfig clang-18
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001-20260509 clang-23
s390 randconfig-002-20260509 clang-23
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allnoconfig gcc-15.2.0
sh allyesconfig clang-19
sh allyesconfig gcc-15.2.0
sh defconfig gcc-14
sh dreamcast_defconfig gcc-15.2.0
sh randconfig-001-20260509 clang-23
sh randconfig-002-20260509 clang-23
sh shx3_defconfig gcc-15.2.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-15.2.0
sparc defconfig gcc-15.2.0
sparc randconfig-001 clang-23
sparc randconfig-001-20260509 clang-23
sparc randconfig-002 clang-23
sparc randconfig-002-20260509 clang-23
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001 clang-23
sparc64 randconfig-001-20260509 clang-23
sparc64 randconfig-002 clang-23
sparc64 randconfig-002-20260509 clang-23
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001 clang-23
um randconfig-001-20260509 clang-23
um randconfig-002 clang-23
um randconfig-002-20260509 clang-23
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260509 clang-20
x86_64 buildonly-randconfig-002-20260509 clang-20
x86_64 buildonly-randconfig-003-20260509 clang-20
x86_64 buildonly-randconfig-004-20260509 clang-20
x86_64 buildonly-randconfig-005-20260509 clang-20
x86_64 buildonly-randconfig-006-20260509 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001 clang-20
x86_64 randconfig-001 gcc-14
x86_64 randconfig-001-20260509 clang-20
x86_64 randconfig-001-20260509 gcc-14
x86_64 randconfig-002 clang-20
x86_64 randconfig-002 gcc-14
x86_64 randconfig-002-20260509 clang-20
x86_64 randconfig-002-20260509 gcc-14
x86_64 randconfig-003 clang-20
x86_64 randconfig-003-20260509 clang-20
x86_64 randconfig-003-20260509 gcc-14
x86_64 randconfig-004 clang-20
x86_64 randconfig-004-20260509 clang-20
x86_64 randconfig-004-20260509 gcc-14
x86_64 randconfig-005 clang-20
x86_64 randconfig-005 gcc-14
x86_64 randconfig-005-20260509 clang-20
x86_64 randconfig-005-20260509 gcc-14
x86_64 randconfig-006 clang-20
x86_64 randconfig-006-20260509 clang-20
x86_64 randconfig-006-20260509 gcc-14
x86_64 randconfig-011-20260509 gcc-14
x86_64 randconfig-012-20260509 gcc-14
x86_64 randconfig-013-20260509 gcc-14
x86_64 randconfig-014-20260509 gcc-14
x86_64 randconfig-015-20260509 gcc-14
x86_64 randconfig-016-20260509 gcc-14
x86_64 randconfig-071-20260509 clang-20
x86_64 randconfig-071-20260509 gcc-14
x86_64 randconfig-072-20260509 clang-20
x86_64 randconfig-072-20260509 gcc-14
x86_64 randconfig-073-20260509 clang-20
x86_64 randconfig-074-20260509 clang-20
x86_64 randconfig-075-20260509 clang-20
x86_64 randconfig-076-20260509 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig clang-23
xtensa allyesconfig gcc-11.5.0
xtensa allyesconfig gcc-15.2.0
xtensa randconfig-001 clang-23
xtensa randconfig-001-20260509 clang-23
xtensa randconfig-002 clang-23
xtensa randconfig-002-20260509 clang-23
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [tj-cgroup:for-7.2] BUILD SUCCESS 7ea04cc4fe3cee2139cc2474cadaecc7c53d986d
From: kernel test robot @ 2026-05-09 15:02 UTC (permalink / raw)
To: Tejun Heo; +Cc: cgroups
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git for-7.2
branch HEAD: 7ea04cc4fe3cee2139cc2474cadaecc7c53d986d selftests/cgroup: Fix incorrect variable check in online_cpus()
elapsed time: 738m
configs tested: 262
configs skipped: 56
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc allyesconfig gcc-15.2.0
arc defconfig gcc-15.2.0
arc randconfig-001 gcc-8.5.0
arc randconfig-001-20260509 gcc-8.5.0
arc randconfig-001-20260509 gcc-9.5.0
arc randconfig-002 gcc-8.5.0
arc randconfig-002-20260509 gcc-8.5.0
arc randconfig-002-20260509 gcc-9.5.0
arm allnoconfig clang-23
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm allyesconfig gcc-15.2.0
arm defconfig gcc-15.2.0
arm randconfig-001 gcc-8.5.0
arm randconfig-001-20260509 gcc-8.5.0
arm randconfig-001-20260509 gcc-9.5.0
arm randconfig-002 gcc-8.5.0
arm randconfig-002-20260509 gcc-8.5.0
arm randconfig-002-20260509 gcc-9.5.0
arm randconfig-003 gcc-8.5.0
arm randconfig-003-20260509 gcc-8.5.0
arm randconfig-003-20260509 gcc-9.5.0
arm randconfig-004 gcc-8.5.0
arm randconfig-004-20260509 gcc-8.5.0
arm randconfig-004-20260509 gcc-9.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260509 gcc-10.5.0
arm64 randconfig-002-20260509 gcc-10.5.0
arm64 randconfig-003-20260509 gcc-10.5.0
arm64 randconfig-004-20260509 gcc-10.5.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260509 gcc-10.5.0
csky randconfig-002-20260509 gcc-10.5.0
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260509 clang-17
hexagon randconfig-001-20260509 gcc-11.5.0
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260509 clang-17
hexagon randconfig-002-20260509 gcc-11.5.0
i386 allmodconfig clang-20
i386 allnoconfig gcc-14
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260509 gcc-14
i386 buildonly-randconfig-002-20260509 gcc-14
i386 buildonly-randconfig-003-20260509 gcc-14
i386 buildonly-randconfig-004-20260509 gcc-14
i386 buildonly-randconfig-005-20260509 gcc-14
i386 buildonly-randconfig-006-20260509 gcc-14
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260509 clang-20
i386 randconfig-002 gcc-14
i386 randconfig-002-20260509 clang-20
i386 randconfig-003 gcc-14
i386 randconfig-003-20260509 clang-20
i386 randconfig-004-20260509 clang-20
i386 randconfig-005 gcc-14
i386 randconfig-005-20260509 clang-20
i386 randconfig-006 gcc-14
i386 randconfig-006-20260509 clang-20
i386 randconfig-007 gcc-14
i386 randconfig-007-20260509 clang-20
i386 randconfig-007-20260509 gcc-14
i386 randconfig-011-20260509 gcc-14
i386 randconfig-012-20260509 gcc-14
i386 randconfig-013-20260509 gcc-14
i386 randconfig-014-20260509 gcc-14
i386 randconfig-015-20260509 gcc-14
i386 randconfig-016-20260509 gcc-14
i386 randconfig-017-20260509 gcc-14
loongarch allmodconfig clang-23
loongarch allnoconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260509 clang-17
loongarch randconfig-001-20260509 gcc-11.5.0
loongarch randconfig-001-20260509 gcc-15.2.0
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260509 clang-17
loongarch randconfig-002-20260509 gcc-11.5.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k allyesconfig gcc-15.2.0
m68k defconfig clang-19
m68k m5407c3_defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
mips ip32_defconfig clang-23
mips maltaup_xpa_defconfig gcc-15.2.0
nios2 allmodconfig clang-23
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-19
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260509 clang-17
nios2 randconfig-001-20260509 gcc-11.5.0
nios2 randconfig-001-20260509 gcc-15.2.0
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260509 clang-17
nios2 randconfig-002-20260509 gcc-11.5.0
nios2 randconfig-002-20260509 gcc-15.2.0
openrisc allmodconfig clang-23
openrisc allmodconfig gcc-11.5.0
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-15.2.0
parisc allyesconfig clang-19
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
parisc randconfig-001 gcc-11.5.0
parisc randconfig-001-20260509 gcc-11.5.0
parisc randconfig-002 gcc-11.5.0
parisc randconfig-002-20260509 gcc-11.5.0
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-15.2.0
powerpc eiger_defconfig clang-23
powerpc ppc64e_defconfig gcc-15.2.0
powerpc randconfig-001 gcc-11.5.0
powerpc randconfig-001-20260509 gcc-11.5.0
powerpc randconfig-002 gcc-11.5.0
powerpc randconfig-002-20260509 gcc-11.5.0
powerpc64 randconfig-001 gcc-11.5.0
powerpc64 randconfig-001-20260509 gcc-11.5.0
powerpc64 randconfig-002 gcc-11.5.0
powerpc64 randconfig-002-20260509 gcc-11.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001-20260509 clang-23
riscv randconfig-002-20260509 clang-23
s390 allmodconfig clang-18
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001-20260509 clang-23
s390 randconfig-002-20260509 clang-23
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allnoconfig gcc-15.2.0
sh allyesconfig clang-19
sh allyesconfig gcc-15.2.0
sh defconfig gcc-14
sh dreamcast_defconfig gcc-15.2.0
sh randconfig-001-20260509 clang-23
sh randconfig-002-20260509 clang-23
sh shx3_defconfig gcc-15.2.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-15.2.0
sparc defconfig gcc-15.2.0
sparc randconfig-001 clang-23
sparc randconfig-001-20260509 clang-23
sparc randconfig-002 clang-23
sparc randconfig-002-20260509 clang-23
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001 clang-23
sparc64 randconfig-001-20260509 clang-23
sparc64 randconfig-002 clang-23
sparc64 randconfig-002-20260509 clang-23
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001 clang-23
um randconfig-001-20260509 clang-23
um randconfig-002 clang-23
um randconfig-002-20260509 clang-23
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260509 clang-20
x86_64 buildonly-randconfig-002-20260509 clang-20
x86_64 buildonly-randconfig-003-20260509 clang-20
x86_64 buildonly-randconfig-004-20260509 clang-20
x86_64 buildonly-randconfig-005-20260509 clang-20
x86_64 buildonly-randconfig-006-20260509 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001 clang-20
x86_64 randconfig-001 gcc-14
x86_64 randconfig-001-20260509 clang-20
x86_64 randconfig-001-20260509 gcc-14
x86_64 randconfig-002 clang-20
x86_64 randconfig-002 gcc-14
x86_64 randconfig-002-20260509 clang-20
x86_64 randconfig-002-20260509 gcc-14
x86_64 randconfig-003 clang-20
x86_64 randconfig-003-20260509 clang-20
x86_64 randconfig-003-20260509 gcc-14
x86_64 randconfig-004 clang-20
x86_64 randconfig-004-20260509 clang-20
x86_64 randconfig-004-20260509 gcc-14
x86_64 randconfig-005 clang-20
x86_64 randconfig-005 gcc-14
x86_64 randconfig-005-20260509 clang-20
x86_64 randconfig-005-20260509 gcc-14
x86_64 randconfig-006 clang-20
x86_64 randconfig-006-20260509 clang-20
x86_64 randconfig-006-20260509 gcc-14
x86_64 randconfig-011-20260509 gcc-14
x86_64 randconfig-012-20260509 gcc-14
x86_64 randconfig-013-20260509 gcc-14
x86_64 randconfig-014-20260509 gcc-14
x86_64 randconfig-015-20260509 gcc-14
x86_64 randconfig-016-20260509 gcc-14
x86_64 randconfig-071-20260509 clang-20
x86_64 randconfig-071-20260509 gcc-14
x86_64 randconfig-072-20260509 clang-20
x86_64 randconfig-072-20260509 gcc-14
x86_64 randconfig-073-20260509 clang-20
x86_64 randconfig-074-20260509 clang-20
x86_64 randconfig-075-20260509 clang-20
x86_64 randconfig-076-20260509 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig clang-23
xtensa allyesconfig gcc-11.5.0
xtensa randconfig-001 clang-23
xtensa randconfig-001-20260509 clang-23
xtensa randconfig-002 clang-23
xtensa randconfig-002-20260509 clang-23
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [LSF/MM/BPF TOPIC] Private Memory Nodes - follow up
From: Gregory Price @ 2026-05-09 16:38 UTC (permalink / raw)
To: lsf-pc
Cc: linux-kernel, linux-cxl, cgroups, linux-mm, linux-trace-kernel,
damon, kernel-team, gregkh, rafael, dakr, dave, jonathan.cameron,
dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
dan.j.williams, longman, akpm, david, lorenzo.stoakes,
Liam.Howlett, vbabka, rppt, surenb, mhocko, osalvador, ziy,
matthew.brost, joshua.hahnjy, rakie.kim, byungchul, ying.huang,
apopple, axelrasmussen, yuanchu, weixugc, yury.norov, linux,
mhiramat, mathieu.desnoyers, tj, hannes, mkoutny, jackmanb, sj,
baolin.wang, npache, ryan.roberts, dev.jain, baohua, lance.yang,
muchun.song, xu.xin16, chengming.zhou, jannh, linmiaohe,
nao.horiguchi, pfalcato, rientjes, shakeel.butt, riel, harry.yoo,
cl, roman.gushchin, chrisl, kasong, shikemeng, nphamcs, bhe,
zhengqi.arch, terry.bowman
In-Reply-To: <20260222084842.1824063-1-gourry@gourry.net>
Just wanting to follow up post-conference with a few major take-aways
since I will be a bit sparse during May / Early June (so want to not
forget, and garner a bit of input on the notes).
If you just want the tl;dr:
0) naming: private -> managed
1) remove global general "possible" and "online" node lists
2) add consistency with "normal" nodes, by opting them all in
to all the new things, and just making that the new normal.
e.g.: node_is_private_managed -> node_is_lru_eligible
3) Have __init add init time nodes to all the lists
Otherwise service/owner must add/enable services.
4) Make folio checks just way more explicit per service
e.g.: folio_is_private_managed -> folio_is_ksm_eligible
5) I still think w/o __GFP_PRIVATE this will still be too fragile,
but we're going to give it a try.
6) No callbacks in the MVP
7) MVP will be, essentially, Buddy + MBind support
Otherwise, more notes below.
~Gregory
<wall of text>
0) Naming is hard. Willy and Liam expressed concern over "private".
We briefly discussed "Managed"
This results in the following changes:
- if (folio_is_zone_device(folio))
+ if (folio_is_managed(folio))
and
+ if (node_is_managed(nid))
and
- N_MEMORY_PRIVATE
+ N_MEMORY_MANAGED
I'm less enthused the last one, but i'm ok with it.
1) There is a desire to fix possible / online node masks to avoid
bad patterns, and maybe to audit existing nodemask users.
there's one UAPI issue with this, and that that these masks
are exposed to userland by nature of existing node attributes
(N_MEMORY, N_CPU, N_POSSIBLE, etc).
I'm considering a name change from `possible` -> `init`, because
that's mostly how it is used (initialize some set of per-node
resources during __init, not at runtime). Externally, this set
would still be reported to uapi as possible.
2) There was concern about inconsistency towards nodes.
Along the lines of #1 - I'm thinking about actually adding explicit
service nodelists, which are populated at boot by __init, and by
hotplug if it's a general purpose node.
So we'd end up with things like:
for_each_ksm_node
for_each_lru_node
for_each_x_node
And we would retire such general defines like
for_each_node
for_each_online_node
For any "normal" node, it lands in all the lists.
For the buddy, we would have
for_buddy_node
For the default buddy-node list, and otherwise "managed" nodes would
still be removed from the standard fallback lists.
This means these nodes cannot be reached via nodemask arguments, and
can only be reached by `alloc_pages_node(nid, ...)` nid argument.
I *think* might resolve __GFP_PRIVATE.
But it's still dependent on system-wide for_each good behavior.
3) How do private nodes get into the lists in the new system?
For any private node, the registering driver (owner) and the managing
service are responsible for adding/removing the nodes from the list.
Example workflow:
0) CXL driver hotplug: add_memory_driver_managed(..., nid, owner)
a) owner=NULL means general purpose node
b) otherwise, reserve nid and (pgdat->owner = owner)
1) hotplug memory onto the node
a) if node is normal, add to all service lists
b) if node is "managed" (private), omit from all lists
2) CXL driver registers node with specific services, e.g.:
cram_register_node(..., nid, owner);
3) Service sets node enabled in appropriate node list, and starts
any appropriate services (kswapd, kcompactd, etc) for that node.
In some cases, nodes would have individual mappings onto services
(cram), in other cases the intent would be to have the memory
otherwise treated as general-purpose, but with special access
patterns (e.g. an LRU node not marked N_MEMORY).
4) There are still concerns about random hooks around the kernel.
My thought is to make this less "random", and more a change
in the way we think about folio operations / node operations
for ALL nodes.
ZONE_DEVICE has a bunch of implicit filtering due to not being
on the LRU - but the intent is to allow flexible LRU membership.
So what if we just made these checks much more explict overall
if (folio_is_ksm_eligible(folio)) /* can be merged */
if (folio_is_lru_eligible(folio)) /* managed by lru services */
if (folio_is_demotion_eligible(folio)) /* demotion target */
if (folio_is_mbind_eligible(folio)) /* can be an mbind target */
Rather than rathole over what the set of bits should be, i think it's
more important to determine what the actual operation here will be.
right now I have this defined as essentially:
folio_pgdat(folio)->private.ops.mask & NP_OPT_KSM
But if we generalize to all nodes / all features, it's essentially
a per-pgdat bitmask lookup:
bool folio_is_ksm_eligible(folio)) {
return test_bit(N_FEATURE_KSM, folio_pgdat(folio)->features);
}
With the bonus that all ZONE_DEVICE hooks can be sunk into these
checks, so there are many places in mm/ where this becomes essentially
a single-line change.
5) Lacking __GFP_PRIVATE, I have concern over fragility.
Previously, __GFP_PRIVATE created a "default opt-out" mechanism.
I *think* the above nodelist changes, specifically removing:
for_each_node()
for_each_online_node()
for_each_node_with_cpus()
The problem I foresee is with existing node_state masks, like
node_state((node), N_POSSIBLE)
node_state((node), N_CPU)
This might be tractable, but it may also simply be too fragile.
Right now only 3 or 4 locations use node_state() outside mm/, and
I'm tempted to try to sink these into mm/internal.h instead of
include/linux/nodemask.h. If that becomes unpalletable, then I will
lobby for __GFP_PRIVATE again (I may still anyway :P).
6) No callbacks by default, but nothing technically prevents it.
I was already in the process of killing this. I think mmu_notifier
does *most* of what the callbacks where doing anyway, so we can
probably collapse that.
7) David asked me to limit the MVP to Buddy + MBind support.
There's some odd interactions with pagecache, so that might evolve
too (may not be able to reliably fault a file directly onto a private
node, tbd - mempolicy does not apply to page cache faults, so it's
just unreliable).
</wall of text>
~Gregory
^ permalink raw reply
* [PATCH 0/3] security, sched: Expand task_setscheduler LSM hook and related fixes
From: Aaron Tomlin @ 2026-05-09 16:48 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
Hi,
This series expands the task_setscheduler LSM hook to include the requested
CPU affinity mask, enabling BPF-based security modules to enforce strict
spatial isolation boundaries. During the development of this expansion, two
pre-existing subsystem bugs were identified and fixed.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. Currently, the task_setscheduler hook lacks visibility
into the actual CPU affinity mask being requested via sched_setaffinity()
or cgroup migrations. This limits the effectiveness of eBPF-driven security
policies when attempting to monitor and shield specific cores.
By expanding the LSM hook signature, BPF LSMs are provided with the
necessary context to audit and even restrict specific CPU pinning requests.
Patch 1 (cgroup/cpuset): Fixes a pre-existing deadline (DL) bandwidth
metric leak in cpuset_can_attach(). It was discovered that if a task
fails its security checks mid-batch during a thread group migration,
the loop aborts without unwinding previously accumulated DL metrics
(nr_migrate_dl_tasks and sum_migrate_dl_bw). This patch introduces an
out_unlock_reset path to guarantee clean unwinding.
Patch 2 (security): Implements the core LSM hook expansion. It safely
propagates either the requested cpumask (via sched_setaffinity and
cpuset_can_attach) or passes NULL for unchanged affinities. It also
adds proper __nullable annotations to ensure the BPF verifier mandates
explicit NULL checks for attached eBPF programs, and mechanically
updates SELinux, Smack, and Commoncap.
Patch 3 (mips): Resolves a critical memory corruption vulnerability in
the MIPS MT architecture's sched_setaffinity implementation. When
CONFIG_CPUMASK_OFFSTACK=y is enabled, copy_from_user() was clobbering
the stack pointer due to an invalid sizeof() evaluation, followed by an
uninitialised heap allocation. This patch safely reorders the
allocations and properly utilises cpumask_size().
These patches have been logically separated to assist subsystem maintainers
with review and backporting.
Comments and feedback are welcome.
Kind regards,
Aaron Tomlin (3):
cgroup/cpuset: Fix deadline bandwidth leak in cpuset_can_attach()
security: Expand task_setscheduler LSM hook to include CPU affinity
mask
mips: sched: Fix CPUMASK_OFFSTACK memory corruption
arch/mips/kernel/mips-mt-fpaff.c | 41 ++++++++++++++++----------------
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++----
kernel/cgroup/cpuset.c | 13 ++++++----
kernel/sched/syscalls.c | 4 ++--
security/commoncap.c | 7 ++++--
security/security.c | 11 +++++----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 +++++++--
10 files changed, 64 insertions(+), 42 deletions(-)
--
2.51.0
^ permalink raw reply
* [PATCH 1/3] cgroup/cpuset: Fix deadline bandwidth leak in cpuset_can_attach()
From: Aaron Tomlin @ 2026-05-09 16:48 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509164847.939294-1-atomlin@atomlin.com>
During a cgroup migration, cpuset_can_attach() iterates over the
provided taskset. If a task within the batch is a deadline (DL) task,
the destination cpuset's DL metrics (i.e., nr_migrate_dl_tasks and
sum_migrate_dl_bw) are appropriately incremented.
However, if a subsequent task in the same migration batch fails the
task_can_attach() check, the loop aborts and jumps directly to
out_unlock. Consequently, any DL metrics accumulated from previously
processed tasks in the batch remain permanently inflated in the
destination cpuset. Because the migration is subsequently aborted by the
cgroup core, cpuset_cancel_attach() is never invoked to unwind these
specific increments.
This behaviour results in a permanent leak of deadline bandwidth, which
incorrectly restricts the admission control capacity of the destination
cpuset.
To resolve this, introduce an out_unlock_reset failure path that
conditionally invokes reset_migrate_dl_data(). This guarantees that if a
batch migration is aborted for any reason, the pending DL metrics are
safely reset before returning the error.
Fixes: 0a67b847e1f06 ("cpuset: Allow setscheduler regardless of manipulated task")
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
kernel/cgroup/cpuset.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index e3a081a07c6d..b8022f6e2a35 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3029,12 +3029,12 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
cgroup_taskset_for_each(task, css, tset) {
ret = task_can_attach(task);
if (ret)
- goto out_unlock;
+ goto out_unlock_reset;
if (setsched_check) {
ret = security_task_setscheduler(task);
if (ret)
- goto out_unlock;
+ goto out_unlock_reset;
}
if (dl_task(task)) {
@@ -3070,6 +3070,11 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
* changes which zero cpus/mems_allowed.
*/
cs->attach_in_progress++;
+ goto out_unlock;
+
+out_unlock_reset:
+ if (cs->nr_migrate_dl_tasks)
+ reset_migrate_dl_data(cs);
out_unlock:
mutex_unlock(&cpuset_mutex);
return ret;
--
2.51.0
^ permalink raw reply related
* [PATCH 2/3] security: Expand task_setscheduler LSM hook to include CPU affinity mask
From: Aaron Tomlin @ 2026-05-09 16:48 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509164847.939294-1-atomlin@atomlin.com>
At present, the task_setscheduler LSM hook provides security modules
with the opportunity to mediate changes to a task's scheduling policy.
However, when invoked via sched_setaffinity(), the hook lacks
visibility into the actual CPU affinity mask being requested.
Consequently, BPF-based security modules are entirely blind to the
target CPUs and cannot make granular access control decisions based on
spatial isolation.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. The inability to audit or restrict specific CPU
pinning requests limits the effectiveness of eBPF-driven security
policies, particularly when attempting to shield isolated or
cryptographic cores from unprivileged or compromised tasks.
This patch expands the security_task_setscheduler() hook signature to
include a pointer to the requested cpumask. Because this is a shared
hook used for multiple scheduling attribute changes, call sites that do
not modify CPU affinity are updated to safely pass NULL.
To protect against unverified dereferences, the parameter is annotated
with __nullable in the LSM hook definition, ensuring the BPF verifier
mandates explicit NULL checks for attached eBPF programs.
This change updates all in-tree security modules (SELinux and Smack) to
accommodate the new parameter mechanically, whilst providing BPF LSMs
with the necessary context to enforce strict affinity policies.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
arch/mips/kernel/mips-mt-fpaff.c | 2 +-
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++++----
kernel/cgroup/cpuset.c | 4 ++--
kernel/sched/syscalls.c | 4 ++--
security/commoncap.c | 7 +++++--
security/security.c | 11 ++++++-----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 +++++++++--
10 files changed, 37 insertions(+), 21 deletions(-)
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 10172fc4f627..a6a61393fc1a 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -108,7 +108,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
goto out_unlock;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, new_mask);
if (retval)
goto out_unlock;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d9acfa89c894..ac4096958a00 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2619,7 +2619,7 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
}
rcu_read_unlock();
- err = security_task_setscheduler(p);
+ err = security_task_setscheduler(p, NULL);
if (err) {
count = err;
goto out;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..6ec7bc04a1b7 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -255,7 +255,8 @@ LSM_HOOK(int, 0, task_prlimit, const struct cred *cred,
const struct cred *tcred, unsigned int flags)
LSM_HOOK(int, 0, task_setrlimit, struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim)
-LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p)
+LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p,
+ const struct cpumask *in_mask__nullable)
LSM_HOOK(int, 0, task_getscheduler, struct task_struct *p)
LSM_HOOK(int, 0, task_movememory, struct task_struct *p)
LSM_HOOK(int, 0, task_kill, struct task_struct *p, struct kernel_siginfo *info,
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..8b74153daa43 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -196,7 +196,8 @@ extern int cap_mmap_addr(unsigned long addr);
extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
-extern int cap_task_setscheduler(struct task_struct *p);
+extern int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
@@ -531,7 +532,8 @@ int security_task_prlimit(const struct cred *cred, const struct cred *tcred,
unsigned int flags);
int security_task_setrlimit(struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim);
-int security_task_setscheduler(struct task_struct *p);
+int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
int security_task_getscheduler(struct task_struct *p);
int security_task_movememory(struct task_struct *p);
int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
@@ -1392,9 +1394,10 @@ static inline int security_task_setrlimit(struct task_struct *p,
return 0;
}
-static inline int security_task_setscheduler(struct task_struct *p)
+static inline int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask)
{
- return cap_task_setscheduler(p);
+ return cap_task_setscheduler(p, in_mask);
}
static inline int security_task_getscheduler(struct task_struct *p)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b8022f6e2a35..68cf89b17af2 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3032,7 +3032,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
goto out_unlock_reset;
if (setsched_check) {
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, cs->effective_cpus);
if (ret)
goto out_unlock_reset;
}
@@ -3592,7 +3592,7 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
if (ret)
goto out_unlock;
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, NULL);
if (ret)
goto out_unlock;
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index b215b0ead9a6..68bc7e466fb1 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -540,7 +540,7 @@ int __sched_setscheduler(struct task_struct *p,
if (attr->sched_flags & SCHED_FLAG_SUGOV)
return -EINVAL;
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, NULL);
if (retval)
return retval;
}
@@ -1213,7 +1213,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
return -EPERM;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, in_mask);
if (retval)
return retval;
diff --git a/security/commoncap.c b/security/commoncap.c
index 3399535808fe..d86f1c2b9210 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1222,13 +1222,16 @@ static int cap_safe_nice(struct task_struct *p)
/**
* cap_task_setscheduler - Determine if scheduler policy change is permitted
* @p: The task to affect
+ * @in_mask: Requested CPU affinity mask (ignored)
*
* Determine if the requested scheduler policy change is permitted for the
- * specified task.
+ * specified task. The capabilities security module does not evaluate the
+ * @in_mask parameter, relying solely on cap_safe_nice().
*
* Return: 0 if permission is granted, -ve if denied.
*/
-int cap_task_setscheduler(struct task_struct *p)
+int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return cap_safe_nice(p);
}
diff --git a/security/security.c b/security/security.c
index 4e999f023651..53804ee40df5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3240,17 +3240,18 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
}
/**
- * security_task_setscheduler() - Check if setting sched policy/param is allowed
+ * security_task_setscheduler() - Check if setting sched policy/param/affinity is allowed
* @p: target task
+ * @in_mask: requested CPU affinity mask, or NULL if not changing affinity
*
- * Check permission before setting scheduling policy and/or parameters of
- * process @p.
+ * Check permission before setting the scheduling policy, parameters, and/or
+ * CPU affinity of process @p.
*
* Return: Returns 0 if permission is granted.
*/
-int security_task_setscheduler(struct task_struct *p)
+int security_task_setscheduler(struct task_struct *p, const struct cpumask *in_mask)
{
- return call_int_hook(task_setscheduler, p);
+ return call_int_hook(task_setscheduler, p, in_mask);
}
/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0f704380a8c8..5f0914db23f6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4557,7 +4557,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
return 0;
}
-static int selinux_task_setscheduler(struct task_struct *p)
+static int selinux_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3f9ae05039a2..a77143beff44 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2343,10 +2343,17 @@ static int smack_task_getioprio(struct task_struct *p)
/**
* smack_task_setscheduler - Smack check on setting scheduler
* @p: the task object
+ * @in_mask: Requested CPU affinity mask (ignored)
*
- * Return 0 if read access is permitted
+ * Evaluate whether the current task has write access to the target task @p
+ * to change its scheduling policy. The Smack security module relies
+ * strictly on label-based access control and does not evaluate CPU
+ * affinity masks.
+ *
+ * Return: 0 if write access is permitted
*/
-static int smack_task_setscheduler(struct task_struct *p)
+static int smack_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
--
2.51.0
^ permalink raw reply related
* [PATCH 3/3] mips: sched: Fix CPUMASK_OFFSTACK memory corruption
From: Aaron Tomlin @ 2026-05-09 16:48 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509164847.939294-1-atomlin@atomlin.com>
This patch addresses a critical memory management flaw.
When CONFIG_CPUMASK_OFFSTACK is enabled, cpumask_var_t is a pointer.
Consequently, sizeof(new_mask) evaluates to the pointer size, causing
copy_from_user() to clobber the stack pointer. The subsequent
alloc_cpumask_var() overwrites this with an uninitialised heap address,
discarding the user's mask and risking data leaks. Fix this by
allocating masks first, and using cpumask_size() to copy data directly
into the allocated buffer.
Additionally, reorder the failure goto labels to ensure task locks and
memory allocations are cleanly unwound.
Fixes: 295cbf6d63165 ("[MIPS] Move FPU affinity code into separate file.")
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
arch/mips/kernel/mips-mt-fpaff.c | 39 ++++++++++++++++----------------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index a6a61393fc1a..4b3424088302 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -71,11 +71,23 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
struct task_struct *p;
int retval;
- if (len < sizeof(new_mask))
+ if (len < cpumask_size())
return -EINVAL;
- if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
- return -EFAULT;
+ if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL))
+ return -ENOMEM;
+ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
+ retval = -ENOMEM;
+ goto out_free_cpus_allowed;
+ }
+ if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
+ retval = -ENOMEM;
+ goto out_free_new_mask;
+ }
+
+ retval = -EFAULT;
+ if (copy_from_user(new_mask, user_mask_ptr, cpumask_size()))
+ goto out_free_effective_mask;
cpus_read_lock();
rcu_read_lock();
@@ -84,25 +96,14 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
if (!p) {
rcu_read_unlock();
cpus_read_unlock();
- return -ESRCH;
+ retval = -ESRCH;
+ goto out_free_effective_mask;
}
/* Prevent p going away */
get_task_struct(p);
rcu_read_unlock();
- if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_put_task;
- }
- if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_free_cpus_allowed;
- }
- if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_free_new_mask;
- }
if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
retval = -EPERM;
goto out_unlock;
@@ -141,14 +142,14 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
}
}
out_unlock:
+ put_task_struct(p);
+ cpus_read_unlock();
+out_free_effective_mask:
free_cpumask_var(effective_mask);
out_free_new_mask:
free_cpumask_var(new_mask);
out_free_cpus_allowed:
free_cpumask_var(cpus_allowed);
-out_put_task:
- put_task_struct(p);
- cpus_read_unlock();
return retval;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 2/3] security: Expand task_setscheduler LSM hook to include CPU affinity mask
From: Aaron Tomlin @ 2026-05-09 18:29 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, neelx, sean, chjohnst, steve,
mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509164847.939294-3-atomlin@atomlin.com>
[-- Attachment #1: Type: text/plain, Size: 519 bytes --]
On Sat, May 09, 2026 at 12:48:46PM -0400, Aaron Tomlin wrote:
> @@ -3592,7 +3592,7 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
> if (ret)
> goto out_unlock;
>
> - ret = security_task_setscheduler(task);
> + ret = security_task_setscheduler(task, NULL);
> if (ret)
> goto out_unlock;
>
Apologies, we want the CPU affinity mask here too. The NULL should be
replaced with cs->effective_cpus. This will be addressed in the next
iteration.
--
Aaron Tomlin
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v2 0/3] security, sched: Expand task_setscheduler LSM hook and related fixes
From: Aaron Tomlin @ 2026-05-09 21:37 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
Hi,
This series expands the task_setscheduler LSM hook to include the requested
CPU affinity mask, enabling BPF-based security modules to enforce strict
spatial isolation boundaries. During the development of this expansion, two
pre-existing subsystem bugs were identified and fixed.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. Currently, the task_setscheduler hook lacks visibility
into the actual CPU affinity mask being requested via sched_setaffinity()
or cgroup migrations. This limits the effectiveness of eBPF-driven security
policies when attempting to monitor and shield specific cores.
By expanding the LSM hook signature, BPF LSMs are provided with the
necessary context to audit and even restrict specific CPU pinning requests.
Patch 1 (cgroup/cpuset): Fixes a pre-existing deadline (DL) bandwidth
metric leak in cpuset_can_attach(). It was discovered that if a task
fails its security checks mid-batch during a thread group migration,
the loop aborts without unwinding previously accumulated DL metrics
(nr_migrate_dl_tasks and sum_migrate_dl_bw). This patch introduces an
out_unlock_reset path to guarantee clean unwinding.
Patch 2 (security): Implements the core LSM hook expansion. It safely
propagates either the requested cpumask (via sched_setaffinity and
cpuset_can_attach) or passes NULL for unchanged affinities. It also
adds proper __nullable annotations to ensure the BPF verifier mandates
explicit NULL checks for attached eBPF programs, and mechanically
updates SELinux, Smack, and Commoncap.
Patch 3 (mips): Resolves a critical memory corruption vulnerability in
the MIPS MT architecture's sched_setaffinity implementation. When
CONFIG_CPUMASK_OFFSTACK=y is enabled, copy_from_user() was clobbering
the stack pointer due to an invalid sizeof() evaluation, followed by an
uninitialised heap allocation. This patch safely reorders the
allocations and properly utilises cpumask_size().
These patches have been logically separated to assist subsystem maintainers
with review and backporting.
Comments and feedback are welcome.
Kind regards,
Changes since v1 [1]:
- Reordered the allocation and user-copy of new_mask in the MIPS
architecture's mipsmt_sys_sched_setaffinity() to occur before the
LSM hook is invoked. This ensures the security modules evaluate a fully
populated mask rather than uninitialised memory, while cleanly handling
error unwinding
- Updated cpuset_can_fork() to pass the destination cpuset's effective CPU
mask instead of NULL
[1]: https://lore.kernel.org/lkml/20260509164847.939294-1-atomlin@atomlin.com/
Aaron Tomlin (3):
cgroup/cpuset: Fix deadline bandwidth leak in cpuset_can_attach()
security: Expand task_setscheduler LSM hook to include CPU affinity
mask
mips: sched: Fix CPUMASK_OFFSTACK memory corruption
arch/mips/kernel/mips-mt-fpaff.c | 46 +++++++++++++++++---------------
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++---
kernel/cgroup/cpuset.c | 13 ++++++---
kernel/sched/syscalls.c | 4 +--
security/commoncap.c | 7 +++--
security/security.c | 11 ++++----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 ++++++--
10 files changed, 67 insertions(+), 44 deletions(-)
--
2.51.0
^ permalink raw reply
* [PATCH v2 0/3] security, sched: Expand task_setscheduler LSM hook and related fixes
From: Aaron Tomlin @ 2026-05-09 21:38 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509213803.968464-1-atomlin@atomlin.com>
Hi,
This series expands the task_setscheduler LSM hook to include the requested
CPU affinity mask, enabling BPF-based security modules to enforce strict
spatial isolation boundaries. During the development of this expansion, two
pre-existing subsystem bugs were identified and fixed.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. Currently, the task_setscheduler hook lacks visibility
into the actual CPU affinity mask being requested via sched_setaffinity()
or cgroup migrations. This limits the effectiveness of eBPF-driven security
policies when attempting to monitor and shield specific cores.
By expanding the LSM hook signature, BPF LSMs are provided with the
necessary context to audit and even restrict specific CPU pinning requests.
Patch 1 (cgroup/cpuset): Fixes a pre-existing deadline (DL) bandwidth
metric leak in cpuset_can_attach(). It was discovered that if a task
fails its security checks mid-batch during a thread group migration,
the loop aborts without unwinding previously accumulated DL metrics
(nr_migrate_dl_tasks and sum_migrate_dl_bw). This patch introduces an
out_unlock_reset path to guarantee clean unwinding.
Patch 2 (security): Implements the core LSM hook expansion. It safely
propagates either the requested cpumask (via sched_setaffinity and
cpuset_can_attach) or passes NULL for unchanged affinities. It also
adds proper __nullable annotations to ensure the BPF verifier mandates
explicit NULL checks for attached eBPF programs, and mechanically
updates SELinux, Smack, and Commoncap.
Patch 3 (mips): Resolves a critical memory corruption vulnerability in
the MIPS MT architecture's sched_setaffinity implementation. When
CONFIG_CPUMASK_OFFSTACK=y is enabled, copy_from_user() was clobbering
the stack pointer due to an invalid sizeof() evaluation, followed by an
uninitialised heap allocation. This patch safely reorders the
allocations and properly utilises cpumask_size().
These patches have been logically separated to assist subsystem maintainers
with review and backporting.
Comments and feedback are welcome.
Kind regards,
Changes since v1 [1]:
- Reordered the allocation and user-copy of new_mask in the MIPS
architecture's mipsmt_sys_sched_setaffinity() to occur before the
LSM hook is invoked. This ensures the security modules evaluate a fully
populated mask rather than uninitialised memory, while cleanly handling
error unwinding
- Updated cpuset_can_fork() to pass the destination cpuset's effective CPU
mask instead of NULL
[1]: https://lore.kernel.org/lkml/20260509164847.939294-1-atomlin@atomlin.com/
Aaron Tomlin (3):
cgroup/cpuset: Fix deadline bandwidth leak in cpuset_can_attach()
security: Expand task_setscheduler LSM hook to include CPU affinity
mask
mips: sched: Fix CPUMASK_OFFSTACK memory corruption
arch/mips/kernel/mips-mt-fpaff.c | 46 +++++++++++++++++---------------
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++---
kernel/cgroup/cpuset.c | 13 ++++++---
kernel/sched/syscalls.c | 4 +--
security/commoncap.c | 7 +++--
security/security.c | 11 ++++----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 ++++++--
10 files changed, 67 insertions(+), 44 deletions(-)
--
2.51.0
^ permalink raw reply
* [PATCH v2 1/3] cgroup/cpuset: Fix deadline bandwidth leak in cpuset_can_attach()
From: Aaron Tomlin @ 2026-05-09 21:38 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509213803.968464-1-atomlin@atomlin.com>
During a cgroup migration, cpuset_can_attach() iterates over the
provided taskset. If a task within the batch is a deadline (DL) task,
the destination cpuset's DL metrics (i.e., nr_migrate_dl_tasks and
sum_migrate_dl_bw) are appropriately incremented.
However, if a subsequent task in the same migration batch fails the
task_can_attach() check, the loop aborts and jumps directly to
out_unlock. Consequently, any DL metrics accumulated from previously
processed tasks in the batch remain permanently inflated in the
destination cpuset. Because the migration is subsequently aborted by the
cgroup core, cpuset_cancel_attach() is never invoked to unwind these
specific increments.
This behaviour results in a permanent leak of deadline bandwidth, which
incorrectly restricts the admission control capacity of the destination
cpuset.
To resolve this, introduce an out_unlock_reset failure path that
conditionally invokes reset_migrate_dl_data(). This guarantees that if a
batch migration is aborted for any reason, the pending DL metrics are
safely reset before returning the error.
Fixes: 0a67b847e1f06 ("cpuset: Allow setscheduler regardless of manipulated task")
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
kernel/cgroup/cpuset.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index e3a081a07c6d..b8022f6e2a35 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3029,12 +3029,12 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
cgroup_taskset_for_each(task, css, tset) {
ret = task_can_attach(task);
if (ret)
- goto out_unlock;
+ goto out_unlock_reset;
if (setsched_check) {
ret = security_task_setscheduler(task);
if (ret)
- goto out_unlock;
+ goto out_unlock_reset;
}
if (dl_task(task)) {
@@ -3070,6 +3070,11 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
* changes which zero cpus/mems_allowed.
*/
cs->attach_in_progress++;
+ goto out_unlock;
+
+out_unlock_reset:
+ if (cs->nr_migrate_dl_tasks)
+ reset_migrate_dl_data(cs);
out_unlock:
mutex_unlock(&cpuset_mutex);
return ret;
--
2.51.0
^ permalink raw reply related
* [PATCH v2 2/3] security: Expand task_setscheduler LSM hook to include CPU affinity mask
From: Aaron Tomlin @ 2026-05-09 21:38 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509213803.968464-1-atomlin@atomlin.com>
At present, the task_setscheduler LSM hook provides security modules
with the opportunity to mediate changes to a task's scheduling policy.
However, when invoked via sched_setaffinity(), the hook lacks
visibility into the actual CPU affinity mask being requested.
Consequently, BPF-based security modules are entirely blind to the
target CPUs and cannot make granular access control decisions based on
spatial isolation.
In modern multi-tenant and real-time environments, CPU isolation is a
critical boundary. The inability to audit or restrict specific CPU
pinning requests limits the effectiveness of eBPF-driven security
policies, particularly when attempting to shield isolated or
cryptographic cores from unprivileged or compromised tasks.
This patch expands the security_task_setscheduler() hook signature to
include a pointer to the requested cpumask. Because this is a shared
hook used for multiple scheduling attribute changes, call sites that do
not modify CPU affinity are updated to safely pass NULL.
To protect against unverified dereferences, the parameter is annotated
with __nullable in the LSM hook definition, ensuring the BPF verifier
mandates explicit NULL checks for attached eBPF programs.
This change updates all in-tree security modules (SELinux and Smack) to
accommodate the new parameter mechanically, whilst providing BPF LSMs
with the necessary context to enforce strict affinity policies.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
arch/mips/kernel/mips-mt-fpaff.c | 30 +++++++++++++++++-------------
fs/proc/base.c | 2 +-
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 11 +++++++----
kernel/cgroup/cpuset.c | 4 ++--
kernel/sched/syscalls.c | 4 ++--
security/commoncap.c | 7 +++++--
security/security.c | 11 ++++++-----
security/selinux/hooks.c | 3 ++-
security/smack/smack_lsm.c | 11 +++++++++--
10 files changed, 53 insertions(+), 33 deletions(-)
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 10172fc4f627..6424152d9091 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -71,11 +71,18 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
struct task_struct *p;
int retval;
- if (len < sizeof(new_mask))
- return -EINVAL;
+ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+ return -ENOMEM;
- if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
- return -EFAULT;
+ if (len < sizeof(new_mask)) {
+ retval = -EINVAL;
+ goto out_free_new_mask;
+ }
+
+ if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) {
+ retval = -EFAULT;
+ goto out_free_new_mask;
+ }
cpus_read_lock();
rcu_read_lock();
@@ -84,7 +91,8 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
if (!p) {
rcu_read_unlock();
cpus_read_unlock();
- return -ESRCH;
+ retval = -ESRCH;
+ goto out_free_new_mask;
}
/* Prevent p going away */
@@ -95,20 +103,16 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
retval = -ENOMEM;
goto out_put_task;
}
- if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_free_cpus_allowed;
- }
if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
retval = -ENOMEM;
- goto out_free_new_mask;
+ goto out_free_cpus_allowed;
}
if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
retval = -EPERM;
goto out_unlock;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, new_mask);
if (retval)
goto out_unlock;
@@ -142,13 +146,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
}
out_unlock:
free_cpumask_var(effective_mask);
-out_free_new_mask:
- free_cpumask_var(new_mask);
out_free_cpus_allowed:
free_cpumask_var(cpus_allowed);
out_put_task:
put_task_struct(p);
cpus_read_unlock();
+out_free_new_mask:
+ free_cpumask_var(new_mask);
return retval;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d9acfa89c894..ac4096958a00 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2619,7 +2619,7 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
}
rcu_read_unlock();
- err = security_task_setscheduler(p);
+ err = security_task_setscheduler(p, NULL);
if (err) {
count = err;
goto out;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2b8dfb35caed..6ec7bc04a1b7 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -255,7 +255,8 @@ LSM_HOOK(int, 0, task_prlimit, const struct cred *cred,
const struct cred *tcred, unsigned int flags)
LSM_HOOK(int, 0, task_setrlimit, struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim)
-LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p)
+LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p,
+ const struct cpumask *in_mask__nullable)
LSM_HOOK(int, 0, task_getscheduler, struct task_struct *p)
LSM_HOOK(int, 0, task_movememory, struct task_struct *p)
LSM_HOOK(int, 0, task_kill, struct task_struct *p, struct kernel_siginfo *info,
diff --git a/include/linux/security.h b/include/linux/security.h
index 41d7367cf403..8b74153daa43 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -196,7 +196,8 @@ extern int cap_mmap_addr(unsigned long addr);
extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
-extern int cap_task_setscheduler(struct task_struct *p);
+extern int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
@@ -531,7 +532,8 @@ int security_task_prlimit(const struct cred *cred, const struct cred *tcred,
unsigned int flags);
int security_task_setrlimit(struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim);
-int security_task_setscheduler(struct task_struct *p);
+int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask);
int security_task_getscheduler(struct task_struct *p);
int security_task_movememory(struct task_struct *p);
int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
@@ -1392,9 +1394,10 @@ static inline int security_task_setrlimit(struct task_struct *p,
return 0;
}
-static inline int security_task_setscheduler(struct task_struct *p)
+static inline int security_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask)
{
- return cap_task_setscheduler(p);
+ return cap_task_setscheduler(p, in_mask);
}
static inline int security_task_getscheduler(struct task_struct *p)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b8022f6e2a35..e463f5cbbb06 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3032,7 +3032,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
goto out_unlock_reset;
if (setsched_check) {
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, cs->effective_cpus);
if (ret)
goto out_unlock_reset;
}
@@ -3592,7 +3592,7 @@ static int cpuset_can_fork(struct task_struct *task, struct css_set *cset)
if (ret)
goto out_unlock;
- ret = security_task_setscheduler(task);
+ ret = security_task_setscheduler(task, cs->effective_cpus);
if (ret)
goto out_unlock;
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index b215b0ead9a6..68bc7e466fb1 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -540,7 +540,7 @@ int __sched_setscheduler(struct task_struct *p,
if (attr->sched_flags & SCHED_FLAG_SUGOV)
return -EINVAL;
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, NULL);
if (retval)
return retval;
}
@@ -1213,7 +1213,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
return -EPERM;
}
- retval = security_task_setscheduler(p);
+ retval = security_task_setscheduler(p, in_mask);
if (retval)
return retval;
diff --git a/security/commoncap.c b/security/commoncap.c
index 3399535808fe..d86f1c2b9210 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1222,13 +1222,16 @@ static int cap_safe_nice(struct task_struct *p)
/**
* cap_task_setscheduler - Determine if scheduler policy change is permitted
* @p: The task to affect
+ * @in_mask: Requested CPU affinity mask (ignored)
*
* Determine if the requested scheduler policy change is permitted for the
- * specified task.
+ * specified task. The capabilities security module does not evaluate the
+ * @in_mask parameter, relying solely on cap_safe_nice().
*
* Return: 0 if permission is granted, -ve if denied.
*/
-int cap_task_setscheduler(struct task_struct *p)
+int cap_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return cap_safe_nice(p);
}
diff --git a/security/security.c b/security/security.c
index 4e999f023651..53804ee40df5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3240,17 +3240,18 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
}
/**
- * security_task_setscheduler() - Check if setting sched policy/param is allowed
+ * security_task_setscheduler() - Check if setting sched policy/param/affinity is allowed
* @p: target task
+ * @in_mask: requested CPU affinity mask, or NULL if not changing affinity
*
- * Check permission before setting scheduling policy and/or parameters of
- * process @p.
+ * Check permission before setting the scheduling policy, parameters, and/or
+ * CPU affinity of process @p.
*
* Return: Returns 0 if permission is granted.
*/
-int security_task_setscheduler(struct task_struct *p)
+int security_task_setscheduler(struct task_struct *p, const struct cpumask *in_mask)
{
- return call_int_hook(task_setscheduler, p);
+ return call_int_hook(task_setscheduler, p, in_mask);
}
/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0f704380a8c8..5f0914db23f6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4557,7 +4557,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
return 0;
}
-static int selinux_task_setscheduler(struct task_struct *p)
+static int selinux_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3f9ae05039a2..a77143beff44 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2343,10 +2343,17 @@ static int smack_task_getioprio(struct task_struct *p)
/**
* smack_task_setscheduler - Smack check on setting scheduler
* @p: the task object
+ * @in_mask: Requested CPU affinity mask (ignored)
*
- * Return 0 if read access is permitted
+ * Evaluate whether the current task has write access to the target task @p
+ * to change its scheduling policy. The Smack security module relies
+ * strictly on label-based access control and does not evaluate CPU
+ * affinity masks.
+ *
+ * Return: 0 if write access is permitted
*/
-static int smack_task_setscheduler(struct task_struct *p)
+static int smack_task_setscheduler(struct task_struct *p,
+ const struct cpumask *in_mask __always_unused)
{
return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 3/3] mips: sched: Fix CPUMASK_OFFSTACK memory corruption
From: Aaron Tomlin @ 2026-05-09 21:38 UTC (permalink / raw)
To: tsbogend, paul, jmorris, serge, mingo, peterz, juri.lelli,
vincent.guittot, stephen.smalley.work, casey, longman, tj, hannes,
mkoutny
Cc: chenridong, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
kprateek.nayak, omosnace, kees, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange, cgroups, linux-mips, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260509213803.968464-1-atomlin@atomlin.com>
This patch addresses a critical memory management flaw.
When CONFIG_CPUMASK_OFFSTACK is enabled, cpumask_var_t is a pointer.
Consequently, sizeof(new_mask) evaluates to the pointer size, causing
copy_from_user() to clobber the stack pointer. The subsequent
alloc_cpumask_var() overwrites this with an uninitialised heap address,
discarding the user's mask and risking data leaks. Fix this by
allocating masks first, and using cpumask_size() to copy data directly
into the allocated buffer.
Fixes: 295cbf6d63165 ("[MIPS] Move FPU affinity code into separate file.")
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
arch/mips/kernel/mips-mt-fpaff.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 6424152d9091..7c215372c5e8 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -71,17 +71,23 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
struct task_struct *p;
int retval;
+ if (len < cpumask_size())
+ return -EINVAL;
+
if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
return -ENOMEM;
-
- if (len < sizeof(new_mask)) {
- retval = -EINVAL;
+ if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
+ retval = -ENOMEM;
goto out_free_new_mask;
}
+ if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
+ retval = -ENOMEM;
+ goto out_free_cpus_allowed;
+ }
- if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) {
+ if (copy_from_user(new_mask, user_mask_ptr, cpumask_size())) {
retval = -EFAULT;
- goto out_free_new_mask;
+ goto out_free_effective_mask;
}
cpus_read_lock();
@@ -92,21 +98,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
rcu_read_unlock();
cpus_read_unlock();
retval = -ESRCH;
- goto out_free_new_mask;
+ goto out_free_effective_mask;
}
/* Prevent p going away */
get_task_struct(p);
rcu_read_unlock();
- if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_put_task;
- }
- if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
- retval = -ENOMEM;
- goto out_free_cpus_allowed;
- }
if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
retval = -EPERM;
goto out_unlock;
@@ -145,12 +143,12 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
}
}
out_unlock:
+ put_task_struct(p);
+ cpus_read_unlock();
+out_free_effective_mask:
free_cpumask_var(effective_mask);
out_free_cpus_allowed:
free_cpumask_var(cpus_allowed);
-out_put_task:
- put_task_struct(p);
- cpus_read_unlock();
out_free_new_mask:
free_cpumask_var(new_mask);
return retval;
--
2.51.0
^ permalink raw reply related
* [PATCH] cgroup/dmem: return -ENOMEM on failed pool preallocation
From: Guopeng Zhang @ 2026-05-11 1:31 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Natalie Vock, Tejun Heo
Cc: Johannes Weiner, Michal Koutný, cgroups, dri-devel,
linux-kernel, Guopeng Zhang
get_cg_pool_unlocked() handles allocation failures under dmemcg_lock by
dropping the lock, preallocating a pool with GFP_KERNEL, and retrying the
locked lookup and creation path.
If the fallback allocation fails too, pool remains NULL. Since the loop
condition is while (!pool), the function can keep retrying instead of
propagating the allocation failure to the caller.
Set pool to ERR_PTR(-ENOMEM) when the fallback allocation fails so the
loop exits through the existing common return path. The callers already
handle ERR_PTR() from get_cg_pool_unlocked(), so this restores the
expected error path.
Fixes: b168ed458dde ("kernel/cgroup: Add "dmem" memory accounting cgroup")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
kernel/cgroup/dmem.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 1ab1fb47f271..4753a67d0f0f 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -602,6 +602,7 @@ get_cg_pool_unlocked(struct dmemcg_state *cg, struct dmem_cgroup_region *region)
pool = NULL;
continue;
}
+ pool = ERR_PTR(-ENOMEM);
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH] selftests/cgroup: fix string comparison in write_test
From: Hongfu Li @ 2026-05-11 1:39 UTC (permalink / raw)
To: longman, chenridong, tj, hannes, mkoutny, shuah
Cc: cgroups, linux-kselftest, linux-kernel, Hongfu Li
Use string comparison (!=) instead of numeric comparison (-ne) for
cpuset values like "0-1".
For example:
$ [[ "0-1" != "2-3" ]] && echo "true" || echo "false"
true
$ [[ "0-1" -ne "2-3" ]] && echo "true" || echo "false"
false
Signed-off-by: Hongfu Li <lihongfu@kylinos.cn>
---
tools/testing/selftests/cgroup/test_cpuset_v1_base.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/cgroup/test_cpuset_v1_base.sh b/tools/testing/selftests/cgroup/test_cpuset_v1_base.sh
index 42a6628fb8bc..1c0444729e70 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_v1_base.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_v1_base.sh
@@ -18,7 +18,7 @@ write_test() {
echo "testing $interface $value"
echo $value > $dir/$interface
new=$(cat $dir/$interface)
- [[ $value -ne $(cat $dir/$interface) ]] && {
+ [[ "$value" != "$new" ]] && {
echo "$interface write $value failed: new:$new"
exit 1
}
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] cgroup/dmem: return -ENOMEM on failed pool preallocation
From: Tejun Heo @ 2026-05-11 1:46 UTC (permalink / raw)
To: Guopeng Zhang
Cc: Maarten Lankhorst, Maxime Ripard, Natalie Vock, Johannes Weiner,
Michal Koutný, cgroups, dri-devel, linux-kernel
In-Reply-To: <20260511013150.7235-1-zhangguopeng@kylinos.cn>
Hello,
Applied to cgroup/for-7.1-fixes with Cc: stable@vger.kernel.org # v6.14+
added, as the bug is in released kernels. Also capitalized the subject.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH] selftests/cgroup: Fix cg_read_strcmp() empty string comparison
From: Tejun Heo @ 2026-05-11 1:59 UTC (permalink / raw)
To: Hongfu Li
Cc: Johannes Weiner, Michal Koutný, Shuah Khan,
Sean Christopherson, James Houghton, zhangguopeng, cgroups,
linux-kselftest, linux-kernel
In-Reply-To: <20260509080328.632007-1-lihongfu@kylinos.cn>
Hello,
Applied to cgroup/for-7.1-fixes.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH] selftests/cgroup: fix string comparison in write_test
From: Tejun Heo @ 2026-05-11 1:59 UTC (permalink / raw)
To: Hongfu Li
Cc: Waiman Long, Chen Ridong, Johannes Weiner, Michal Koutný,
Shuah Khan, cgroups, linux-kselftest, linux-kernel
In-Reply-To: <20260511013957.1749665-1-lihongfu@kylinos.cn>
Hello,
Applied to cgroup/for-7.1-fixes with the subject capitalized to "Fix
string comparison in write_test".
Thanks.
--
tejun
^ permalink raw reply
* [PATCH] selftests/cgroup: check malloc return value in alloc_anon functions
From: Hongfu Li @ 2026-05-11 2:16 UTC (permalink / raw)
To: hannes, mhocko, roman.gushchin, shakeel.butt, muchun.song, tj,
mkoutny, shuah
Cc: cgroups, linux-mm, linux-kselftest, linux-kernel, Hongfu Li
The alloc_anon() function calls malloc() without checking for a NULL
return. If memory allocation fails, a NULL pointer dereference will
occur when accessing the buffer.
Add proper error handling to return -1 when malloc() fails in all
four alloc_anon variants:
- alloc_anon()
- alloc_anon_50M_check()
- alloc_anon_noexit()
- alloc_anon_50M_check_swap()
Signed-off-by: Hongfu Li <lihongfu@kylinos.cn>
---
tools/testing/selftests/cgroup/test_memcontrol.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
index b43da9bc20c4..8ef9c99a82eb 100644
--- a/tools/testing/selftests/cgroup/test_memcontrol.c
+++ b/tools/testing/selftests/cgroup/test_memcontrol.c
@@ -61,6 +61,11 @@ int alloc_anon(const char *cgroup, void *arg)
char *buf, *ptr;
buf = malloc(size);
+ if (buf == NULL) {
+ fprintf(stderr, "malloc() failed\n");
+ return -1;
+ }
+
for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
*ptr = 0;
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] selftests/cgroup: check malloc return value in alloc_anon functions
From: Muchun Song @ 2026-05-11 2:46 UTC (permalink / raw)
To: Hongfu Li
Cc: hannes, mhocko, roman.gushchin, shakeel.butt, tj, mkoutny, shuah,
cgroups, linux-mm, linux-kselftest, linux-kernel
In-Reply-To: <20260511021615.1768623-1-lihongfu@kylinos.cn>
> On May 11, 2026, at 10:16, Hongfu Li <lihongfu@kylinos.cn> wrote:
>
> The alloc_anon() function calls malloc() without checking for a NULL
> return. If memory allocation fails, a NULL pointer dereference will
> occur when accessing the buffer.
>
> Add proper error handling to return -1 when malloc() fails in all
> four alloc_anon variants:
> - alloc_anon()
> - alloc_anon_50M_check()
> - alloc_anon_noexit()
> - alloc_anon_50M_check_swap()
>
> Signed-off-by: Hongfu Li <lihongfu@kylinos.cn>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Thanks.
^ permalink raw reply
* Re: [PATCH v3 1/2] cgroup/cpuset: reset DL migration state on can_attach() failure
From: Chen Ridong @ 2026-05-11 2:48 UTC (permalink / raw)
To: Guopeng Zhang, Waiman Long, Tejun Heo, Michal Koutný,
Ingo Molnar, Peter Zijlstra, Juri Lelli
Cc: Johannes Weiner, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Gabriele Monaco, Will Deacon, linux-kernel,
cgroups
In-Reply-To: <20260509102031.97608-2-zhangguopeng@kylinos.cn>
On 2026/5/9 18:20, Guopeng Zhang wrote:
> cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration
> state in the destination cpuset while walking the taskset.
>
> If a later task_can_attach() or security_task_setscheduler() check
> fails, cgroup_migrate_execute() treats cpuset as the failing subsystem
> and does not call cpuset_cancel_attach() for it. The partially
> accumulated state is then left behind and can be consumed by a later
> attach, corrupting cpuset DL task accounting and pending DL bandwidth
> accounting.
>
> Reset the pending DL migration state from the common error exit when
> ret is non-zero. Successful can_attach() keeps the state for
> cpuset_attach() or cpuset_cancel_attach().
>
> Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
> Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
> ---
> kernel/cgroup/cpuset.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index e3a081a07c6d..b9c839538900 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3050,16 +3050,13 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
>
> if (unlikely(cpu >= nr_cpu_ids)) {
> - reset_migrate_dl_data(cs);
> ret = -EINVAL;
> goto out_unlock;
> }
>
> ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
> - if (ret) {
> - reset_migrate_dl_data(cs);
> + if (ret)
> goto out_unlock;
> - }
>
> cs->dl_bw_cpu = cpu;
> }
> @@ -3070,7 +3067,10 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> * changes which zero cpus/mems_allowed.
> */
> cs->attach_in_progress++;
> +
> out_unlock:
> + if (ret)
> + reset_migrate_dl_data(cs);
> mutex_unlock(&cpuset_mutex);
> return ret;
> }
LGTM.
Thanks.
Reviewed-by: Chen Ridong <chenridong@huaweicloud.com>
--
Best regards,
Ridong
^ permalink raw reply
* Re: [PATCH v3 1/2] cgroup/cpuset: reset DL migration state on can_attach() failure
From: Waiman Long @ 2026-05-11 5:04 UTC (permalink / raw)
To: Guopeng Zhang, Tejun Heo, Michal Koutný, Ingo Molnar,
Peter Zijlstra, Juri Lelli, Chen Ridong
Cc: Johannes Weiner, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Gabriele Monaco, Will Deacon, linux-kernel,
cgroups
In-Reply-To: <20260509102031.97608-2-zhangguopeng@kylinos.cn>
On 5/9/26 6:20 AM, Guopeng Zhang wrote:
> cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration
> state in the destination cpuset while walking the taskset.
>
> If a later task_can_attach() or security_task_setscheduler() check
> fails, cgroup_migrate_execute() treats cpuset as the failing subsystem
> and does not call cpuset_cancel_attach() for it. The partially
> accumulated state is then left behind and can be consumed by a later
> attach, corrupting cpuset DL task accounting and pending DL bandwidth
> accounting.
>
> Reset the pending DL migration state from the common error exit when
> ret is non-zero. Successful can_attach() keeps the state for
> cpuset_attach() or cpuset_cancel_attach().
>
> Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
> Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
> ---
> kernel/cgroup/cpuset.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index e3a081a07c6d..b9c839538900 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3050,16 +3050,13 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
>
> if (unlikely(cpu >= nr_cpu_ids)) {
> - reset_migrate_dl_data(cs);
> ret = -EINVAL;
> goto out_unlock;
> }
>
> ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
> - if (ret) {
> - reset_migrate_dl_data(cs);
> + if (ret)
> goto out_unlock;
> - }
>
> cs->dl_bw_cpu = cpu;
> }
> @@ -3070,7 +3067,10 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> * changes which zero cpus/mems_allowed.
> */
> cs->attach_in_progress++;
> +
> out_unlock:
> + if (ret)
> + reset_migrate_dl_data(cs);
> mutex_unlock(&cpuset_mutex);
> return ret;
> }
Reviewed-by: Waiman Long <longman@redhat.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox