1578 lines · 38.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  kernel/sched/syscalls.c * *  Core kernel scheduler syscalls related code * *  Copyright (C) 1991-2002  Linus Torvalds *  Copyright (C) 1998-2024  Ingo Molnar, Red Hat */#include <linux/sched.h>#include <linux/cpuset.h>#include <linux/sched/debug.h> #include <uapi/linux/sched/types.h> #include "sched.h"#include "autogroup.h" static inline int __normal_prio(int policy, int rt_prio, int nice){	int prio; 	if (dl_policy(policy))		prio = MAX_DL_PRIO - 1;	else if (rt_policy(policy))		prio = MAX_RT_PRIO - 1 - rt_prio;	else		prio = NICE_TO_PRIO(nice); 	return prio;} /* * Calculate the expected normal priority: i.e. priority * without taking RT-inheritance into account. Might be * boosted by interactivity modifiers. Changes upon fork, * setprio syscalls, and whenever the interactivity * estimator recalculates. */static inline int normal_prio(struct task_struct *p){	return __normal_prio(p->policy, p->rt_priority, PRIO_TO_NICE(p->static_prio));} /* * Calculate the current priority, i.e. the priority * taken into account by the scheduler. This value might * be boosted by RT tasks, or might be boosted by * interactivity modifiers. Will be RT if the task got * RT-boosted. If not then it returns p->normal_prio. */static int effective_prio(struct task_struct *p){	p->normal_prio = normal_prio(p);	/*	 * If we are RT tasks or we were boosted to RT priority,	 * keep the priority unchanged. Otherwise, update priority	 * to the normal priority:	 */	if (!rt_or_dl_prio(p->prio))		return p->normal_prio;	return p->prio;} void set_user_nice(struct task_struct *p, long nice){	int old_prio; 	if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)		return;	/*	 * We have to be careful, if called from sys_setpriority(),	 * the task might be in the middle of scheduling on another CPU.	 */	guard(task_rq_lock)(p); 	/*	 * The RT priorities are set via sched_setscheduler(), but we still	 * allow the 'normal' nice value to be set - but as expected	 * it won't have any effect on scheduling until the task is	 * SCHED_DEADLINE, SCHED_FIFO or SCHED_RR:	 */	if (task_has_dl_policy(p) || task_has_rt_policy(p)) {		p->static_prio = NICE_TO_PRIO(nice);		return;	} 	scoped_guard (sched_change, p, DEQUEUE_SAVE) {		p->static_prio = NICE_TO_PRIO(nice);		set_load_weight(p, true);		old_prio = p->prio;		p->prio = effective_prio(p);	}}EXPORT_SYMBOL(set_user_nice); /* * is_nice_reduction - check if nice value is an actual reduction * * Similar to can_nice() but does not perform a capability check. * * @p: task * @nice: nice value */static bool is_nice_reduction(const struct task_struct *p, const int nice){	/* Convert nice value [19,-20] to rlimit style value [1,40]: */	int nice_rlim = nice_to_rlimit(nice); 	return (nice_rlim <= task_rlimit(p, RLIMIT_NICE));} /* * can_nice - check if a task can reduce its nice value * @p: task * @nice: nice value */int can_nice(const struct task_struct *p, const int nice){	return is_nice_reduction(p, nice) || capable(CAP_SYS_NICE);} #ifdef __ARCH_WANT_SYS_NICE /* * sys_nice - change the priority of the current process. * @increment: priority increment * * sys_setpriority is a more generic, but much slower function that * does similar things. */SYSCALL_DEFINE1(nice, int, increment){	long nice, retval; 	/*	 * Setpriority might change our priority at the same moment.	 * We don't have to worry. Conceptually one call occurs first	 * and we have a single winner.	 */	increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH);	nice = task_nice(current) + increment; 	nice = clamp_val(nice, MIN_NICE, MAX_NICE);	if (increment < 0 && !can_nice(current, nice))		return -EPERM; 	retval = security_task_setnice(current, nice);	if (retval)		return retval; 	set_user_nice(current, nice);	return 0;} #endif /* __ARCH_WANT_SYS_NICE */ /** * task_prio - return the priority value of a given task. * @p: the task in question. * * Return: The priority value as seen by users in /proc. * * sched policy         return value   kernel prio    user prio/nice * * normal, batch, idle     [0 ... 39]  [100 ... 139]          0/[-20 ... 19] * fifo, rr             [-2 ... -100]     [98 ... 0]  [1 ... 99] * deadline                     -101             -1           0 */int task_prio(const struct task_struct *p){	return p->prio - MAX_RT_PRIO;} /** * idle_cpu - is a given CPU idle currently? * @cpu: the processor in question. * * Return: 1 if the CPU is currently idle. 0 otherwise. */int idle_cpu(int cpu){	return idle_rq(cpu_rq(cpu));} /** * idle_task - return the idle task for a given CPU. * @cpu: the processor in question. * * Return: The idle task for the CPU @cpu. */struct task_struct *idle_task(int cpu){	return cpu_rq(cpu)->idle;} #ifdef CONFIG_SCHED_COREint sched_core_idle_cpu(int cpu){	struct rq *rq = cpu_rq(cpu); 	if (sched_core_enabled(rq) && rq->curr == rq->idle)		return 1; 	return idle_cpu(cpu);}#endif /* CONFIG_SCHED_CORE */ /** * find_process_by_pid - find a process with a matching PID value. * @pid: the pid in question. * * The task of @pid, if found. %NULL otherwise. */static struct task_struct *find_process_by_pid(pid_t pid){	return pid ? find_task_by_vpid(pid) : current;} static struct task_struct *find_get_task(pid_t pid){	struct task_struct *p;	guard(rcu)(); 	p = find_process_by_pid(pid);	if (likely(p))		get_task_struct(p); 	return p;} DEFINE_CLASS(find_get_task, struct task_struct *, if (_T) put_task_struct(_T),	     find_get_task(pid), pid_t pid) /* * sched_setparam() passes in -1 for its policy, to let the functions * it calls know not to change it. */#define SETPARAM_POLICY	-1 static void __setscheduler_params(struct task_struct *p,		const struct sched_attr *attr){	int policy = attr->sched_policy; 	if (policy == SETPARAM_POLICY)		policy = p->policy; 	p->policy = policy; 	if (dl_policy(policy))		__setparam_dl(p, attr);	else if (fair_policy(policy))		__setparam_fair(p, attr); 	/* rt-policy tasks do not have a timerslack */	if (rt_or_dl_task_policy(p)) {		p->timer_slack_ns = 0;	} else if (p->timer_slack_ns == 0) {		/* when switching back to non-rt policy, restore timerslack */		p->timer_slack_ns = p->default_timer_slack_ns;	} 	/*	 * __sched_setscheduler() ensures attr->sched_priority == 0 when	 * !rt_policy. Always setting this ensures that things like	 * getparam()/getattr() don't report silly values for !rt tasks.	 */	p->rt_priority = attr->sched_priority;	p->normal_prio = normal_prio(p);	set_load_weight(p, true);} /* * Check the target process has a UID that matches the current process's: */static bool check_same_owner(struct task_struct *p){	const struct cred *cred = current_cred(), *pcred;	guard(rcu)(); 	pcred = __task_cred(p);	return (uid_eq(cred->euid, pcred->euid) ||		uid_eq(cred->euid, pcred->uid));} #ifdef CONFIG_RT_MUTEXESstatic inline void __setscheduler_dl_pi(int newprio, int policy,			      struct task_struct *p,			      struct sched_change_ctx *scope){	/*	 * In case a DEADLINE task (either proper or boosted) gets	 * setscheduled to a lower priority class, check if it neeeds to	 * inherit parameters from a potential pi_task. In that case make	 * sure replenishment happens with the next enqueue.	 */ 	if (dl_prio(newprio) && !dl_policy(policy)) {		struct task_struct *pi_task = rt_mutex_get_top_task(p); 		if (pi_task) {			p->dl.pi_se = pi_task->dl.pi_se;			scope->flags |= ENQUEUE_REPLENISH;		}	}}#else /* !CONFIG_RT_MUTEXES */static inline void __setscheduler_dl_pi(int newprio, int policy,			      struct task_struct *p,			      struct sched_change_ctx *scope){}#endif /* !CONFIG_RT_MUTEXES */ #ifdef CONFIG_UCLAMP_TASK static int uclamp_validate(struct task_struct *p,			   const struct sched_attr *attr){	int util_min = p->uclamp_req[UCLAMP_MIN].value;	int util_max = p->uclamp_req[UCLAMP_MAX].value; 	if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MIN) {		util_min = attr->sched_util_min; 		if (util_min + 1 > SCHED_CAPACITY_SCALE + 1)			return -EINVAL;	} 	if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MAX) {		util_max = attr->sched_util_max; 		if (util_max + 1 > SCHED_CAPACITY_SCALE + 1)			return -EINVAL;	} 	if (util_min != -1 && util_max != -1 && util_min > util_max)		return -EINVAL; 	/*	 * 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	 * scheduler locks.	 */	sched_uclamp_enable(); 	return 0;} static bool uclamp_reset(const struct sched_attr *attr,			 enum uclamp_id clamp_id,			 struct uclamp_se *uc_se){	/* Reset on sched class change for a non user-defined clamp value. */	if (likely(!(attr->sched_flags & SCHED_FLAG_UTIL_CLAMP)) &&	    !uc_se->user_defined)		return true; 	/* Reset on sched_util_{min,max} == -1. */	if (clamp_id == UCLAMP_MIN &&	    attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MIN &&	    attr->sched_util_min == -1) {		return true;	} 	if (clamp_id == UCLAMP_MAX &&	    attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MAX &&	    attr->sched_util_max == -1) {		return true;	} 	return false;} static void __setscheduler_uclamp(struct task_struct *p,				  const struct sched_attr *attr){	enum uclamp_id clamp_id; 	for_each_clamp_id(clamp_id) {		struct uclamp_se *uc_se = &p->uclamp_req[clamp_id];		unsigned int value; 		if (!uclamp_reset(attr, clamp_id, uc_se))			continue; 		/*		 * RT by default have a 100% boost value that could be modified		 * at runtime.		 */		if (unlikely(rt_task(p) && clamp_id == UCLAMP_MIN))			value = sysctl_sched_uclamp_util_min_rt_default;		else			value = uclamp_none(clamp_id); 		uclamp_se_set(uc_se, value, false); 	} 	if (likely(!(attr->sched_flags & SCHED_FLAG_UTIL_CLAMP)))		return; 	if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MIN &&	    attr->sched_util_min != -1) {		uclamp_se_set(&p->uclamp_req[UCLAMP_MIN],			      attr->sched_util_min, true);	} 	if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MAX &&	    attr->sched_util_max != -1) {		uclamp_se_set(&p->uclamp_req[UCLAMP_MAX],			      attr->sched_util_max, true);	}} #else /* !CONFIG_UCLAMP_TASK: */ static inline int uclamp_validate(struct task_struct *p,				  const struct sched_attr *attr){	return -EOPNOTSUPP;}static void __setscheduler_uclamp(struct task_struct *p,				  const struct sched_attr *attr) { }#endif /* !CONFIG_UCLAMP_TASK */ /* * Allow unprivileged RT tasks to decrease priority. * Only issue a capable test if needed and only once to avoid an audit * event on permitted non-privileged operations: */static int user_check_sched_setscheduler(struct task_struct *p,					 const struct sched_attr *attr,					 int policy, int reset_on_fork){	if (fair_policy(policy)) {		if (attr->sched_nice < task_nice(p) &&		    !is_nice_reduction(p, attr->sched_nice))			goto req_priv;	} 	if (rt_policy(policy)) {		unsigned long rlim_rtprio = task_rlimit(p, RLIMIT_RTPRIO); 		/* Can't set/change the rt policy: */		if (policy != p->policy && !rlim_rtprio)			goto req_priv; 		/* Can't increase priority: */		if (attr->sched_priority > p->rt_priority &&		    attr->sched_priority > rlim_rtprio)			goto req_priv;	} 	/*	 * Can't set/change SCHED_DEADLINE policy at all for now	 * (safest behavior); in the future we would like to allow	 * unprivileged DL tasks to increase their relative deadline	 * or reduce their runtime (both ways reducing utilization)	 */	if (dl_policy(policy))		goto req_priv; 	/*	 * Treat SCHED_IDLE as nice 20. Only allow a switch to	 * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.	 */	if (task_has_idle_policy(p) && !idle_policy(policy)) {		if (!is_nice_reduction(p, task_nice(p)))			goto req_priv;	} 	/* Can't change other user's priorities: */	if (!check_same_owner(p))		goto req_priv; 	/* Normal users shall not reset the sched_reset_on_fork flag: */	if (p->sched_reset_on_fork && !reset_on_fork)		goto req_priv; 	return 0; req_priv:	if (!capable(CAP_SYS_NICE))		return -EPERM; 	return 0;} int __sched_setscheduler(struct task_struct *p,			 const struct sched_attr *attr,			 bool user, bool pi){	int oldpolicy = -1, policy = attr->sched_policy;	int retval, oldprio, newprio;	const struct sched_class *prev_class, *next_class;	struct balance_callback *head;

Lines 1–500 of 1578.