1597 lines · 38.2 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){	bool queued, running;	struct rq *rq;	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.	 */	CLASS(task_rq_lock, rq_guard)(p);	rq = rq_guard.rq; 	update_rq_clock(rq); 	/*	 * 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;	} 	queued = task_on_rq_queued(p);	running = task_current_donor(rq, p);	if (queued)		dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);	if (running)		put_prev_task(rq, p); 	p->static_prio = NICE_TO_PRIO(nice);	set_load_weight(p, true);	old_prio = p->prio;	p->prio = effective_prio(p); 	if (queued)		enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);	if (running)		set_next_task(rq, p); 	/*	 * If the task increased its priority or is running and	 * lowered its priority, then reschedule its CPU:	 */	p->sched_class->prio_changed(rq, p, old_prio);}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 /** * 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){	struct rq *rq = cpu_rq(cpu); 	if (rq->curr != rq->idle)		return 0; 	if (rq->nr_running)		return 0; #ifdef CONFIG_SMP	if (rq->ttwu_pending)		return 0;#endif 	return 1;} /** * available_idle_cpu - is a given CPU idle for enqueuing work. * @cpu: the CPU in question. * * Return: 1 if the CPU is currently idle. 0 otherwise. */int available_idle_cpu(int cpu){	if (!idle_cpu(cpu))		return 0; 	if (vcpu_is_preempted(cpu))		return 0; 	return 1;} /** * 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 /** * 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)) {		p->static_prio = NICE_TO_PRIO(attr->sched_nice);		if (attr->sched_runtime) {			p->se.custom_slice = 1;			p->se.slice = clamp_t(u64, attr->sched_runtime,					      NSEC_PER_MSEC/10,   /* HZ=1000 * 10 */					      NSEC_PER_MSEC*100); /* HZ=100  / 10 */		} else {			p->se.custom_slice = 0;			p->se.slice = sysctl_sched_base_slice;		}	} 	/* 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_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.	 */	static_branch_enable(&sched_uclamp_used); 	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 /* * 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; 	/*

Lines 1–500 of 1597.