diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 8c1911fc5664..773175f6df5d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1880,7 +1880,7 @@ done: #endif static int uclamp_validate(struct task_struct *p, - const struct sched_attr *attr) + const struct sched_attr *attr, bool user) { int util_min = p->uclamp_req[UCLAMP_MIN].value; int util_max = p->uclamp_req[UCLAMP_MAX].value; @@ -1905,11 +1905,19 @@ static int uclamp_validate(struct task_struct *p, /* * We have valid uclamp attributes; make sure uclamp is enabled. * - * We need to do that here, because enabling static branches is a - * blocking operation which obviously cannot be done while holding + * We need to do that here, because enabling static branches is + * a blocking operation which obviously cannot be done while holding * scheduler locks. + * + * We only enable the static key if this was initiated by user space + * request. There should be no in-kernel users of uclamp except to + * implement things like inheritance like in binder. These in-kernel + * callers can rightfully be called be sometimes in_atomic() context + * which is invalid context to enable the key in. The enabling path + * unconditionally holds the cpus_read_lock() which might_sleep(). */ - static_branch_enable(&sched_uclamp_used); + if (user) + static_branch_enable(&sched_uclamp_used); return 0; } @@ -2050,7 +2058,7 @@ static void __init init_uclamp(void) static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p) { } static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p) { } static inline int uclamp_validate(struct task_struct *p, - const struct sched_attr *attr) + const struct sched_attr *attr, bool user) { return -EOPNOTSUPP; } @@ -7649,7 +7657,7 @@ recheck: /* Update task specific "requested" clamps */ if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP) { - retval = uclamp_validate(p, attr); + retval = uclamp_validate(p, attr, user); if (retval) return retval; }