From: Andrea Parri <parri.andrea@gmail.com>
To: Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>
Cc: Andrea Parri <parri.andrea@gmail.com>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Steven Rostedt <rostedt@goodmis.org>,
Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
Valentin Schneider <vschneid@redhat.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Clark Williams <clrkwllms@kernel.org>,
Aaron Tomlin <atomlin@atomlin.com>,
linux-rt-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: [PATCH] sched/deadline: Fix spurious -EPERM for migration-disabled tasks
Date: Mon, 2 Nov 2026 14:54:19 +0100 [thread overview]
Message-ID: <20261102135420.244745-1-parri.andrea@gmail.com> (raw)
sched_setattr() can refuse to make a task SCHED_DEADLINE with -EPERM,
even though the task's affinity covers the whole root domain. A retry
can succeed, but the error blames an affinity the task does not have.
__sched_setscheduler() tests p->cpus_ptr, which is not always the task's
affinity. When a task is scheduled out inside a migrate_disable() section,
migrate_disable_switch() points p->cpus_ptr at the current CPU until
migrate_enable(). On PREEMPT_RT every spinlock_t holder is in such a
section, so ordinary kernel work opens the window. Elsewhere, seccomp
filters run in one.
Test p->cpus_mask instead, which keeps the task's affinity and is what
sched_getaffinity() reports. This should be safe because an admitted
task's cpus_mask covers the root domain, so set_cpus_allowed_dl() moves
no bandwidth when migrate_enable() restores p->cpus_ptr.
The following program, run as root, had 553679, 453720 and 424623 of its
1000000 requests refused on three boots of a 4-CPU PREEMPT_RT guest, and
236182, 217174 and 237183 without PREEMPT_RT. With this applied the count
is 0, also with lockdep, and a task pinned to one CPU is still refused:
#define _GNU_SOURCE
#include <errno.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#define REQUESTS 1000000
#define INSNS 300
struct attr {
uint32_t size, policy;
uint64_t flags;
int32_t nice;
uint32_t prio;
uint64_t runtime, deadline, period;
};
static volatile int stop;
static volatile pid_t target;
static long set(struct attr a)
{
a.size = sizeof(a);
return syscall(SYS_sched_setattr, target, &a, 0);
}
static void *worker(void *arg)
{
struct sock_filter f[INSNS + 1];
struct sock_fprog prog = { .len = INSNS + 1, .filter = f };
int i;
/* Reading the arguments keeps seccomp from caching the result */
for (i = 0; i < INSNS; i++)
f[i] = (struct sock_filter)
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
offsetof(struct seccomp_data, args));
f[INSNS] = (struct sock_filter)
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW);
syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog);
target = syscall(SYS_gettid);
while (!stop)
syscall(SYS_getppid);
return arg;
}
static void *hog(void *arg)
{
while (!stop)
;
return arg;
}
int main(void)
{
pthread_t t[9];
long refused = 0;
int i;
pthread_create(&t[0], NULL, worker, NULL);
while (!target)
usleep(100);
for (i = 1; i < 9; i++)
pthread_create(&t[i], NULL, hog, NULL);
for (i = 0; i < REQUESTS; i++) {
/* SCHED_DEADLINE, 2us every 1s */
if (set((struct attr){ .policy = 6, .runtime = 2000,
.deadline = 1000000000,
.period = 1000000000 }) && errno == EPERM)
refused++;
set((struct attr){ .policy = 0 }); /* SCHED_OTHER */
}
stop = 1;
for (i = 0; i < 9; i++)
pthread_join(t[i], NULL);
printf("%ld of %d requests refused\n", refused, REQUESTS);
return 0;
}
An LLM helped find this bug and write this patch and its test.
Fixes: af449901b84c ("sched: Add migrate_disable()")
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
Cc: stable@vger.kernel.org
---
This textually conflicts with [1], which rewrites this line and keeps
p->cpus_ptr. Whichever goes second needs to keep &p->cpus_mask.
Also tested on PREEMPT_RT with lockdep by holding a 1ms/10ms reservation
for 3ms at a time, so that tasks admitted while migration-disabled reach
migrate_enable() as SCHED_DEADLINE: no warnings, total_bw unchanged, and
none of 6788 requests refused. Without this patch, 826 of 6645 are refused.
Other !PREEMPT_RT migrate_disable() users were not tested.
[1] https://lore.kernel.org/20261030151307.768523-2-atomlin@atomlin.com/
kernel/sched/syscalls.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index 45a127deeadd9..fb8f332074b88 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -628,7 +628,7 @@ int __sched_setscheduler(struct task_struct *p,
* the entire root_domain to become SCHED_DEADLINE. We
* will also fail if there's no bandwidth available.
*/
- if (!cpumask_subset(span, p->cpus_ptr) ||
+ if (!cpumask_subset(span, &p->cpus_mask) ||
rq->rd->dl_bw.bw == 0) {
retval = -EPERM;
goto unlock;
--
2.53.0
next reply other threads:[~2026-11-02 13:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 13:54 Andrea Parri [this message]
2026-11-02 14:45 ` Aaron Tomlin
2026-11-02 15:14 ` Andrea Parri
2026-11-02 17:00 ` Aaron Tomlin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102135420.244745-1-parri.andrea@gmail.com \
--to=parri.andrea@gmail.com \
--cc=atomlin@atomlin.com \
--cc=bigeasy@linutronix.de \
--cc=bsegall@google.com \
--cc=clrkwllms@kernel.org \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®