From: Guopeng Zhang <guopeng.zhang@linux.dev>
To: Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Juri Lelli <juri.lelli@redhat.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>,
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>,
Tommaso Cucinotta <tommaso.cucinotta@gmail.com>,
linux-kernel@vger.kernel.org,
Guopeng Zhang <zhangguopeng@kylinos.cn>
Subject: [PATCH] sched/deadline: Lock the task's runqueue for dynamic sched_getattr()
Date: Sat, 18 Jul 2026 17:48:47 +0800 [thread overview]
Message-ID: <20260718094847.1239114-1-guopeng.zhang@linux.dev> (raw)
From: Guopeng Zhang <zhangguopeng@kylinos.cn>
SCHED_GETATTR_FLAG_DL_DYNAMIC reads task_rq(p) before taking the rq lock.
If p migrates between the lookup and lock acquisition, the old rq lock
does not protect p->dl and the absolute deadline is converted with the
wrong rq clock. Directly locking rq->__lock also bypasses the rq lock
indirection used by core scheduling.
The policy can also change after the initial check. Use task_rq_lock()
to stabilize p's runqueue, recheck its policy, and read the dynamic
deadline fields while holding the lock.
Update deadline accounting first when p is the current donor. Under
proxy execution, update_curr_dl() accounts rq->donor rather than
rq->curr.
Fixes: 2e7af192697e ("sched/deadline: Add reporting of runtime left & abs deadline to sched_getattr() for DEADLINE tasks")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
kernel/sched/deadline.c | 36 +++++++++++++++++++++++++++---------
kernel/sched/sched.h | 2 +-
kernel/sched/syscalls.c | 20 +++++++++++++++-----
3 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index a3003b0f4522..de5057680da9 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -3853,29 +3853,47 @@ void __setparam_dl(struct task_struct *p, const struct sched_attr *attr)
dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
}
-void __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
+int __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
{
struct sched_dl_entity *dl_se = &p->dl;
- struct rq *rq = task_rq(p);
- u64 adj_deadline;
+ struct rq_flags rf;
+ struct rq *rq;
- attr->sched_priority = p->rt_priority;
if (flags & SCHED_GETATTR_FLAG_DL_DYNAMIC) {
- guard(raw_spinlock_irq)(&rq->__lock);
+ u64 adj_deadline;
+
+ rq = task_rq_lock(p, &rf);
+ if (!task_has_dl_policy(p)) {
+ task_rq_unlock(rq, p, &rf);
+ return -EINVAL;
+ }
+
update_rq_clock(rq);
- if (task_current(rq, p))
+ if (task_current_donor(rq, p))
update_curr_dl(rq);
+ attr->sched_policy = p->policy;
+ attr->sched_priority = p->rt_priority;
attr->sched_runtime = dl_se->runtime;
adj_deadline = dl_se->deadline - rq_clock(rq) + ktime_get_ns();
attr->sched_deadline = adj_deadline;
- } else {
- attr->sched_runtime = dl_se->dl_runtime;
- attr->sched_deadline = dl_se->dl_deadline;
+ attr->sched_period = dl_se->dl_period;
+ attr->sched_flags &= ~(SCHED_FLAG_RESET_ON_FORK | SCHED_DL_FLAGS);
+ if (p->sched_reset_on_fork)
+ attr->sched_flags |= SCHED_FLAG_RESET_ON_FORK;
+ attr->sched_flags |= dl_se->flags;
+ task_rq_unlock(rq, p, &rf);
+ return 0;
}
+
+ attr->sched_priority = p->rt_priority;
+ attr->sched_runtime = dl_se->dl_runtime;
+ attr->sched_deadline = dl_se->dl_deadline;
attr->sched_period = dl_se->dl_period;
attr->sched_flags &= ~SCHED_DL_FLAGS;
attr->sched_flags |= dl_se->flags;
+
+ return 0;
}
/*
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index e3e4e68bb0c5..500163f81a9e 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -356,7 +356,7 @@ extern int sched_dl_global_validate(void);
extern void sched_dl_do_global(void);
extern int sched_dl_overflow(struct task_struct *p, int policy, const struct sched_attr *attr);
extern void __setparam_dl(struct task_struct *p, const struct sched_attr *attr);
-extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags);
+extern int __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags);
extern bool __checkparam_dl(const struct sched_attr *attr);
extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
extern int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial);
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index b215b0ead9a6..c5ff37e083db 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -911,16 +911,21 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a
return -E2BIG;
}
-static void get_params(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
+static int get_params(struct task_struct *p, struct sched_attr *attr, unsigned int flags)
{
+ if (flags)
+ return __getparam_dl(p, attr, flags);
+
if (task_has_dl_policy(p)) {
- __getparam_dl(p, attr, flags);
+ return __getparam_dl(p, attr, flags);
} else if (task_has_rt_policy(p)) {
attr->sched_priority = p->rt_priority;
} else {
attr->sched_nice = task_nice(p);
attr->sched_runtime = p->se.slice;
}
+
+ return 0;
}
/**
@@ -979,8 +984,11 @@ SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
if (!p)
return -ESRCH;
- if (attr.sched_flags & SCHED_FLAG_KEEP_PARAMS)
- get_params(p, &attr, 0);
+ if (attr.sched_flags & SCHED_FLAG_KEEP_PARAMS) {
+ retval = get_params(p, &attr, 0);
+ if (retval)
+ return retval;
+ }
return sched_setattr(p, &attr);
}
@@ -1086,7 +1094,9 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
kattr.sched_policy = p->policy;
if (p->sched_reset_on_fork)
kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
- get_params(p, &kattr, flags);
+ retval = get_params(p, &kattr, flags);
+ if (retval)
+ return retval;
kattr.sched_flags &= SCHED_FLAG_ALL;
#ifdef CONFIG_UCLAMP_TASK
--
2.43.0
reply other threads:[~2026-07-18 9:49 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260718094847.1239114-1-guopeng.zhang@linux.dev \
--to=guopeng.zhang@linux.dev \
--cc=bsegall@google.com \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tommaso.cucinotta@gmail.com \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=zhangguopeng@kylinos.cn \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.