Impressum core.c
Sprache: C
// SPDX-License-Identifier: GPL-2.0-only
/*
* kernel / sched / core . c
*
* Core kernel CPU scheduler code
*
* Copyright ( C ) 1991 - 2002 Linus Torvalds
* Copyright ( C ) 1998 - 2024 Ingo Molnar , Red Hat
*/
#include <linux/highmem.h>
#include <linux/hrtimer_api.h>
#include <linux/ktime_api.h>
#include <linux/sched/signal.h>
#include <linux/syscalls_api.h>
#include <linux/debug_locks.h>
#include <linux/prefetch.h>
#include <linux/capability.h>
#include <linux/pgtable_api.h>
#include <linux/wait_bit.h>
#include <linux/jiffies.h>
#include <linux/spinlock_api.h>
#include <linux/cpumask_api.h>
#include <linux/lockdep_api.h>
#include <linux/hardirq.h>
#include <linux/softirq.h>
#include <linux/refcount_api.h>
#include <linux/topology.h>
#include <linux/sched/clock.h>
#include <linux/sched/cond_resched.h>
#include <linux/sched/cputime.h>
#include <linux/sched/debug.h>
#include <linux/sched/hotplug.h>
#include <linux/sched/init.h>
#include <linux/sched/isolation.h>
#include <linux/sched/loadavg.h>
#include <linux/sched/mm.h>
#include <linux/sched/nohz.h>
#include <linux/sched/rseq_api.h>
#include <linux/sched/rt.h>
#include <linux/blkdev.h>
#include <linux/context_tracking.h>
#include <linux/cpuset.h>
#include <linux/delayacct.h>
#include <linux/init_task.h>
#include <linux/interrupt.h>
#include <linux/ioprio.h>
#include <linux/kallsyms.h>
#include <linux/kcov.h>
#include <linux/kprobes.h>
#include <linux/llist_api.h>
#include <linux/mmu_context.h>
#include <linux/mmzone.h>
#include <linux/mutex_api.h>
#include <linux/nmi.h>
#include <linux/nospec.h>
#include <linux/perf_event_api.h>
#include <linux/profile.h>
#include <linux/psi.h>
#include <linux/rcuwait_api.h>
#include <linux/rseq.h>
#include <linux/sched/wake_q.h>
#include <linux/scs.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/vtime.h>
#include <linux/wait_api.h>
#include <linux/workqueue_api.h>
#include <linux/livepatch_sched.h>
#ifdef CONFIG_PREEMPT_DYNAMIC
# ifdef CONFIG_GENERIC_IRQ_ENTRY
# include <linux/irq-entry-common.h>
# endif
#endif
#include <uapi/linux/sched/types.h>
#include <asm /irq_regs.h>
#include <asm /switch_to.h>
#include <asm /tlb.h>
#define CREATE_TRACE_POINTS
#include <linux/sched/rseq_api.h>
#include <trace/events/sched.h>
#include <trace/events/ipi.h>
#undef CREATE_TRACE_POINTS
#include "sched.h"
#include "stats.h"
#include "autogroup.h"
#include "pelt.h"
#include "smp.h"
#include "../workqueue_internal.h"
#include "../../io_uring/io-wq.h"
#include "../smpboot.h"
#include "../locking/mutex.h"
EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpu);
EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpumask);
/*
* Export tracepoints that act as a bare tracehook ( ie : have no trace event
* associated with them ) to allow external modules to probe them .
*/
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_cfs_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_hw_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp);
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp);
DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
#ifdef CONFIG_SCHED_PROXY_EXEC
DEFINE_STATIC_KEY_TRUE(__sched_proxy_exec);
static int __init setup_proxy_exec(char *str)
{
bool proxy_enable = true ;
if (*str && kstrtobool(str + 1 , &proxy_enable)) {
pr_warn("Unable to parse sched_proxy_exec=\n" );
return 0 ;
}
if (proxy_enable) {
pr_info("sched_proxy_exec enabled via boot arg\n" );
static_branch_enable(&__sched_proxy_exec);
} else {
pr_info("sched_proxy_exec disabled via boot arg\n" );
static_branch_disable(&__sched_proxy_exec);
}
return 1 ;
}
#else
static int __init setup_proxy_exec(char *str)
{
pr_warn("CONFIG_SCHED_PROXY_EXEC=n, so it cannot be enabled or disabled at boot time\n" );
return 0 ;
}
#endif
__setup("sched_proxy_exec" , setup_proxy_exec);
/*
* Debugging : various feature bits
*
* If SCHED_DEBUG is disabled , each compilation unit has its own copy of
* sysctl_sched_features , defined in sched . h , to allow constants propagation
* at compile time and compiler optimization based on features default .
*/
#define SCHED_FEAT(name, enabled) \
(1 UL << __SCHED_FEAT_## name) * enabled |
__read_mostly unsigned int sysctl_sched_features =
#include "features.h"
0 ;
#undef SCHED_FEAT
/*
* Print a warning if need_resched is set for the given duration ( if
* LATENCY_WARN is enabled ) .
*
* If sysctl_resched_latency_warn_once is set , only one warning will be shown
* per boot .
*/
__read_mostly int sysctl_resched_latency_warn_ms = 100 ;
__read_mostly int sysctl_resched_latency_warn_once = 1 ;
/*
* Number of tasks to iterate in a single balance run .
* Limited because this is done with IRQs disabled .
*/
__read_mostly unsigned int sysctl_sched_nr_migrate = SCHED_NR_MIGRATE_BREAK;
__read_mostly int scheduler_running;
#ifdef CONFIG_SCHED_CORE
DEFINE_STATIC_KEY_FALSE(__sched_core_enabled);
/* kernel prio, less is more */
static inline int __task_prio(const struct task_struct *p)
{
if (p->sched_class == &stop_sched_class) /* trumps deadline */
return -2 ;
if (p->dl_server)
return -1 ; /* deadline */
if (rt_or_dl_prio(p->prio))
return p->prio; /* [-1, 99] */
if (p->sched_class == &idle_sched_class)
return MAX_RT_PRIO + NICE_WIDTH; /* 140 */
if (task_on_scx(p))
return MAX_RT_PRIO + MAX_NICE + 1 ; /* 120, squash ext */
return MAX_RT_PRIO + MAX_NICE; /* 119, squash fair */
}
/*
* l ( a , b )
* le ( a , b ) : = ! l ( b , a )
* g ( a , b ) : = l ( b , a )
* ge ( a , b ) : = ! l ( a , b )
*/
/* real prio, less is less */
static inline bool prio_less(const struct task_struct *a,
const struct task_struct *b, bool in_fi)
{
int pa = __task_prio(a), pb = __task_prio(b);
if (-pa < -pb)
return true ;
if (-pb < -pa)
return false ;
if (pa == -1 ) { /* dl_prio() doesn't work because of stop_class above */
const struct sched_dl_entity *a_dl, *b_dl;
a_dl = &a->dl;
/*
* Since , ' a ' and ' b ' can be CFS tasks served by DL server ,
* _ _ task_prio ( ) can return - 1 ( for DL ) even for those . In that
* case , get to the dl_server ' s DL entity .
*/
if (a->dl_server)
a_dl = a->dl_server;
b_dl = &b->dl;
if (b->dl_server)
b_dl = b->dl_server;
return !dl_time_before(a_dl->deadline, b_dl->deadline);
}
if (pa == MAX_RT_PRIO + MAX_NICE) /* fair */
return cfs_prio_less(a, b, in_fi);
#ifdef CONFIG_SCHED_CLASS_EXT
if (pa == MAX_RT_PRIO + MAX_NICE + 1 ) /* ext */
return scx_prio_less(a, b, in_fi);
#endif
return false ;
}
static inline bool __sched_core_less(const struct task_struct *a,
const struct task_struct *b)
{
if (a->core_cookie < b->core_cookie)
return true ;
if (a->core_cookie > b->core_cookie)
return false ;
/* flip prio, so high prio is leftmost */
if (prio_less(b, a, !!task_rq(a)->core->core_forceidle_count))
return true ;
return false ;
}
#define __node_2_sc(node) rb_entry((node), struct task_struct, core_node)
static inline bool rb_sched_core_less(struct rb_node *a, const struct rb_node *b)
{
return __sched_core_less(__node_2_sc(a), __node_2_sc(b));
}
static inline int rb_sched_core_cmp(const void *key, const struct rb_node *node)
{
const struct task_struct *p = __node_2_sc(node);
unsigned long cookie = (unsigned long )key;
if (cookie < p->core_cookie)
return -1 ;
if (cookie > p->core_cookie)
return 1 ;
return 0 ;
}
void sched_core_enqueue(struct rq *rq, struct task_struct *p)
{
if (p->se.sched_delayed)
return ;
rq->core->core_task_seq++;
if (!p->core_cookie)
return ;
rb_add(&p->core_node, &rq->core_tree, rb_sched_core_less);
}
void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags)
{
if (p->se.sched_delayed)
return ;
rq->core->core_task_seq++;
if (sched_core_enqueued(p)) {
rb_erase(&p->core_node, &rq->core_tree);
RB_CLEAR_NODE(&p->core_node);
}
/*
* Migrating the last task off the cpu , with the cpu in forced idle
* state . Reschedule to create an accounting edge for forced idle ,
* and re - examine whether the core is still in forced idle state .
*/
if (!(flags & DEQUEUE_SAVE) && rq->nr_running == 1 &&
rq->core->core_forceidle_count && rq->curr == rq->idle)
resched_curr(rq);
}
static int sched_task_is_throttled(struct task_struct *p, int cpu)
{
if (p->sched_class->task_is_throttled)
return p->sched_class->task_is_throttled(p, cpu);
return 0 ;
}
static struct task_struct *sched_core_next(struct task_struct *p, unsigned long cookie)
{
struct rb_node *node = &p->core_node;
int cpu = task_cpu(p);
do {
node = rb_next(node);
if (!node)
return NULL;
p = __node_2_sc(node);
if (p->core_cookie != cookie)
return NULL;
} while (sched_task_is_throttled(p, cpu));
return p;
}
/*
* Find left - most ( aka , highest priority ) and unthrottled task matching @ cookie .
* If no suitable task is found , NULL will be returned .
*/
static struct task_struct *sched_core_find(struct rq *rq, unsigned long cookie)
{
struct task_struct *p;
struct rb_node *node;
node = rb_find_first((void *)cookie, &rq->core_tree, rb_sched_core_cmp);
if (!node)
return NULL;
p = __node_2_sc(node);
if (!sched_task_is_throttled(p, rq->cpu))
return p;
return sched_core_next(p, cookie);
}
/*
* Magic required such that :
*
* raw_spin_rq_lock ( rq ) ;
* . . .
* raw_spin_rq_unlock ( rq ) ;
*
* ends up locking and unlocking the _ same_ lock , and all CPUs
* always agree on what rq has what lock .
*
* XXX entirely possible to selectively enable cores , don ' t bother for now .
*/
static DEFINE_MUTEX(sched_core_mutex);
static atomic_t sched_core_count;
static struct cpumask sched_core_mask;
static void sched_core_lock(int cpu, unsigned long *flags)
{
const struct cpumask *smt_mask = cpu_smt_mask(cpu);
int t, i = 0 ;
local_irq_save(*flags);
for_each_cpu(t, smt_mask)
raw_spin_lock_nested(&cpu_rq(t)->__lock, i++);
}
static void sched_core_unlock(int cpu, unsigned long *flags)
{
const struct cpumask *smt_mask = cpu_smt_mask(cpu);
int t;
for_each_cpu(t, smt_mask)
raw_spin_unlock(&cpu_rq(t)->__lock);
local_irq_restore(*flags);
}
static void __sched_core_flip(bool enabled)
{
unsigned long flags;
int cpu, t;
cpus_read_lock();
/*
* Toggle the online cores , one by one .
*/
cpumask_copy(&sched_core_mask, cpu_online_mask);
for_each_cpu(cpu, &sched_core_mask) {
const struct cpumask *smt_mask = cpu_smt_mask(cpu);
sched_core_lock(cpu, &flags);
for_each_cpu(t, smt_mask)
cpu_rq(t)->core_enabled = enabled;
cpu_rq(cpu)->core->core_forceidle_start = 0 ;
sched_core_unlock(cpu, &flags);
cpumask_andnot(&sched_core_mask, &sched_core_mask, smt_mask);
}
/*
* Toggle the offline CPUs .
*/
for_each_cpu_andnot(cpu, cpu_possible_mask, cpu_online_mask)
cpu_rq(cpu)->core_enabled = enabled;
cpus_read_unlock();
}
static void sched_core_assert_empty(void )
{
int cpu;
for_each_possible_cpu(cpu)
WARN_ON_ONCE(!RB_EMPTY_ROOT(&cpu_rq(cpu)->core_tree));
}
static void __sched_core_enable(void )
{
static_branch_enable(&__sched_core_enabled);
/*
* Ensure all previous instances of raw_spin_rq_ * lock ( ) have finished
* and future ones will observe ! sched_core_disabled ( ) .
*/
synchronize_rcu();
__sched_core_flip(true );
sched_core_assert_empty();
}
static void __sched_core_disable(void )
{
sched_core_assert_empty();
__sched_core_flip(false );
static_branch_disable(&__sched_core_enabled);
}
void sched_core_get(void )
{
if (atomic_inc_not_zero(&sched_core_count))
return ;
mutex_lock(&sched_core_mutex);
if (!atomic_read(&sched_core_count))
__sched_core_enable();
smp_mb__before_atomic();
atomic_inc(&sched_core_count);
mutex_unlock(&sched_core_mutex);
}
static void __sched_core_put(struct work_struct *work)
{
if (atomic_dec_and_mutex_lock(&sched_core_count, &sched_core_mutex)) {
__sched_core_disable();
mutex_unlock(&sched_core_mutex);
}
}
void sched_core_put(void )
{
static DECLARE_WORK(_work, __sched_core_put);
/*
* " There can be only one "
*
* Either this is the last one , or we don ' t actually need to do any
* ' work ' . If it is the last * again * , we rely on
* WORK_STRUCT_PENDING_BIT .
*/
if (!atomic_add_unless(&sched_core_count, -1 , 1 ))
schedule_work(&_work);
}
#else /* !CONFIG_SCHED_CORE: */
static inline void sched_core_enqueue(struct rq *rq, struct task_struct *p) { }
static inline void
sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { }
#endif /* !CONFIG_SCHED_CORE */
/* need a wrapper since we may need to trace from modules */
EXPORT_TRACEPOINT_SYMBOL(sched_set_state_tp);
/* Call via the helper macro trace_set_current_state. */
void __trace_set_current_state(int state_value)
{
trace_sched_set_state_tp(current, state_value);
}
EXPORT_SYMBOL(__trace_set_current_state);
/*
* Serialization rules :
*
* Lock order :
*
* p - > pi_lock
* rq - > lock
* hrtimer_cpu_base - > lock ( hrtimer_start ( ) for bandwidth controls )
*
* rq1 - > lock
* rq2 - > lock where : rq1 < rq2
*
* Regular state :
*
* Normal scheduling state is serialized by rq - > lock . _ _ schedule ( ) takes the
* local CPU ' s rq - > lock , it optionally removes the task from the runqueue and
* always looks at the local rq data structures to find the most eligible task
* to run next .
*
* Task enqueue is also under rq - > lock , possibly taken from another CPU .
* Wakeups from another LLC domain might use an IPI to transfer the enqueue to
* the local CPU to avoid bouncing the runqueue state around [ see
* ttwu_queue_wakelist ( ) ]
*
* Task wakeup , specifically wakeups that involve migration , are horribly
* complicated to avoid having to take two rq - > locks .
*
* Special state :
*
* System - calls and anything external will use task_rq_lock ( ) which acquires
* both p - > pi_lock and rq - > lock . As a consequence the state they change is
* stable while holding either lock :
*
* - sched_setaffinity ( ) /
* set_cpus_allowed_ptr ( ) : p - > cpus_ptr , p - > nr_cpus_allowed
* - set_user_nice ( ) : p - > se . load , p - > * prio
* - _ _ sched_setscheduler ( ) : p - > sched_class , p - > policy , p - > * prio ,
* p - > se . load , p - > rt_priority ,
* p - > dl . dl_ { runtime , deadline , period , flags , bw , density }
* - sched_setnuma ( ) : p - > numa_preferred_nid
* - sched_move_task ( ) : p - > sched_task_group
* - uclamp_update_active ( ) p - > uclamp *
*
* p - > state < - TASK_ * :
*
* is changed locklessly using set_current_state ( ) , _ _ set_current_state ( ) or
* set_special_state ( ) , see their respective comments , or by
* try_to_wake_up ( ) . This latter uses p - > pi_lock to serialize against
* concurrent self .
*
* p - > on_rq < - { 0 , 1 = TASK_ON_RQ_QUEUED , 2 = TASK_ON_RQ_MIGRATING } :
*
* is set by activate_task ( ) and cleared by deactivate_task ( ) , under
* rq - > lock . Non - zero indicates the task is runnable , the special
* ON_RQ_MIGRATING state is used for migration without holding both
* rq - > locks . It indicates task_cpu ( ) is not stable , see task_rq_lock ( ) .
*
* Additionally it is possible to be - > on_rq but still be considered not
* runnable when p - > se . sched_delayed is true . These tasks are on the runqueue
* but will be dequeued as soon as they get picked again . See the
* task_is_runnable ( ) helper .
*
* p - > on_cpu < - { 0 , 1 } :
*
* is set by prepare_task ( ) and cleared by finish_task ( ) such that it will be
* set before p is scheduled - in and cleared after p is scheduled - out , both
* under rq - > lock . Non - zero indicates the task is running on its CPU .
*
* [ The astute reader will observe that it is possible for two tasks on one
* CPU to have - > on_cpu = 1 at the same time . ]
*
* task_cpu ( p ) : is changed by set_task_cpu ( ) , the rules are :
*
* - Don ' t call set_task_cpu ( ) on a blocked task :
*
* We don ' t care what CPU we ' re not running on , this simplifies hotplug ,
* the CPU assignment of blocked tasks isn ' t required to be valid .
*
* - for try_to_wake_up ( ) , called under p - > pi_lock :
*
* This allows try_to_wake_up ( ) to only take one rq - > lock , see its comment .
*
* - for migration called under rq - > lock :
* [ see task_on_rq_migrating ( ) in task_rq_lock ( ) ]
*
* o move_queued_task ( )
* o detach_task ( )
*
* - for migration called under double_rq_lock ( ) :
*
* o _ _ migrate_swap_task ( )
* o push_rt_task ( ) / pull_rt_task ( )
* o push_dl_task ( ) / pull_dl_task ( )
* o dl_task_offline_migration ( )
*
*/
void raw_spin_rq_lock_nested(struct rq *rq, int subclass)
{
raw_spinlock_t *lock;
/* Matches synchronize_rcu() in __sched_core_enable() */
preempt_disable();
if (sched_core_disabled()) {
raw_spin_lock_nested(&rq->__lock, subclass);
/* preempt_count *MUST* be > 1 */
preempt_enable_no_resched();
return ;
}
for (;;) {
lock = __rq_lockp(rq);
raw_spin_lock_nested(lock, subclass);
if (likely(lock == __rq_lockp(rq))) {
/* preempt_count *MUST* be > 1 */
preempt_enable_no_resched();
return ;
}
raw_spin_unlock(lock);
}
}
bool raw_spin_rq_trylock(struct rq *rq)
{
raw_spinlock_t *lock;
bool ret;
/* Matches synchronize_rcu() in __sched_core_enable() */
preempt_disable();
if (sched_core_disabled()) {
ret = raw_spin_trylock(&rq->__lock);
preempt_enable();
return ret;
}
for (;;) {
lock = __rq_lockp(rq);
ret = raw_spin_trylock(lock);
if (!ret || (likely(lock == __rq_lockp(rq)))) {
preempt_enable();
return ret;
}
raw_spin_unlock(lock);
}
}
void raw_spin_rq_unlock(struct rq *rq)
{
raw_spin_unlock(rq_lockp(rq));
}
/*
* double_rq_lock - safely lock two runqueues
*/
void double_rq_lock(struct rq *rq1, struct rq *rq2)
{
lockdep_assert_irqs_disabled();
if (rq_order_less(rq2, rq1))
swap(rq1, rq2);
raw_spin_rq_lock(rq1);
if (__rq_lockp(rq1) != __rq_lockp(rq2))
raw_spin_rq_lock_nested(rq2, SINGLE_DEPTH_NESTING);
double_rq_clock_clear_update(rq1, rq2);
}
/*
* _ _ task_rq_lock - lock the rq @ p resides on .
*/
struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf)
__acquires(rq->lock)
{
struct rq *rq;
lockdep_assert_held(&p->pi_lock);
for (;;) {
rq = task_rq(p);
raw_spin_rq_lock(rq);
if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
rq_pin_lock(rq, rf);
return rq;
}
raw_spin_rq_unlock(rq);
while (unlikely(task_on_rq_migrating(p)))
cpu_relax();
}
}
/*
* task_rq_lock - lock p - > pi_lock and lock the rq @ p resides on .
*/
struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
__acquires(p->pi_lock)
__acquires(rq->lock)
{
struct rq *rq;
for (;;) {
raw_spin_lock_irqsave(&p->pi_lock, rf->flags);
rq = task_rq(p);
raw_spin_rq_lock(rq);
/*
* move_queued_task ( ) task_rq_lock ( )
*
* ACQUIRE ( rq - > lock )
* [ S ] - > on_rq = MIGRATING [ L ] rq = task_rq ( )
* WMB ( _ _ set_task_cpu ( ) ) ACQUIRE ( rq - > lock ) ;
* [ S ] - > cpu = new_cpu [ L ] task_rq ( )
* [ L ] - > on_rq
* RELEASE ( rq - > lock )
*
* If we observe the old CPU in task_rq_lock ( ) , the acquire of
* the old rq - > lock will fully serialize against the stores .
*
* If we observe the new CPU in task_rq_lock ( ) , the address
* dependency headed by ' [ L ] rq = task_rq ( ) ' and the acquire
* will pair with the WMB to ensure we then also see migrating .
*/
if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
rq_pin_lock(rq, rf);
return rq;
}
raw_spin_rq_unlock(rq);
raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
while (unlikely(task_on_rq_migrating(p)))
cpu_relax();
}
}
/*
* RQ - clock updating methods :
*/
static void update_rq_clock_task(struct rq *rq, s64 delta)
{
/*
* In theory , the compile should just see 0 here , and optimize out the call
* to sched_rt_avg_update . But I don ' t trust it . . .
*/
s64 __maybe_unused steal = 0 , irq_delta = 0 ;
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
if (irqtime_enabled()) {
irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time;
/*
* Since irq_time is only updated on { soft , } irq_exit , we might run into
* this case when a previous update_rq_clock ( ) happened inside a
* { soft , } IRQ region .
*
* When this happens , we stop - > clock_task and only update the
* prev_irq_time stamp to account for the part that fit , so that a next
* update will consume the rest . This ensures - > clock_task is
* monotonic .
*
* It does however cause some slight miss - attribution of { soft , } IRQ
* time , a more accurate solution would be to update the irq_time using
* the current rq - > clock timestamp , except that would require using
* atomic ops .
*/
if (irq_delta > delta)
irq_delta = delta;
rq->prev_irq_time += irq_delta;
delta -= irq_delta;
delayacct_irq(rq->curr, irq_delta);
}
#endif
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
if (static_key_false((¶virt_steal_rq_enabled))) {
u64 prev_steal;
steal = prev_steal = paravirt_steal_clock(cpu_of(rq));
steal -= rq->prev_steal_time_rq;
if (unlikely(steal > delta))
steal = delta;
rq->prev_steal_time_rq = prev_steal;
delta -= steal;
}
#endif
rq->clock_task += delta;
#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
if ((irq_delta + steal) && sched_feat(NONTASK_CAPACITY))
update_irq_load_avg(rq, irq_delta + steal);
#endif
update_rq_clock_pelt(rq, delta);
}
void update_rq_clock(struct rq *rq)
{
s64 delta;
u64 clock;
lockdep_assert_rq_held(rq);
if (rq->clock_update_flags & RQCF_ACT_SKIP)
return ;
if (sched_feat(WARN_DOUBLE_CLOCK))
WARN_ON_ONCE(rq->clock_update_flags & RQCF_UPDATED);
rq->clock_update_flags |= RQCF_UPDATED;
clock = sched_clock_cpu(cpu_of(rq));
scx_rq_clock_update(rq, clock);
delta = clock - rq->clock;
if (delta < 0 )
return ;
rq->clock += delta;
update_rq_clock_task(rq, delta);
}
#ifdef CONFIG_SCHED_HRTICK
/*
* Use HR - timers to deliver accurate preemption points .
*/
static void hrtick_clear(struct rq *rq)
{
if (hrtimer_active(&rq->hrtick_timer))
hrtimer_cancel(&rq->hrtick_timer);
}
/*
* High - resolution timer tick .
* Runs from hardirq context with interrupts disabled .
*/
static enum hrtimer_restart hrtick(struct hrtimer *timer)
{
struct rq *rq = container_of(timer, struct rq, hrtick_timer);
struct rq_flags rf;
WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
rq_lock(rq, &rf);
update_rq_clock(rq);
rq->donor->sched_class->task_tick(rq, rq->curr, 1 );
rq_unlock(rq, &rf);
return HRTIMER_NORESTART;
}
static void __hrtick_restart(struct rq *rq)
{
struct hrtimer *timer = &rq->hrtick_timer;
ktime_t time = rq->hrtick_time;
hrtimer_start(timer, time, HRTIMER_MODE_ABS_PINNED_HARD);
}
/*
* called from hardirq ( IPI ) context
*/
static void __hrtick_start(void *arg)
{
struct rq *rq = arg;
struct rq_flags rf;
rq_lock(rq, &rf);
__hrtick_restart(rq);
rq_unlock(rq, &rf);
}
/*
* Called to set the hrtick timer state .
*
* called with rq - > lock held and IRQs disabled
*/
void hrtick_start(struct rq *rq, u64 delay)
{
struct hrtimer *timer = &rq->hrtick_timer;
s64 delta;
/*
* Don ' t schedule slices shorter than 10000 ns , that just
* doesn ' t make sense and can cause timer DoS .
*/
delta = max_t(s64, delay, 10000 LL);
rq->hrtick_time = ktime_add_ns(timer->base->get_time(), delta);
if (rq == this_rq())
__hrtick_restart(rq);
else
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
}
static void hrtick_rq_init(struct rq *rq)
{
INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
}
#else /* !CONFIG_SCHED_HRTICK: */
static inline void hrtick_clear(struct rq *rq)
{
}
static inline void hrtick_rq_init(struct rq *rq)
{
}
#endif /* !CONFIG_SCHED_HRTICK */
/*
* try_cmpxchg based fetch_or ( ) macro so it works for different integer types :
*/
#define fetch_or(ptr, mask) \
({ \
typeof(ptr) _ptr = (ptr); \
typeof(mask) _mask = (mask); \
typeof(*_ptr) _val = *_ptr; \
\
do { \
} while (!try_cmpxchg(_ptr, &_val, _val | _mask)); \
_val; \
})
#ifdef TIF_POLLING_NRFLAG
/*
* Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG ,
* this avoids any races wrt polling state changes and thereby avoids
* spurious IPIs .
*/
static inline bool set_nr_and_not_polling(struct thread_info *ti, int tif)
{
return !(fetch_or(&ti->flags, 1 << tif) & _TIF_POLLING_NRFLAG);
}
/*
* Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set .
*
* If this returns true , then the idle task promises to call
* sched_ttwu_pending ( ) and reschedule soon .
*/
static bool set_nr_if_polling(struct task_struct *p)
{
struct thread_info *ti = task_thread_info(p);
typeof(ti->flags) val = READ_ONCE(ti->flags);
do {
if (!(val & _TIF_POLLING_NRFLAG))
return false ;
if (val & _TIF_NEED_RESCHED)
return true ;
} while (!try_cmpxchg(&ti->flags, &val, val | _TIF_NEED_RESCHED));
return true ;
}
#else
static inline bool set_nr_and_not_polling(struct thread_info *ti, int tif)
{
set_ti_thread_flag(ti, tif);
return true ;
}
static inline bool set_nr_if_polling(struct task_struct *p)
{
return false ;
}
#endif
static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
{
struct wake_q_node *node = &task->wake_q;
/*
* Atomically grab the task , if - > wake_q is ! nil already it means
* it ' s already queued ( either by us or someone else ) and will get the
* wakeup due to that .
*
* In order to ensure that a pending wakeup will observe our pending
* state , even in the failed case , an explicit smp_mb ( ) must be used .
*/
smp_mb__before_atomic();
if (unlikely(cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL)))
return false ;
/*
* The head is context local , there can be no concurrency .
*/
*head->lastp = node;
head->lastp = &node->next;
return true ;
}
/**
* wake_q_add ( ) - queue a wakeup for ' later ' waking .
* @ head : the wake_q_head to add @ task to
* @ task : the task to queue for ' later ' wakeup
*
* Queue a task for later wakeup , most likely by the wake_up_q ( ) call in the
* same context , _ HOWEVER_ this is not guaranteed , the wakeup can come
* instantly .
*
* This function must be used as - if it were wake_up_process ( ) ; IOW the task
* must be ready to be woken at this location .
*/
void wake_q_add(struct wake_q_head *head, struct task_struct *task)
{
if (__wake_q_add(head, task))
get_task_struct(task);
}
/**
* wake_q_add_safe ( ) - safely queue a wakeup for ' later ' waking .
* @ head : the wake_q_head to add @ task to
* @ task : the task to queue for ' later ' wakeup
*
* Queue a task for later wakeup , most likely by the wake_up_q ( ) call in the
* same context , _ HOWEVER_ this is not guaranteed , the wakeup can come
* instantly .
*
* This function must be used as - if it were wake_up_process ( ) ; IOW the task
* must be ready to be woken at this location .
*
* This function is essentially a task - safe equivalent to wake_q_add ( ) . Callers
* that already hold reference to @ task can call the ' safe ' version and trust
* wake_q to do the right thing depending whether or not the @ task is already
* queued for wakeup .
*/
void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)
{
if (!__wake_q_add(head, task))
put_task_struct(task);
}
void wake_up_q(struct wake_q_head *head)
{
struct wake_q_node *node = head->first;
while (node != WAKE_Q_TAIL) {
struct task_struct *task;
task = container_of(node, struct task_struct, wake_q);
node = node->next;
/* pairs with cmpxchg_relaxed() in __wake_q_add() */
WRITE_ONCE(task->wake_q.next, NULL);
/* Task can safely be re-inserted now. */
/*
* wake_up_process ( ) executes a full barrier , which pairs with
* the queueing in wake_q_add ( ) so as not to miss wakeups .
*/
wake_up_process(task);
put_task_struct(task);
}
}
/*
* resched_curr - mark rq ' s current task ' to be rescheduled now ' .
*
* On UP this means the setting of the need_resched flag , on SMP it
* might also involve a cross - CPU call to trigger the scheduler on
* the target CPU .
*/
static void __resched_curr(struct rq *rq, int tif)
{
struct task_struct *curr = rq->curr;
struct thread_info *cti = task_thread_info(curr);
int cpu;
lockdep_assert_rq_held(rq);
/*
* Always immediately preempt the idle task ; no point in delaying doing
* actual work .
*/
if (is_idle_task(curr) && tif == TIF_NEED_RESCHED_LAZY)
tif = TIF_NEED_RESCHED;
if (cti->flags & ((1 << tif) | _TIF_NEED_RESCHED))
return ;
cpu = cpu_of(rq);
trace_sched_set_need_resched_tp(curr, cpu, tif);
if (cpu == smp_processor_id()) {
set_ti_thread_flag(cti, tif);
if (tif == TIF_NEED_RESCHED)
set_preempt_need_resched();
return ;
}
if (set_nr_and_not_polling(cti, tif)) {
if (tif == TIF_NEED_RESCHED)
smp_send_reschedule(cpu);
} else {
trace_sched_wake_idle_without_ipi(cpu);
}
}
void __trace_set_need_resched(struct task_struct *curr, int tif)
{
trace_sched_set_need_resched_tp(curr, smp_processor_id(), tif);
}
void resched_curr(struct rq *rq)
{
__resched_curr(rq, TIF_NEED_RESCHED);
}
#ifdef CONFIG_PREEMPT_DYNAMIC
static DEFINE_STATIC_KEY_FALSE(sk_dynamic_preempt_lazy);
static __always_inline bool dynamic_preempt_lazy(void )
{
return static_branch_unlikely(&sk_dynamic_preempt_lazy);
}
#else
static __always_inline bool dynamic_preempt_lazy(void )
{
return IS_ENABLED(CONFIG_PREEMPT_LAZY);
}
#endif
static __always_inline int get_lazy_tif_bit(void )
{
if (dynamic_preempt_lazy())
return TIF_NEED_RESCHED_LAZY;
return TIF_NEED_RESCHED;
}
void resched_curr_lazy(struct rq *rq)
{
__resched_curr(rq, get_lazy_tif_bit());
}
void resched_cpu(int cpu)
{
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
raw_spin_rq_lock_irqsave(rq, flags);
if (cpu_online(cpu) || cpu == smp_processor_id())
resched_curr(rq);
raw_spin_rq_unlock_irqrestore(rq, flags);
}
#ifdef CONFIG_NO_HZ_COMMON
/*
* In the semi idle case , use the nearest busy CPU for migrating timers
* from an idle CPU . This is good for power - savings .
*
* We don ' t do similar optimization for completely idle system , as
* selecting an idle CPU will add more delays to the timers than intended
* ( as that CPU ' s timer base may not be up to date wrt jiffies etc ) .
*/
int get_nohz_timer_target(void )
{
int i, cpu = smp_processor_id(), default_cpu = -1 ;
struct sched_domain *sd;
const struct cpumask *hk_mask;
if (housekeeping_cpu(cpu, HK_TYPE_KERNEL_NOISE)) {
if (!idle_cpu(cpu))
return cpu;
default_cpu = cpu;
}
hk_mask = housekeeping_cpumask(HK_TYPE_KERNEL_NOISE);
guard(rcu)();
for_each_domain(cpu, sd) {
for_each_cpu_and(i, sched_domain_span(sd), hk_mask) {
if (cpu == i)
continue ;
if (!idle_cpu(i))
return i;
}
}
if (default_cpu == -1 )
default_cpu = housekeeping_any_cpu(HK_TYPE_KERNEL_NOISE);
return default_cpu;
}
/*
* When add_timer_on ( ) enqueues a timer into the timer wheel of an
* idle CPU then this timer might expire before the next timer event
* which is scheduled to wake up that CPU . In case of a completely
* idle system the next event might even be infinite time into the
* future . wake_up_idle_cpu ( ) ensures that the CPU is woken up and
* leaves the inner idle loop so the newly added timer is taken into
* account when the CPU goes back to idle and evaluates the timer
* wheel for the next timer event .
*/
static void wake_up_idle_cpu(int cpu)
{
struct rq *rq = cpu_rq(cpu);
if (cpu == smp_processor_id())
return ;
/*
* Set TIF_NEED_RESCHED and send an IPI if in the non - polling
* part of the idle loop . This forces an exit from the idle loop
* and a round trip to schedule ( ) . Now this could be optimized
* because a simple new idle loop iteration is enough to
* re - evaluate the next tick . Provided some re - ordering of tick
* nohz functions that would need to follow TIF_NR_POLLING
* clearing :
*
* - On most architectures , a simple fetch_or on ti : : flags with a
* " 0 " value would be enough to know if an IPI needs to be sent .
*
* - x86 needs to perform a last need_resched ( ) check between
* monitor and mwait which doesn ' t take timers into account .
* There a dedicated TIF_TIMER flag would be required to
* fetch_or here and be checked along with TIF_NEED_RESCHED
* before mwait ( ) .
*
* However , remote timer enqueue is not such a frequent event
* and testing of the above solutions didn ' t appear to report
* much benefits .
*/
if (set_nr_and_not_polling(task_thread_info(rq->idle), TIF_NEED_RESCHED))
smp_send_reschedule(cpu);
else
trace_sched_wake_idle_without_ipi(cpu);
}
static bool wake_up_full_nohz_cpu(int cpu)
{
/*
* We just need the target to call irq_exit ( ) and re - evaluate
* the next tick . The nohz full kick at least implies that .
* If needed we can still optimize that later with an
* empty IRQ .
*/
if (cpu_is_offline(cpu))
return true ; /* Don't try to wake offline CPUs. */
if (tick_nohz_full_cpu(cpu)) {
if (cpu != smp_processor_id() ||
tick_nohz_tick_stopped())
tick_nohz_full_kick_cpu(cpu);
return true ;
}
return false ;
}
/*
* Wake up the specified CPU . If the CPU is going offline , it is the
* caller ' s responsibility to deal with the lost wakeup , for example ,
* by hooking into the CPU_DEAD notifier like timers and hrtimers do .
*/
void wake_up_nohz_cpu(int cpu)
{
if (!wake_up_full_nohz_cpu(cpu))
wake_up_idle_cpu(cpu);
}
static void nohz_csd_func(void *info)
{
struct rq *rq = info;
int cpu = cpu_of(rq);
unsigned int flags;
/*
* Release the rq : : nohz_csd .
*/
flags = atomic_fetch_andnot(NOHZ_KICK_MASK | NOHZ_NEWILB_KICK, nohz_flags(cpu));
WARN_ON(!(flags & NOHZ_KICK_MASK));
rq->idle_balance = idle_cpu(cpu);
if (rq->idle_balance) {
rq->nohz_idle_balance = flags;
__raise_softirq_irqoff(SCHED_SOFTIRQ);
}
}
#endif /* CONFIG_NO_HZ_COMMON */
#ifdef CONFIG_NO_HZ_FULL
static inline bool __need_bw_check(struct rq *rq, struct task_struct *p)
{
if (rq->nr_running != 1 )
return false ;
if (p->sched_class != &fair_sched_class)
return false ;
if (!task_on_rq_queued(p))
return false ;
return true ;
}
bool sched_can_stop_tick(struct rq *rq)
{
int fifo_nr_running;
/* Deadline tasks, even if single, need the tick */
if (rq->dl.dl_nr_running)
return false ;
/*
* If there are more than one RR tasks , we need the tick to affect the
* actual RR behaviour .
*/
if (rq->rt.rr_nr_running) {
if (rq->rt.rr_nr_running == 1 )
return true ;
else
return false ;
}
/*
* If there ' s no RR tasks , but FIFO tasks , we can skip the tick , no
* forced preemption between FIFO tasks .
*/
fifo_nr_running = rq->rt.rt_nr_running - rq->rt.rr_nr_running;
if (fifo_nr_running)
return true ;
/*
* If there are no DL , RR / FIFO tasks , there must only be CFS or SCX tasks
* left . For CFS , if there ' s more than one we need the tick for
* involuntary preemption . For SCX , ask .
*/
if (scx_enabled() && !scx_can_stop_tick(rq))
return false ;
if (rq->cfs.h_nr_queued > 1 )
return false ;
/*
* If there is one task and it has CFS runtime bandwidth constraints
* and it ' s on the cpu now we don ' t want to stop the tick .
* This check prevents clearing the bit if a newly enqueued task here is
* dequeued by migrating while the constrained task continues to run .
* E . g . going from 2 - > 1 without going through pick_next_task ( ) .
* /
if ( _ _ need_bw_check ( rq , rq - > curr ) ) {
if ( cfs_task_bw_constrained ( rq - > curr ) )
return false ;
}
return true ;
}
# endif #endif /* CONFIG_NO_HZ_FULL */
#if defined (CONFIG_RT_GROUP_SCHED) || defined (CONFIG_FAIR_GROUP_SCHED)
/*
* Iterate task_group tree rooted at * from , calling @ down when first entering a
* node and @ up when leaving it for the final time .
*
* Caller must hold rcu_lock or sufficient equivalent .
*/
int walk_tg_tree_from(struct task_group *from,
tg_visitor down, tg_visitor up, void *data)
{
struct task_group *parent, *child;
int ret;
parent = from;
down:
ret = (*down)(parent, data);
if (ret)
goto out;
list_for_each_entry_rcu(child, &parent->children, siblings) {
parent = child;
goto down;
up:
continue ;
}
ret = (*up)(parent, data);
if (ret || parent == from)
goto out;
child = parent;
parent = parent->parent;
if (parent)
goto up;
out:
return ret;
}
int tg_nop(struct task_group *tg, void *data)
{
return 0 ;
}
#endif
void set_load_weight(struct task_struct *p, bool update_load)
{
int prio = p->static_prio - MAX_RT_PRIO;
struct load_weight lw;
if (task_has_idle_policy(p)) {
lw.weight = scale_load(WEIGHT_IDLEPRIO);
lw.inv_weight = WMULT_IDLEPRIO;
} else {
lw.weight = scale_load(sched_prio_to_weight[prio]);
lw.inv_weight = sched_prio_to_wmult[prio];
}
/*
* SCHED_OTHER tasks have to update their load when changing their
* weight
*/
if (update_load && p->sched_class->reweight_task)
p->sched_class->reweight_task(task_rq(p), p, &lw);
else
p->se.load = lw;
}
#ifdef CONFIG_UCLAMP_TASK
/*
* Serializes updates of utilization clamp values
*
* The ( slow - path ) user - space triggers utilization clamp value updates which
* can require updates on ( fast - path ) scheduler ' s data structures used to
* support enqueue / dequeue operations .
* While the per - CPU rq lock protects fast - path update operations , user - space
* requests are serialized using a mutex to reduce the risk of conflicting
* updates or API abuses .
*/
static __maybe_unused DEFINE_MUTEX(uclamp_mutex);
/* Max allowed minimum utilization */
static unsigned int __maybe_unused sysctl_sched_uclamp_util_min = SCHED_CAPACITY_SCALE;
/* Max allowed maximum utilization */
static unsigned int __maybe_unused sysctl_sched_uclamp_util_max = SCHED_CAPACITY_SCALE;
/*
* By default RT tasks run at the maximum performance point / capacity of the
* system . Uclamp enforces this by always setting UCLAMP_MIN of RT tasks to
* SCHED_CAPACITY_SCALE .
*
* This knob allows admins to change the default behavior when uclamp is being
* used . In battery powered devices , particularly , running at the maximum
* capacity and frequency will increase energy consumption and shorten the
* battery life .
*
* This knob only affects RT tasks that their uclamp_se - > user_defined = = false .
*
* This knob will not override the system default sched_util_clamp_min defined
* above .
*/
unsigned int sysctl_sched_uclamp_util_min_rt_default = SCHED_CAPACITY_SCALE;
/* All clamps are required to be less or equal than these values */
static struct uclamp_se uclamp_default[UCLAMP_CNT];
/*
* This static key is used to reduce the uclamp overhead in the fast path . It
* primarily disables the call to uclamp_rq_ { inc , dec } ( ) in
* enqueue / dequeue_task ( ) .
*
* This allows users to continue to enable uclamp in their kernel config with
* minimum uclamp overhead in the fast path .
*
* As soon as userspace modifies any of the uclamp knobs , the static key is
* enabled , since we have an actual users that make use of uclamp
* functionality .
*
* The knobs that would enable this static key are :
*
* * A task modifying its uclamp value with sched_setattr ( ) .
* * An admin modifying the sysctl_sched_uclamp_ { min , max } via procfs .
* * An admin modifying the cgroup cpu . uclamp . { min , max }
*/
DEFINE_STATIC_KEY_FALSE(sched_uclamp_used);
static inline unsigned int
uclamp_idle_value(struct rq *rq, enum uclamp_id clamp_id,
unsigned int clamp_value)
{
/*
* Avoid blocked utilization pushing up the frequency when we go
* idle ( which drops the max - clamp ) by retaining the last known
* max - clamp .
*/
if (clamp_id == UCLAMP_MAX) {
rq->uclamp_flags |= UCLAMP_FLAG_IDLE;
return clamp_value;
}
return uclamp_none(UCLAMP_MIN);
}
static inline void uclamp_idle_reset(struct rq *rq, enum uclamp_id clamp_id,
unsigned int clamp_value)
{
/* Reset max-clamp retention only on idle exit */
if (!(rq->uclamp_flags & UCLAMP_FLAG_IDLE))
return ;
uclamp_rq_set(rq, clamp_id, clamp_value);
}
static inline
unsigned int uclamp_rq_max_value(struct rq *rq, enum uclamp_id clamp_id,
unsigned int clamp_value)
{
struct uclamp_bucket *bucket = rq->uclamp[clamp_id].bucket;
int bucket_id = UCLAMP_BUCKETS - 1 ;
/*
* Since both min and max clamps are max aggregated , find the
* top most bucket with tasks in .
*/
for ( ; bucket_id >= 0 ; bucket_id--) {
if (!bucket[bucket_id].tasks)
continue ;
return bucket[bucket_id].value;
}
/* No tasks -- default clamp values */
return uclamp_idle_value(rq, clamp_id, clamp_value);
}
static void __uclamp_update_util_min_rt_default(struct task_struct *p)
{
unsigned int default_util_min;
struct uclamp_se *uc_se;
lockdep_assert_held(&p->pi_lock);
uc_se = &p->uclamp_req[UCLAMP_MIN];
/* Only sync if user didn't override the default */
if (uc_se->user_defined)
return ;
default_util_min = sysctl_sched_uclamp_util_min_rt_default;
uclamp_se_set(uc_se, default_util_min, false );
}
static void uclamp_update_util_min_rt_default(struct task_struct *p)
{
if (!rt_task(p))
return ;
/* Protect updates to p->uclamp_* */
guard(task_rq_lock)(p);
__uclamp_update_util_min_rt_default(p);
}
static inline struct uclamp_se
uclamp_tg_restrict(struct task_struct *p, enum uclamp_id clamp_id)
{
/* Copy by value as we could modify it */
struct uclamp_se uc_req = p->uclamp_req[clamp_id];
#ifdef CONFIG_UCLAMP_TASK_GROUP
unsigned int tg_min, tg_max, value;
/*
* Tasks in autogroups or root task group will be
* restricted by system defaults .
*/
if (task_group_is_autogroup(task_group(p)))
return uc_req;
if (task_group(p) == &root_task_group)
return uc_req;
tg_min = task_group(p)->uclamp[UCLAMP_MIN].value;
tg_max = task_group(p)->uclamp[UCLAMP_MAX].value;
value = uc_req.value;
value = clamp(value, tg_min, tg_max);
uclamp_se_set(&uc_req, value, false );
#endif
return uc_req;
}
/*
* The effective clamp bucket index of a task depends on , by increasing
* priority :
* - the task specific clamp value , when explicitly requested from userspace
* - the task group effective clamp value , for tasks not either in the root
* group or in an autogroup
* - the system default clamp value , defined by the sysadmin
*/
static inline struct uclamp_se
uclamp_eff_get(struct task_struct *p, enum uclamp_id clamp_id)
{
struct uclamp_se uc_req = uclamp_tg_restrict(p, clamp_id);
struct uclamp_se uc_max = uclamp_default[clamp_id];
/* System default restrictions always apply */
if (unlikely(uc_req.value > uc_max.value))
return uc_max;
return uc_req;
}
unsigned long uclamp_eff_value(struct task_struct *p, enum uclamp_id clamp_id)
{
struct uclamp_se uc_eff;
/* Task currently refcounted: use back-annotated (effective) value */
if (p->uclamp[clamp_id].active)
return (unsigned long )p->uclamp[clamp_id].value;
uc_eff = uclamp_eff_get(p, clamp_id);
return (unsigned long )uc_eff.value;
}
/*
* When a task is enqueued on a rq , the clamp bucket currently defined by the
* task ' s uclamp : : bucket_id is refcounted on that rq . This also immediately
* updates the rq ' s clamp value if required .
*
* Tasks can have a task - specific value requested from user - space , track
* within each bucket the maximum value for tasks refcounted in it .
* This " local max aggregation " allows to track the exact " requested " value
* for each bucket when all its RUNNABLE tasks require the same clamp .
*/
static inline void uclamp_rq_inc_id(struct rq *rq, struct task_struct *p,
enum uclamp_id clamp_id)
{
struct uclamp_rq *uc_rq = &rq->uclamp[clamp_id];
struct uclamp_se *uc_se = &p->uclamp[clamp_id];
struct uclamp_bucket *bucket;
lockdep_assert_rq_held(rq);
/* Update task effective clamp */
p->uclamp[clamp_id] = uclamp_eff_get(p, clamp_id);
bucket = &uc_rq->bucket[uc_se->bucket_id];
bucket->tasks++;
uc_se->active = true ;
uclamp_idle_reset(rq, clamp_id, uc_se->value);
/*
* Local max aggregation : rq buckets always track the max
* " requested " clamp value of its RUNNABLE tasks .
*/
if (bucket->tasks == 1 || uc_se->value > bucket->value)
bucket->value = uc_se->value;
if (uc_se->value > uclamp_rq_get(rq, clamp_id))
uclamp_rq_set(rq, clamp_id, uc_se->value);
}
/*
* When a task is dequeued from a rq , the clamp bucket refcounted by the task
* is released . If this is the last task reference counting the rq ' s max
* active clamp value , then the rq ' s clamp value is updated .
*
* Both refcounted tasks and rq ' s cached clamp values are expected to be
* always valid . If it ' s detected they are not , as defensive programming ,
* enforce the expected state and warn .
* /
static inline void uclamp_rq_dec_id ( struct rq * rq , struct task_struct * p ,
enum uclamp_id clamp_id )
{
struct uclamp_rq * uc_rq = & rq - > uclamp [ clamp_id ] ;
/ Samples are collected to form a timeline // (markers) used for filtering. The samples include both native stacks and
* bucket ;
unsigned < T MinInlineCapacity , class AllocPolicy >
rq_clamp
lockdep_assert_rq_held ) ;
/*
* If sched_uclamp_used was enabled after / / also save a shutdown profile if // after this point and all profiling stack labels should have been popped .
* we could end up java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
*
* In this case the uc_se - > active flag should be false since no uclamp
* accounting // correlating different Windows loaded within the same tab or frame element.
* here .
*
Need to careful of the the enqueue / dequeue
* problem too
*
* enqueue ( askA )
* // sched_uclamp_used gets enabled
* enqueue ( taskB java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
* )
* // Must not decrement bucket->tasks here
* dequeue ( taskB )
*
* where we could end up ProfilerStackCollector {
* bucket [ uc_se - bucket_id ]
*
* The following const ProfilingStackFrame & aFrame ) = 0 ;
*/
if java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 74
return // aCaptureOptions is NoStack.
bucket-[;
WARN_ON_ONCE
if (likely ProfilerStats
bucket->tasks
// Put profiling data into the//---------------------------------------------------------------------------
/*
* Keep " bool = ,
* java.lang.StringIndexOutOfBoundsException: Range [14, 13) out of bounds for length 53
* The rq clamp // profiler_save_profile_to_file when called from debugger.
) { java.lang.StringIndexOutOfBoundsException: Range [46, 41) out of bounds for length 46
*/
if (likely(bucket->
return ;
rq_clamp = uclamp_rq_get(rq, clamp_id// in the current process. The given function is invoked once for
/*
* Defensive programming : this should never happen . If it happens ,
* e . g . due to future modification , warn and fix up the expected value .
*/
WARN_ON_ONCE(bucket->value > rq_clamp);
if (bucket->value >= rq_clamp) {
bkt_clamp = uclamp_rq_max_value(rq, clamp_id, uc_se->value);
uclamp_rq_set(rq, clamp_id, bkt_clamp);
}
}
static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p, int flags)
{
enum uclamp_id clamp_id;
/*
* Avoid any overhead until uclamp is actually used by the userspace .
*
* The condition is constructed such that a NOP is generated when
* sched_uclamp_used is disabled .
*/
if (!uclamp_is_used())
return ;
if (unlikely(!p->sched_class->uclamp_enabled))
return ;
/* Only inc the delayed task which being woken up. */
if (p->se.sched_delayed && !(flags & ENQUEUE_DELAYED))
return ;
for_each_clamp_id(clamp_id)
uclamp_rq_inc_id(rq, p, clamp_id);
/* Reset clamp idle holding when there is one RUNNABLE task */
if (rq->uclamp_flags & UCLAMP_FLAG_IDLE)
rq->uclamp_flags &= ~UCLAMP_FLAG_IDLE;
}
static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p)
{
enum uclamp_id clamp_id;
/*
* Avoid any overhead until uclamp is actually used by the userspace .
*
* The condition is constructed such that a NOP is generated when
* sched_uclamp_used is disabled .
*/
if (!uclamp_is_used())
return ;
if (unlikely(!p->sched_class->uclamp_enabled))
return ;
if (p->se.sched_delayed)
return ;
for_each_clamp_id(clamp_id)
uclamp_rq_dec_id(rq, p, clamp_id);
}
static inline void uclamp_rq_reinc_id(struct rq *rq, struct task_struct *p,
enum uclamp_id clamp_id)
{
if (!p->uclamp[clamp_id].active)
return ;
uclamp_rq_dec_id(rq, p, clamp_id);
uclamp_rq_inc_id(rq, p, clamp_id);
/*
* Make sure to clear the idle flag if we ' ve transiently reached 0
* active tasks on rq .
*/
if (clamp_id == UCLAMP_MAX && (rq->uclamp_flags & UCLAMP_FLAG_IDLE))
rq->uclamp_flags &= ~UCLAMP_FLAG_IDLE;
}
static inline void
uclamp_update_active(struct task_struct *p)
{
enum uclamp_id clamp_id;
struct rq_flags rf;
struct rq *rq;
/*
* Lock the task and the rq where the task is ( or was ) queued .
*
* We might lock the ( previous ) rq of a ! RUNNABLE task , but that ' s the
* price to pay to safely serialize util_ { min , max } updates with
* enqueues , dequeues and migration operations .
* This is the same locking schema used by _ _ set_cpus_allowed_ptr ( ) .
*/
rq = task_rq_lock(p, &rf);
/*
* Setting the clamp bucket is serialized by task_rq_lock ( ) .
* If the task is not yet RUNNABLE and its task_struct is not
* affecting a valid clamp bucket , the next time it ' s enqueued ,
* it will already see the updated clamp bucket value .
*/
for_each_clamp_id(clamp_id)
uclamp_rq_reinc_id(rq, p, clamp_id);
task_rq_unlock(rq, p, &rf);
}
#ifdef CONFIG_UCLAMP_TASK_GROUP
static inline void
uclamp_update_active_tasks(struct cgroup_subsys_state *css)
{
struct css_task_iter it;
struct task_struct *p;
css_task_iter_start(css, 0 , &it);
while ((p = css_task_iter_next(&it)))
uclamp_update_active(p);
css_task_iter_end(&it);
}
static void cpu_util_update_eff(struct cgroup_subsys_state *css);
#endif
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_UCLAMP_TASK_GROUP
static void uclamp_update_root_tg(void )
{
struct task_group *tg = &root_task_group;
uclamp_se_set(&tg->uclamp_req[UCLAMP_MIN],
sysctl_sched_uclamp_util_min, false );
uclamp_se_set(&tg->uclamp_req[UCLAMP_MAX],
sysctl_sched_uclamp_util_max, false );
guard(rcu)();
cpu_util_update_eff(&root_task_group.css);
}
#else
static void uclamp_update_root_tg(void ) { }
#endif
static void uclamp_sync_util_min_rt_default(void )
{
struct task_struct *g, *p;
/*
* copy_process ( ) sysctl_uclamp
* uclamp_min_rt = X ;
* write_lock ( & tasklist_lock ) read_lock ( & tasklist_lock )
* // link thread smp_mb__after_spinlock()
* write_unlock ( & tasklist_lock ) read_unlock ( & tasklist_lock ) ;
* sched_post_fork ( ) for_each_process_thread ( )
* _ _ uclamp_sync_rt ( ) _ _ uclamp_sync_rt ( )
*
* Ensures that either sched_post_fork ( ) will observe the new
* uclamp_min_rt or for_each_process_thread ( ) will observe the new
* task .
*/
read_lock(&tasklist_lock);
smp_mb__after_spinlock();
read_unlock(&tasklist_lock);
guard(rcu)();
for_each_process_thread(g, p)
uclamp_update_util_min_rt_default(p);
}
static int sysctl_sched_uclamp_handler(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
bool update_root_tg = false ;
int old_min, old_max, old_min_rt;
int result;
guard(mutex)(&uclamp_mutex);
old_min = sysctl_sched_uclamp_util_min;
old_max = sysctl_sched_uclamp_util_max;
old_min_rt = sysctl_sched_uclamp_util_min_rt_default;
result = proc_dointvec(table, write, buffer, lenp, ppos);
if (result)
goto undo;
if (!write)
return 0 ;
if (sysctl_sched_uclamp_util_min > sysctl_sched_uclamp_util_max ||
sysctl_sched_uclamp_util_max > SCHED_CAPACITY_SCALE ||
sysctl_sched_uclamp_util_min_rt_default > SCHED_CAPACITY_SCALE) {
result = -EINVAL;
goto undo;
}
if (old_min != sysctl_sched_uclamp_util_min) {
uclamp_se_set(&uclamp_default[UCLAMP_MIN],
sysctl_sched_uclamp_util_min, false );
update_root_tg = true ;
}
if (old_max != sysctl_sched_uclamp_util_max) {
uclamp_se_set(&uclamp_default[UCLAMP_MAX],
sysctl_sched_uclamp_util_max, false );
update_root_tg = true ;
}
if (update_root_tg) {
sched_uclamp_enable();
uclamp_update_root_tg();
}
if (old_min_rt != sysctl_sched_uclamp_util_min_rt_default) {
sched_uclamp_enable();
uclamp_sync_util_min_rt_default();
}
/*
* We update all RUNNABLE tasks only when task groups are in use .
* Otherwise , keep it simple and do just a lazy update at each next
* task enqueue time .
*/
return 0 ;
undo:
sysctl_sched_uclamp_util_min = old_min;
sysctl_sched_uclamp_util_max = old_max;
sysctl_sched_uclamp_util_min_rt_default = old_min_rt;
return result;
}
#endif /* CONFIG_SYSCTL */
static void uclamp_fork(struct task_struct *p)
{
enum uclamp_id clamp_id;
/*
* We don ' t need to hold task_rq_lock ( ) when updating p - > uclamp_ * here
* as the task is still at its early fork stages .
*/
for_each_clamp_id(clamp_id)
p->uclamp[clamp_id].active = false ;
if (likely(!p->sched_reset_on_fork))
return ;
for_each_clamp_id(clamp_id) {
uclamp_se_set(&p->uclamp_req[clamp_id],
uclamp_none(clamp_id), false );
}
}
static void uclamp_post_fork(struct task_struct *p)
{
uclamp_update_util_min_rt_default(p);
}
static void __init init_uclamp_rq(struct rq *rq)
{
enum uclamp_id clamp_id;
struct uclamp_rq *uc_rq = rq->uclamp;
for_each_clamp_id(clamp_id) {
uc_rq[clamp_id] = (struct uclamp_rq) {
.value = uclamp_none(clamp_id)
};
}
rq->uclamp_flags = UCLAMP_FLAG_IDLE;
}
static void __init init_uclamp(void )
{
struct uclamp_se uc_max = {};
enum uclamp_id clamp_id;
int cpu;
for_each_possible_cpu(cpu)
init_uclamp_rq(cpu_rq(cpu));
for_each_clamp_id(clamp_id) {
uclamp_se_set(&init_task.uclamp_req[clamp_id],
uclamp_none(clamp_id), false );
}
/* System defaults allow max clamp values for both indexes */
uclamp_se_set(&uc_max, uclamp_none(UCLAMP_MAX), false );
for_each_clamp_id(clamp_id) {
uclamp_default[clamp_id] = uc_max;
#ifdef CONFIG_UCLAMP_TASK_GROUP
root_task_group.uclamp_req[clamp_id] = uc_max;
root_task_group.uclamp[clamp_id] = uc_max;
#endif
}
}
#else /* !CONFIG_UCLAMP_TASK: */
static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p, int flags) { }
static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p) { }
static inline void uclamp_fork(struct task_struct *p) { }
static inline void uclamp_post_fork(struct task_struct *p) { }
static inline void init_uclamp(void ) { }
#endif /* !CONFIG_UCLAMP_TASK */
bool sched_task_on_rq(struct task_struct *p)
{
return task_on_rq_queued(p);
}
unsigned long get_wchan(struct task_struct *p)
{
unsigned long ip = 0 ;
unsigned int state;
if (!p || p == current)
return 0 ;
/* Only get wchan if task is blocked and we can keep it that way. */
raw_spin_lock_irq(&p->pi_lock);
state = READ_ONCE(p->__state);
smp_rmb(); /* see try_to_wake_up() */
if (state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq)
ip = __get_wchan(p);
raw_spin_unlock_irq(&p->pi_lock);
return ip;
}
void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
{
if (!(flags & ENQUEUE_NOCLOCK))
update_rq_clock(rq);
/*
* Can be before - > enqueue_task ( ) because uclamp considers the
* ENQUEUE_DELAYED task before its - > sched_delayed gets cleared
* in - > enqueue_task ( ) .
*/
uclamp_rq_inc(rq, p, flags);
p->sched_class->enqueue_task(rq, p, flags);
psi_enqueue(p, flags);
if (!(flags & ENQUEUE_RESTORE))
sched_info_enqueue(rq, p);
if (sched_core_enabled(rq))
sched_core_enqueue(rq, p);
}
/*
* Must only return false when DEQUEUE_SLEEP .
*/
inline bool dequeue_task(struct rq *rq, struct task_struct *p, int flags)
{
if (sched_core_enabled(rq))
sched_core_dequeue(rq, p, flags);
if (!(flags & DEQUEUE_NOCLOCK))
update_rq_clock(rq);
if (!(flags & DEQUEUE_SAVE))
sched_info_dequeue(rq, p);
psi_dequeue(p, flags);
/*
* Must be before - > dequeue_task ( ) because - > dequeue_task ( ) can ' fail '
* and mark the task - > sched_delayed .
*/
uclamp_rq_dec(rq, p);
return p->sched_class->dequeue_task(rq, p, flags);
}
void activate_task(struct rq *rq, struct task_struct *p, int flags)
{
if (task_on_rq_migrating(p))
flags |= ENQUEUE_MIGRATED;
if (flags & ENQUEUE_MIGRATED)
sched_mm_cid_migrate_to(rq, p);
enqueue_task(rq, p, flags);
WRITE_ONCE(p->on_rq, TASK_ON_RQ_QUEUED);
ASSERT_EXCLUSIVE_WRITER(p->on_rq);
}
void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
{
WARN_ON_ONCE(flags & DEQUEUE_SLEEP);
WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
ASSERT_EXCLUSIVE_WRITER(p->on_rq);
/*
* Code explicitly relies on TASK_ON_RQ_MIGRATING begin set * before *
* dequeue_task ( ) and cleared * after * enqueue_task ( ) .
*/
dequeue_task(rq, p, flags);
}
static void block_task(struct rq *rq, struct task_struct *p, int flags)
{
if (dequeue_task(rq, p, DEQUEUE_SLEEP | flags))
__block_task(rq, p);
}
/**
* task_curr - is this task currently executing on a CPU ?
* @ p : the task in question .
*
* Return : 1 if the task is currently executing . 0 otherwise .
*/
inline int task_curr(const struct task_struct *p)
{
return cpu_curr(task_cpu(p)) == p;
}
/*
* - > switching_to ( ) is called with the pi_lock and rq_lock held and must not
* mess with locking .
*/
void check_class_changing(struct rq *rq, struct task_struct *p,
const struct sched_class *prev_class)
{
if (prev_class != p->sched_class && p->sched_class->switching_to)
p->sched_class->switching_to(rq, p);
}
/*
* switched_from , switched_to and prio_changed must _ NOT_ drop rq - > lock ,
* use the balance_callback list if you want balancing .
*
* this means any call to check_class_changed ( ) must be followed by a call to
* balance_callback ( ) .
*/
void check_class_changed(struct rq *rq, struct task_struct *p,
const struct sched_class *prev_class,
int oldprio)
{
if (prev_class != p->sched_class) {
if (prev_class->switched_from)
prev_class->switched_from(rq, p);
p->sched_class->switched_to(rq, p);
} else if (oldprio != p->prio || dl_task(p))
p->sched_class->prio_changed(rq, p, oldprio);
}
void wakeup_preempt(struct rq *rq, struct task_struct *p, int flags)
{
struct task_struct *donor = rq->donor;
if (p->sched_class == donor->sched_class)
donor->sched_class->wakeup_preempt(rq, p, flags);
else if (sched_class_above(p->sched_class, donor->sched_class))
resched_curr(rq);
/*
* A queue event has occurred , and we ' re going to schedule . In
* this case , we can save a useless back to back clock update .
*/
if (task_on_rq_queued(donor) && test_tsk_need_resched(rq->curr))
rq_clock_skip_update(rq);
}
static __always_inline
int __task_state_match(struct task_struct *p, unsigned int state)
{
if (READ_ONCE(p->__state) & state)
return 1 ;
if (READ_ONCE(p->saved_state) & state)
return -1 ;
return 0 ;
}
static __always_inline
int task_state_match(struct task_struct *p, unsigned int state)
{
/*
* Serialize against current_save_and_set_rtlock_wait_state ( ) ,
* current_restore_rtlock_saved_state ( ) , and _ _ refrigerator ( ) .
*/
guard(raw_spinlock_irq)(&p->pi_lock);
return __task_state_match(p, state);
}
/*
* wait_task_inactive - wait for a thread to unschedule .
*
* Wait for the thread to block in any of the states set in @ match_state .
* If it changes , i . e . @ p might have woken up , then return zero . When we
* succeed in waiting for @ p to be off its CPU , we return a positive number
* ( its total switch count ) . If a second call a short while later returns the
* same number , the caller can be sure that @ p has remained unscheduled the
* whole time .
*
* The caller must ensure that the task * will * unschedule sometime soon ,
* else this function might spin for a * long * time . This function can ' t
* be called with interrupts off , or it may introduce deadlock with
* smp_call_function ( ) if an IPI is sent by the same process we are
* waiting to become inactive .
*/
unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
{
int running, queued, match;
struct rq_flags rf;
unsigned long ncsw;
struct rq *rq;
for (;;) {
/*
* We do the initial early heuristics without holding
* any task - queue locks at all . We ' ll only try to get
* the runqueue lock when things look like they will
* work out !
*/
rq = task_rq(p);
/*
* If the task is actively running on another CPU
* still , just relax and busy - wait without holding
* any locks .
*
* NOTE ! Since we don ' t hold any locks , it ' s not
* even sure that " rq " stays as the right runqueue !
* But we don ' t care , since " task_on_cpu ( ) " will
* return false if the runqueue has changed and p
* is actually now running somewhere else !
* /
while ( task_on_cpu ( rq , p ) ) {
if ( ! task_state_match ( p , match_state ) )
return 0 ;
cpu_relax ( ) ;
}
/*
* Ok , time to look more closely ! We need the rq
* lock now , to be * sure * . If we ' re wrong , we ' ll
* just go back and repeat .
*/
rq = task_rq_lock(p, &rf);
/*
* If task is sched_delayed , force dequeue it , to avoid always
* hitting the tick timeout in the queued case
*/
if (p->se.sched_delayed)
dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED);
trace_sched_wait_task(p);
running = task_on_cpu(rq, p);
queued = task_on_rq_queued(p);
ncsw = 0 ;
if ((match = __task_state_match(p, match_state))) {
/*
* When matching on p - > saved_state , consider this task
* still queued so it will wait .
*/
if (match < 0 )
queued = 1 ;
ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
}
task_rq_unlock(rq, p, &rf);
/*
* If it changed from the expected state , bail out now .
*/
if (unlikely(!ncsw))
break ;
/*
* Was it really running after all now that we
* checked with the proper locks actually held ?
*
* Oops . Go back and try again . .
*/
if (unlikely(running)) {
cpu_relax();
continue ;
}
/*
* It ' s not enough that it ' s not actively running ,
* it must be off the runqueue _ entirely_ , and not
* preempted !
*
* So if it was still runnable ( but just not actively
* running right now ) , it ' s preempted , and we should
* yield - it could be a while .
*/
if (unlikely(queued)) {
ktime_t to = NSEC_PER_SEC / HZ;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_hrtimeout(&to, HRTIMER_MODE_REL_HARD);
continue ;
}
/*
* Ahh , all good . It wasn ' t running , and it wasn ' t
* runnable , which means that it will never become
* running in the future either . We ' re all done !
*/
break ;
}
return ncsw;
}
static void
__do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx);
static void migrate_disable_switch(struct rq *rq, struct task_struct *p)
{
struct affinity_context ac = {
.new_mask = cpumask_of(rq->cpu),
.flags = SCA_MIGRATE_DISABLE,
};
if (likely(!p->migration_disabled))
return ;
if (p->cpus_ptr != &p->cpus_mask)
return ;
/*
* Violates locking rules ! See comment in _ _ do_set_cpus_allowed ( ) .
*/
__do_set_cpus_allowed(p, &ac);
}
void migrate_disable(void )
{
struct task_struct *p = current;
if (p->migration_disabled) {
#ifdef CONFIG_DEBUG_PREEMPT
/*
* Warn about overflow half - way through the range .
*/
WARN_ON_ONCE((s16)p->migration_disabled < 0 );
#endif
p->migration_disabled++;
return ;
}
guard(preempt)();
this_rq()->nr_pinned++;
p->migration_disabled = 1 ;
}
EXPORT_SYMBOL_GPL(migrate_disable);
void migrate_enable(void )
{
struct task_struct *p = current;
struct affinity_context ac = {
.new_mask = &p->cpus_mask,
.flags = SCA_MIGRATE_ENABLE,
};
#ifdef CONFIG_DEBUG_PREEMPT
/*
* Check both overflow from migrate_disable ( ) and superfluous
* migrate_enable ( ) .
*/
if (WARN_ON_ONCE((s16)p->migration_disabled <= 0 ))
return ;
#endif
if (p->migration_disabled > 1 ) {
p->migration_disabled--;
return ;
}
/*
* Ensure stop_task runs either before or after this , and that
* _ _ set_cpus_allowed_ptr ( SCA_MIGRATE_ENABLE ) doesn ' t schedule ( ) .
*/
guard(preempt)();
if (p->cpus_ptr != &p->cpus_mask)
__set_cpus_allowed_ptr(p, &ac);
/*
* Mustn ' t clear migration_disabled ( ) until cpus_ptr points back at the
* regular cpus_mask , otherwise things that race ( eg .
* select_fallback_rq ) get confused .
*/
barrier();
p->migration_disabled = 0 ;
this_rq()->nr_pinned--;
}
EXPORT_SYMBOL_GPL(migrate_enable);
static inline bool rq_has_pinned_tasks(struct rq *rq)
{
return rq->nr_pinned;
}
/*
* Per - CPU kthreads are allowed to run on ! active & & online CPUs , see
* _ _ set_cpus_allowed_ptr ( ) and select_fallback_rq ( ) .
*/
static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
{
/* When not in the task's cpumask, no point in looking further. */
if (!task_allowed_on_cpu(p, cpu))
return false ;
/* migrate_disabled() must be allowed to finish. */
if (is_migration_disabled(p))
return cpu_online(cpu);
/* Non kernel threads are not allowed during either online or offline. */
if (!(p->flags & PF_KTHREAD))
return cpu_active(cpu);
/* KTHREAD_IS_PER_CPU is always allowed. */
if (kthread_is_per_cpu(p))
return cpu_online(cpu);
/* Regular kernel threads don't get to stay during offline. */
if (cpu_dying(cpu))
return false ;
/* But are allowed during online. */
return cpu_online(cpu);
}
/*
* This is how migration works :
*
* 1 ) we invoke migration_cpu_stop ( ) on the target CPU using
* stop_one_cpu ( ) .
* 2 ) stopper starts to run ( implicitly forcing the migrated thread
* off the CPU )
* 3 ) it checks whether the migrated task is still in the wrong runqueue .
* 4 ) if it ' s in the wrong runqueue then the migration thread removes
* it and puts it into the right queue .
* 5 ) stopper completes and stop_one_cpu ( ) returns and the migration
* is done .
*/
/*
* move_queued_task - move a queued task to new rq .
*
* Returns ( locked ) new rq . Old rq ' s lock is released .
*/
static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
struct task_struct *p, int new_cpu)
{
lockdep_assert_rq_held(rq);
deactivate_task(rq, p, DEQUEUE_NOCLOCK);
set_task_cpu(p, new_cpu);
rq_unlock(rq, rf);
rq = cpu_rq(new_cpu);
rq_lock(rq, rf);
WARN_ON_ONCE(task_cpu(p) != new_cpu);
activate_task(rq, p, 0 );
wakeup_preempt(rq, p, 0 );
return rq;
}
struct migration_arg {
struct task_struct *task;
int dest_cpu;
struct set_affinity_pending *pending;
};
/*
* @ refs : number of wait_for_completion ( )
* @ stop_pending : is @ stop_work in use
*/
struct set_affinity_pending {
refcount_t refs;
unsigned int stop_pending;
struct completion done;
struct cpu_stop_work stop_work;
struct migration_arg arg;
};
/*
* Move ( not current ) task off this CPU , onto the destination CPU . We ' re doing
* this because either it can ' t run here any more ( set_cpus_allowed ( )
* from this CPU , or going ) , because we ' re
on exec s )
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
id . , }
* } java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
*/
_struct rqstruct *f
nt dest_cpu)
/
id = java.lang.StringIndexOutOfBoundsException: Range [36, 29) out of bounds for length 40
return rq ;
rq = ( rq , rf , dest_cpu ;
return rq ;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/* java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
* will by -prio stopper
* and performs thread migration by bumping thread off CPU then
* ' pushing ' onto another runqueue .
*/
taticint ( data
{
struct migration_arg(;
struct java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 32
struct task_struct *{
struct rq *rq = this_rq();
bool cfg80211_inform_bss inform_bss={
struct java.lang.StringIndexOutOfBoundsException: Range [5, 4) out of bounds for length 33
originaltarget might gonedown we java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
_
java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 4
java.lang.StringIndexOutOfBoundsException: Range [18, 15) out of bounds for length 26
*
* We need toskb_put_u8(input,WLAN_EID_SSID)
*java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
* wakeups ) test
/
)
test,link_bss;
rq_lock(rq, &rf);
/*
were passed then > was set , thus
* p - > migration_pending must have remained stable .
*/
WARN_ON_ONCE(pending && pending != p->migration_pending);
/*
* If task_rq ( add_junk ;
rq > lock , if p - > on_rq = = 0 it cannot get enqueued because
* .des c java.lang.StringIndexOutOfBoundsException: Range [40, 38) out of bounds for length 40
*/
if (desc java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 30
if ijava.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 31
goto out;
if
cfg80211_parse_colocated_apjava.lang.StringIndexOutOfBoundsException: Range [86, 85) out of bounds for length 92
complete
cpumask_test_cpup,&-cpus_mask)
out
}
java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 29
struct inform_bss_test_cases
} {
p->java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 3
}
/*
* XXX _ _ migrate_task ( ) can fail , at which point we might end
* up running on a dodgy CPU , AFAICT this can only happen
* during CPU hotplug , at which point we ' ll get pushed out
* anyway , so it ' s probably not a big deal .
*/
} else if (pending) {
/*
* This happens when we get migrated between migrate_enable ( ) ' s
* preempt_enable ( ) and scheduling the stopper task . At that
* point we ' re a regular task again and not current anymore .
*
* A ! PREEMPT kernel has a giant hole here , which makes it far
* more likely .
*/
/*
* The task moved before the stopper got to run . We ' re holding
* - > pi_lock , so the allowed mask is stable - if it got
* somewhere allowed , we ' re done .
*/
if (cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
p->migration_pending = NULL;
complete = true ;
goto out;
}
/*
* When migrate_enable ( ) hits a rq mis - match we can ' t reliably
* determine is_migration_disabled ( ) and so have to chase after
* it .
*/
WARN_ON_ONCE(!pending->stop_pending);
preempt_disable();
task_rq_unlock(rq, p, &rf);
stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
&pending->arg, &pending->stop_work);
preempt_enable();
return 0 ;
}
out:
if (pending)
pending->stop_pending = false ;
task_rq_unlock(rq, p, &rf);
if (complete)
complete_all(&pending->done);
return 0 ;
}
int push_cpu_stop(void *arg)
{
struct rq *lowest_rq = NULL, *rq = this_rq();
struct task_struct *p = arg;
raw_spin_lock_irq(&p->pi_lock);
raw_spin_rq_lock(rq);
if (task_rq(p) != rq)
goto out_unlock;
if (is_migration_disabled(p)) {
p->migration_flags |= MDF_PUSH;
goto out_unlock;
}
p->migration_flags &= ~MDF_PUSH;
if (p->sched_class->find_lock_rq)
lowest_rq = p->sched_class->find_lock_rq(p, rq);
if (!lowest_rq)
goto out_unlock;
// XXX validate p is still the highest prio task
if (task_rq(p) == rq) {
move_queued_task_locked(rq, lowest_rq, p);
resched_curr(lowest_rq);
}
double_unlock_balance(rq, lowest_rq);
out_unlock:
rq->push_busy = false ;
raw_spin_rq_unlock(rq);
raw_spin_unlock_irq(&p->pi_lock);
put_task_struct(p);
return 0 ;
}
/*
* sched_class : : set_cpus_allowed must do the below , but is not required to
* actually call this function .
*/
void set_cpus_allowed_common(struct task_struct *p, struct affinity_context *ctx)
{
if (ctx->flags & (SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) {
p->cpus_ptr = ctx->new_mask;
return ;
}
cpumask_copy(&p->cpus_mask, ctx->new_mask);
p->nr_cpus_allowed = cpumask_weight(ctx->new_mask);
/*
* Swap in a new user_cpus_ptr if SCA_USER flag set
*/
if (ctx->flags & SCA_USER)
swap(p->user_cpus_ptr, ctx->user_mask);
}
static void
__do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx)
{
struct rq *rq = task_rq(p);
bool queued, running;
/*
* This here violates the locking rules for affinity , since we ' re only
* supposed to change these variables while holding both rq - > lock and
* p - > pi_lock .
*
* HOWEVER , it magically works , because ttwu ( ) is the only code that
* accesses these variables under p - > pi_lock and only does so after
* smp_cond_load_acquire ( & p - > on_cpu , ! VAL ) , and we ' re in _ _ schedule ( )
* before finish_task ( ) .
*
* XXX do further audits , this smells like something putrid .
*/
if (ctx->flags & SCA_MIGRATE_DISABLE)
WARN_ON_ONCE(!p->on_cpu);
else
lockdep_assert_held(&p->pi_lock);
queued = task_on_rq_queued(p);
running = task_current_donor(rq, p);
if (queued) {
/*
* Because _ _ kthread_bind ( ) calls this on blocked tasks without
* holding rq - > lock .
*/
lockdep_assert_rq_held(rq);
dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);
}
if (running)
put_prev_task(rq, p);
p->sched_class->set_cpus_allowed(p, ctx);
mm_set_cpus_allowed(p->mm, ctx->new_mask);
if (queued)
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
if (running)
set_next_task(rq, p);
}
/*
* Used for kthread_bind ( ) and select_fallback_rq ( ) , in both cases the user
* affinity ( if any ) should be destroyed too .
*/
void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
{
struct affinity_context ac = {
.new_mask = new_mask,
.user_mask = NULL,
.flags = SCA_USER, /* clear the user requested mask */
};
union cpumask_rcuhead {
cpumask_t cpumask;
struct rcu_head rcu;
};
__do_set_cpus_allowed(p, &ac);
/*
* Because this is called with p - > pi_lock held , it is not possible
* to use kfree ( ) here ( when PREEMPT_RT = y ) , therefore punt to using
* kfree_rcu ( ) .
*/
kfree_rcu((union cpumask_rcuhead *)ac.user_mask, rcu);
}
int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
int node)
{
cpumask_t *user_mask;
unsigned long flags;
/*
* Always clear dst - > user_cpus_ptr first as their user_cpus_ptr ' s
* may differ by now due to racing .
*/
dst->user_cpus_ptr = NULL;
/*
* This check is racy and losing the race is a valid situation .
* It is not worth the extra overhead of taking the pi_lock on
* every fork / clone .
*/
if (data_race(!src->user_cpus_ptr))
return 0 ;
user_mask = alloc_user_cpus_ptr(node);
if (!user_mask)
return -ENOMEM;
/*
* Use pi_lock to protect content of user_cpus_ptr
*
* Though unlikely , user_cpus_ptr can be reset to NULL by a concurrent
* do_set_cpus_allowed ( ) .
*/
raw_spin_lock_irqsave(&src->pi_lock, flags);
if (src->user_cpus_ptr) {
swap(dst->user_cpus_ptr, user_mask);
cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
}
raw_spin_unlock_irqrestore(&src->pi_lock, flags);
if (unlikely(user_mask))
kfree(user_mask);
return 0 ;
}
static inline struct cpumask *clear_user_cpus_ptr(struct task_struct *p)
{
struct cpumask *user_mask = NULL;
swap(p->user_cpus_ptr, user_mask);
return user_mask;
}
void release_user_cpus_ptr(struct task_struct *p)
{
kfree(clear_user_cpus_ptr(p));
}
/*
* This function is wildly self concurrent ; here be dragons .
*
*
* When given a valid mask , _ _ set_cpus_allowed_ptr ( ) must block until the
* designated task is enqueued on an allowed CPU . If that task is currently
* running , we have to kick it out using the CPU stopper .
*
* Migrate - Disable comes along and tramples all over our nice sandcastle .
* Consider :
*
* Initial conditions : P0 - > cpus_mask = [ 0 , 1 ]
*
* P0 @ CPU0 P1
*
* migrate_disable ( ) ;
* < preempted >
* set_cpus_allowed_ptr ( P0 , [ 1 ] ) ;
*
* P1 * cannot * return from this set_cpus_allowed_ptr ( ) call until P0 executes
* its outermost migrate_enable ( ) ( i . e . it exits its Migrate - Disable region ) .
* This means we need the following scheme :
*
* P0 @ CPU0 P1
*
* migrate_disable ( ) ;
* < preempted >
* set_cpus_allowed_ptr ( P0 , [ 1 ] ) ;
* < blocks >
* < resumes >
* migrate_enable ( ) ;
* _ _ set_cpus_allowed_ptr ( ) ;
* < wakes local stopper >
* ` - - > < woken on migration completion >
*
* Now the fun stuff : there may be several P1 - like tasks , i . e . multiple
* concurrent set_cpus_allowed_ptr ( P0 , [ * ] ) calls . CPU affinity changes of any
* task p are serialized by p - > pi_lock , which we can leverage : the one that
* should come into effect at the end of the Migrate - Disable region is the last
* one . This means we only need to track a single cpumask ( i . e . p - > cpus_mask ) ,
* but we still need to properly signal those waiting tasks at the appropriate
* moment .
*
* This is implemented using struct set_affinity_pending . The first
* _ _ set_cpus_allowed_ptr ( ) caller within a given Migrate - Disable region will
* setup an instance of that struct and install it on the targeted task_struct .
* Any and all further callers will reuse that instance . Those then wait for
* a completion signaled at the tail of the CPU stopper callback ( 1 ) , triggered
* on the end of the Migrate - Disable region ( i . e . outermost migrate_enable ( ) ) .
*
*
* ( 1 ) In the cases covered above . There is one more where the completion is
* signaled within affine_move_task ( ) itself : when a subsequent affinity request
* occurs after the stopper bailed out due to the targeted task still being
* Migrate - Disable . Consider :
*
* Initial conditions : P0 - > cpus_mask = [ 0 , 1 ]
*
* CPU0 P1 P2
* < P0 >
* migrate_disable ( ) ;
* < preempted >
* set_cpus_allowed_ptr ( P0 , [ 1 ] ) ;
* < blocks >
* < migration / 0 >
* migration_cpu_stop ( )
* is_migration_disabled ( )
* < bails >
* set_cpus_allowed_ptr ( P0 , [ 0 , 1 ] ) ;
* < signal completion >
* < awakes >
*
* Note that the above is safe vs a concurrent migrate_enable ( ) , as any
* pending affinity completion is preceded by an uninstallation of
* p - > migration_pending done with p - > pi_lock held .
*/
static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flags *rf,
int dest_cpu, unsigned int flags)
__releases(rq->lock)
__releases(p->pi_lock)
{
struct set_affinity_pending my_pending = { }, *pending = NULL;
bool stop_pending, complete = false ;
/*
* Can the task run on the task ' s current CPU ? If so , we ' re done
*
* We are also done if the task is the current donor , boosting a lock -
* holding proxy , ( and potentially has been migrated outside its
* current or previous affinity mask )
*/
if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask) ||
(task_current_donor(rq, p) && !task_current(rq, p))) {
struct task_struct *push_task = NULL;
if ((flags & SCA_MIGRATE_ENABLE) &&
(p->migration_flags & MDF_PUSH) && !rq->push_busy) {
rq->push_busy = true ;
push_task = get_task_struct(p);
}
/*
* If there are pending waiters , but no pending stop_work ,
* then complete now .
*/
pending = p->migration_pending;
if (pending && !pending->stop_pending) {
p->migration_pending = NULL;
complete = true ;
}
preempt_disable();
task_rq_unlock(rq, p, rf);
if (push_task) {
stop_one_cpu_nowait(rq->cpu, push_cpu_stop,
p, &rq->push_work);
}
preempt_enable();
if (complete)
complete_all(&pending->done);
return 0 ;
}
if (!(flags & SCA_MIGRATE_ENABLE)) {
/* serialized by p->pi_lock */
if (!p->migration_pending) {
/* Install the request */
refcount_set(&my_pending.refs, 1 );
init_completion(&my_pending.done);
my_pending.arg = (struct migration_arg) {
.task = p,
.dest_cpu = dest_cpu,
.pending = &my_pending,
};
p->migration_pending = &my_pending;
} else {
pending = p->migration_pending;
refcount_inc(&pending->refs);
/*
* Affinity has changed , but we ' ve already installed a
* pending . migration_cpu_stop ( ) * must * see this , else
* we risk a completion of the pending despite having a
* task on a disallowed CPU .
*
* Serialized by p - > pi_lock , so this is safe .
*/
pending->arg.dest_cpu = dest_cpu;
}
}
pending = p->migration_pending;
/*
* - ! MIGRATE_ENABLE :
* we ' ll have installed a pending if there wasn ' t one already .
*
* - MIGRATE_ENABLE :
* we ' re here because the current CPU isn ' t matching anymore ,
* the only way that can happen is because of a concurrent
* set_cpus_allowed_ptr ( ) call , which should then still be
* pending completion .
*
* Either way , we really should have a @ pending here .
*/
if (WARN_ON_ONCE(!pending)) {
task_rq_unlock(rq, p, rf);
return -EINVAL;
}
if (task_on_cpu(rq, p) || READ_ONCE(p->__state) == TASK_WAKING) {
/*
* MIGRATE_ENABLE gets here because ' p = = current ' , but for
* anything else we cannot do is_migration_disabled ( ) , punt
* and have the stopper function handle it all race - free .
*/
stop_pending = pending->stop_pending;
if (!stop_pending)
pending->stop_pending = true ;
if (flags & SCA_MIGRATE_ENABLE)
p->migration_flags &= ~MDF_PUSH;
preempt_disable();
task_rq_unlock(rq, p, rf);
if (!stop_pending) {
stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
&pending->arg, &pending->stop_work);
}
preempt_enable();
if (flags & SCA_MIGRATE_ENABLE)
return 0 ;
} else {
if (!is_migration_disabled(p)) {
if (task_on_rq_queued(p))
rq = move_queued_task(rq, rf, p, dest_cpu);
if (!pending->stop_pending) {
p->migration_pending = NULL;
complete = true ;
}
}
task_rq_unlock(rq, p, rf);
if (complete)
complete_all(&pending->done);
}
wait_for_completion(&pending->done);
if (refcount_dec_and_test(&pending->refs))
wake_up_var(&pending->refs); /* No UaF, just an address */
/*
* Block the original owner of & pending until all subsequent callers
* have seen the completion and decremented the refcount
*/
wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
/* ARGH */
WARN_ON_ONCE(my_pending.stop_pending);
return 0 ;
}
/*
* Called with both p - > pi_lock and rq - > lock held ; drops both before returning .
*/
static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
struct affinity_context *ctx,
struct rq *rq,
struct rq_flags *rf)
__releases(rq->lock)
__releases(p->pi_lock)
{
const struct cpumask *cpu_allowed_mask = task_cpu_possible_mask(p);
const struct cpumask *cpu_valid_mask = cpu_active_mask;
bool kthread = p->flags & PF_KTHREAD;
unsigned int dest_cpu;
int ret = 0 ;
update_rq_clock(rq);
if (kthread || is_migration_disabled(p)) {
/*
* Kernel threads are allowed on online & & ! active CPUs ,
* however , during cpu - hot - unplug , even these might get pushed
* away if not KTHREAD_IS_PER_CPU .
*
* Specifically , migration_disabled ( ) tasks must not fail the
* cpumask_any_and_distribute ( ) pick below , esp . so on
* SCA_MIGRATE_ENABLE , otherwise we ' ll not call
* set_cpus_allowed_common ( ) and actually reset p - > cpus_ptr .
*/
cpu_valid_mask = cpu_online_mask;
}
if (!kthread && !cpumask_subset(ctx->new_mask, cpu_allowed_mask)) {
ret = -EINVAL;
goto out;
}
/*
* Must re - check here , to close a race against _ _ kthread_bind ( ) ,
* sched_setaffinity ( ) is not guaranteed to observe the flag .
* /
if ( ( ctx - > flags & SCA_CHECK ) & & ( p - > flags & PF_NO_SETAFFINITY ) ) {
ret = - EINVAL ;
goto out ;
}
if ( ! ( ctx - > flags & SCA_MIGRATE_ENABLE ) ) {
if ( cpumask_equal ( & p - > cpus_mask , ctx - > new_mask ) ) {
if ( ctx - > flags & SCA_USER )
swap ( p - > user_cpus_ptr , ctx - > user_mask ) ;
goto out ;
}
if ( WARN_ON_ONCE ( p = = current & &
is_migration_disabled ( p ) & &
! cpumask_test_cpu ( task_cpu ( p ) , ctx - > new_mask ) ) ) {
ret = - EBUSY ;
goto out ;
}
}
/ *
* Picking a ~ random cpu helps in cases where we are changing affinity
* for groups of tasks ( ie . cpuset ) , so that load balancing is not
* immediately required to distribute the tasks within their new mask .
* /
dest_cpu = cpumask_any_and_distribute ( cpu_valid_mask , ctx - > new_mask ) ;
if ( dest_cpu > = nr_cpu_ids ) {
ret = - EINVAL ;
goto out ;
}
_ _ do_set_cpus_allowed ( p , ctx ) ;
return affine_move_task ( rq , p , rf , dest_cpu , ctx - > flags ) ;
out :
task_rq_unlock ( rq , p , rf ) ;
return ret ;
}
/ *
* Change a given task ' s CPU affinity . Migrate the thread to a
* proper CPU and schedule it away if the CPU it ' s executing on
* is removed from the allowed bitmask .
*
* NOTE : the caller must have a valid reference to the task , the
* task must not exit ( ) & deallocate itself prematurely . The
* call is not atomic ; no spinlocks may be held .
* /
int _ _ set_cpus_allowed_ptr ( struct task_struct * p , struct affinity_context * ctx )
{
struct rq_flags rf ;
struct rq * rq ;
rq = task_rq_lock ( p , & rf ) ;
/ *
* Masking should be skipped if SCA_USER or any of the SCA_MIGRATE_ *
* flags are set .
* /
if ( p - > user_cpus_ptr & &
! ( ctx - > flags & ( SCA_USER | SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE ) ) & &
cpumask_and ( rq - > scratch_mask , ctx - > new_mask , p - > user_cpus_ptr ) )
ctx - > new_mask = rq - > scratch_mask ;
return _ _ set_cpus_allowed_ptr_locked ( p , ctx , rq , & rf ) ;
}
int set_cpus_allowed_ptr ( struct task_struct * p , const struct cpumask * new_mask )
{
struct affinity_context ac = {
. new_mask = new_mask ,
. flags = 0 ,
} ;
return _ _ set_cpus_allowed_ptr ( p , & ac ) ;
}
EXPORT_SYMBOL_GPL ( set_cpus_allowed_ptr ) ;
/ *
* Change a given task ' s CPU affinity to the intersection of its current
* affinity mask and @ subset_mask , writing the resulting mask to @ new_mask .
* If user_cpus_ptr is defined , use it as the basis for restricting CPU
* affinity or use cpu_online_mask instead .
*
* If the resulting mask is empty , leave the affinity unchanged and return
* - EINVAL .
* /
static int restrict_cpus_allowed_ptr ( struct task_struct * p ,
struct cpumask * new_mask ,
const struct cpumask * subset_mask )
{
struct affinity_context ac = {
. new_mask = new_mask ,
. flags = 0 ,
} ;
struct rq_flags rf ;
struct rq * rq ;
int err ;
rq = task_rq_lock ( p , & rf ) ;
/ *
* Forcefully restricting the affinity of a deadline task is
* likely to cause problems , so fail and noisily override the
* mask entirely .
* /
if ( task_has_dl_policy ( p ) & & dl_bandwidth_enabled ( ) ) {
err = - EPERM ;
goto err_unlock ;
}
if ( ! cpumask_and ( new_mask , task_user_cpus ( p ) , subset_mask ) ) {
err = - EINVAL ;
goto err_unlock ;
}
return _ _ set_cpus_allowed_ptr_locked ( p , & ac , rq , & rf ) ;
err_unlock :
task_rq_unlock ( rq , p , & rf ) ;
return err ;
}
/ *
* Restrict the CPU affinity of task @ p so that it is a subset of
* task_cpu_possible_mask ( ) and point @ p - > user_cpus_ptr to a copy of the
* old affinity mask . If the resulting mask is empty , we warn and walk
* up the cpuset hierarchy until we find a suitable mask .
* /
void force_compatible_cpus_allowed_ptr ( struct task_struct * p )
{
cpumask_var_t new_mask ;
const struct cpumask * override_mask = task_cpu_possible_mask ( p ) ;
alloc_cpumask_var ( & new_mask , GFP_KERNEL ) ;
/ *
* _ _ migrate_task ( ) can fail silently in the face of concurrent
* offlining of the chosen destination CPU , so take the hotplug
* lock to ensure that the migration succeeds .
* /
cpus_read_lock ( ) ;
if ( ! cpumask_available ( new_mask ) )
goto out_set_mask ;
if ( ! restrict_cpus_allowed_ptr ( p , new_mask , override_mask ) )
goto out_free_mask ;
/ *
* We failed to find a valid subset of the affinity mask for the
* task , so override it based on its cpuset hierarchy .
* /
cpuset_cpus_allowed ( p , new_mask ) ;
override_mask = new_mask ;
out_set_mask :
if ( printk_ratelimit ( ) ) {
printk_deferred ( " Overriding affinity for process % d ( % s ) to CPUs % * pbl \ n " ,
task_pid_nr ( p ) , p - > comm ,
cpumask_pr_args ( override_mask ) ) ;
}
WARN_ON ( set_cpus_allowed_ptr ( p , override_mask ) ) ;
out_free_mask :
cpus_read_unlock ( ) ;
free_cpumask_var ( new_mask ) ;
}
/ *
* Restore the affinity of a task @ p which was previously restricted by a
* call to force_compatible_cpus_allowed_ptr ( ) .
*
* It is the caller ' s responsibility to serialise this with any calls to
* force_compatible_cpus_allowed_ptr ( @ p ) .
* /
void relax_compatible_cpus_allowed_ptr ( struct task_struct * p )
{
struct affinity_context ac = {
. new_mask = task_user_cpus ( p ) ,
. flags = 0 ,
} ;
int ret ;
/ *
* Try to restore the old affinity mask with _ _ sched_setaffinity ( ) .
* Cpuset masking will be done there too .
* /
ret = _ _ sched_setaffinity ( p , & ac ) ;
WARN_ON_ONCE ( ret ) ;
}
# ifdef CONFIG_SMP
void set_task_cpu ( struct task_struct * p , unsigned int new_cpu )
{
unsigned int state = READ_ONCE ( p - > _ _ state ) ;
/ *
* We should never call set_task_cpu ( ) on a blocked task ,
* ttwu ( ) will sort out the placement .
* /
WARN_ON_ONCE ( state ! = TASK_RUNNING & & state ! = TASK_WAKING & & ! p - > on_rq ) ;
/ *
* Migrating fair class task must have p - > on_rq = TASK_ON_RQ_MIGRATING ,
* because schedstat_wait_ { start , end } rebase migrating task ' s wait_start
* time relying on p - > on_rq .
* /
WARN_ON_ONCE ( state = = TASK_RUNNING & &
p - > sched_class = = & fair_sched_class & &
( p - > on_rq & & ! task_on_rq_migrating ( p ) ) ) ;
# ifdef CONFIG_LOCKDEP
/ *
* The caller should hold either p - > pi_lock or rq - > lock , when changing
* a task ' s CPU . - > pi_lock for waking tasks , rq - > lock for runnable tasks .
*
* sched_move_task ( ) holds both and thus holding either pins the cgroup ,
* see task_group ( ) .
*
* Furthermore , all task_rq users should acquire both locks , see
* task_rq_lock ( ) .
* /
WARN_ON_ONCE ( debug_locks & & ! ( lockdep_is_held ( & p - > pi_lock ) | |
lockdep_is_held ( _ _ rq_lockp ( task_rq ( p ) ) ) ) ) ;
# endif
/ *
* Clearly , migrating tasks to offline CPUs is a fairly daft thing .
* /
WARN_ON_ONCE ( ! cpu_online ( new_cpu ) ) ;
WARN_ON_ONCE ( is_migration_disabled ( p ) ) ;
trace_sched_migrate_task ( p , new_cpu ) ;
if ( task_cpu ( p ) ! = new_cpu ) {
if ( p - > sched_class - > migrate_task_rq )
p - > sched_class - > migrate_task_rq ( p , new_cpu ) ;
p - > se . nr_migrations + + ;
rseq_migrate ( p ) ;
sched_mm_cid_migrate_from ( p ) ;
perf_event_task_migrate ( p ) ;
}
_ _ set_task_cpu ( p , new_cpu ) ;
}
# endif / * CONFIG_SMP * /
# ifdef CONFIG_NUMA_BALANCING
static void _ _ migrate_swap_task ( struct task_struct * p , int cpu )
{
if ( task_on_rq_queued ( p ) ) {
struct rq * src_rq , * dst_rq ;
struct rq_flags srf , drf ;
src_rq = task_rq ( p ) ;
dst_rq = cpu_rq ( cpu ) ;
rq_pin_lock ( src_rq , & srf ) ;
rq_pin_lock ( dst_rq , & drf ) ;
move_queued_task_locked ( src_rq , dst_rq , p ) ;
wakeup_preempt ( dst_rq , p , 0 ) ;
rq_unpin_lock ( dst_rq , & drf ) ;
rq_unpin_lock ( src_rq , & srf ) ;
} else {
/ *
* Task isn ' t running anymore ; make it appear like we migrated
* it before it went to sleep . This means on wakeup we make the
* previous CPU our target instead of where it really is .
* /
p - > wake_cpu = cpu ;
}
}
struct migration_swap_arg {
struct task_struct * src_task , * dst_task ;
int src_cpu , dst_cpu ;
} ;
static int migrate_swap_stop ( void * data )
{
struct migration_swap_arg * arg = data ;
struct rq * src_rq , * dst_rq ;
if ( ! cpu_active ( arg - > src_cpu ) | | ! cpu_active ( arg - > dst_cpu ) )
return - EAGAIN ;
src_rq = cpu_rq ( arg - > src_cpu ) ;
dst_rq = cpu_rq ( arg - > dst_cpu ) ;
guard ( double_raw_spinlock ) ( & arg - > src_task - > pi_lock , & arg - > dst_task - > pi_lock ) ;
guard ( double_rq_lock ) ( src_rq , dst_rq ) ;
if ( task_cpu ( arg - > dst_task ) ! = arg - > dst_cpu )
return - EAGAIN ;
if ( task_cpu ( arg - > src_task ) ! = arg - > src_cpu )
return - EAGAIN ;
if ( ! cpumask_test_cpu ( arg - > dst_cpu , arg - > src_task - > cpus_ptr ) )
return - EAGAIN ;
if ( ! cpumask_test_cpu ( arg - > src_cpu , arg - > dst_task - > cpus_ptr ) )
return - EAGAIN ;
_ _ migrate_swap_task ( arg - > src_task , arg - > dst_cpu ) ;
_ _ migrate_swap_task ( arg - > dst_task , arg - > src_cpu ) ;
return 0 ;
}
/ *
* Cross migrate two tasks
* /
int migrate_swap ( struct task_struct * cur , struct task_struct * p ,
int target_cpu , int curr_cpu )
{
struct migration_swap_arg arg ;
int ret = - EINVAL ;
arg = ( struct migration_swap_arg ) {
. src_task = cur ,
. src_cpu = curr_cpu ,
. dst_task = p ,
. dst_cpu = target_cpu ,
} ;
if ( arg . src_cpu = = arg . dst_cpu )
goto out ;
/ *
* These three tests are all lockless ; this is OK since all of them
* will be re - checked with proper locks held further down the line .
* /
if ( ! cpu_active ( arg . src_cpu ) | | ! cpu_active ( arg . dst_cpu ) )
goto out ;
if ( ! cpumask_test_cpu ( arg . dst_cpu , arg . src_task - > cpus_ptr ) )
goto out ;
if ( ! cpumask_test_cpu ( arg . src_cpu , arg . dst_task - > cpus_ptr ) )
goto out ;
trace_sched_swap_numa ( cur , arg . src_cpu , p , arg . dst_cpu ) ;
ret = stop_two_cpus ( arg . dst_cpu , arg . src_cpu , migrate_swap_stop , & arg ) ;
out :
return ret ;
}
# endif / * CONFIG_NUMA_BALANCING * /
/ * * *
* kick_process - kick a running thread to enter / exit the kernel
* @ p : the to - be - kicked thread
*
* Cause a process which is running on another CPU to enter
* kernel - mode , without any delay . ( to get signals handled . )
*
* NOTE : this function doesn ' t have to take the runqueue lock ,
* because all it wants to ensure is that the remote task enters
* the kernel . If the IPI races and the task has been migrated
* to another CPU then no harm is done and the purpose has been
* achieved as well .
* /
void kick_process ( struct task_struct * p )
{
guard ( preempt ) ( ) ;
int cpu = task_cpu ( p ) ;
if ( ( cpu ! = smp_processor_id ( ) ) & & task_curr ( p ) )
smp_send_reschedule ( cpu ) ;
}
EXPORT_SYMBOL_GPL ( kick_process ) ;
/ *
* - > cpus_ptr is protected by both rq - > lock and p - > pi_lock
*
* A few notes on cpu_active vs cpu_online :
*
* - cpu_active must be a subset of cpu_online
*
* - on CPU - up we allow per - CPU kthreads on the online & & ! active CPU ,
* see _ _ set_cpus_allowed_ptr ( ) . At this point the newly online
* CPU isn ' t yet part of the sched domains , and balancing will not
* see it .
*
* - on CPU - down we clear cpu_active ( ) to mask the sched domains and
* avoid the load balancer to place new tasks on the to be removed
* CPU . Existing tasks will remain running there and will be taken
* off .
*
* This means that fallback selection must not select ! active CPUs .
* And can assume that any active CPU must be online . Conversely
* select_task_rq ( ) below may allow selection of ! active CPUs in order
* to satisfy the above rules .
* /
static int select_fallback_rq ( int cpu , struct task_struct * p )
{
int nid = cpu_to_node ( cpu ) ;
const struct cpumask * nodemask = NULL ;
enum { cpuset , possible , fail } state = cpuset ;
int dest_cpu ;
/ *
* If the node that the CPU is on has been offlined , cpu_to_node ( )
* will return - 1 . There is no CPU on the node , and we should
* select the CPU on the other node .
* /
if ( nid ! = - 1 ) {
nodemask = cpumask_of_node ( nid ) ;
/ * Look for allowed , online CPU in same node . * /
for_each_cpu ( dest_cpu , nodemask ) {
if ( is_cpu_allowed ( p , dest_cpu ) )
return dest_cpu ;
}
}
for ( ; ; ) {
/ * Any allowed , online CPU ? * /
for_each_cpu ( dest_cpu , p - > cpus_ptr ) {
if ( ! is_cpu_allowed ( p , dest_cpu ) )
continue ;
goto out ;
}
/ * No more Mr . Nice Guy . * /
switch ( state ) {
case cpuset :
if ( cpuset_cpus_allowed_fallback ( p ) ) {
state = possible ;
break ;
}
fallthrough ;
case possible :
/ *
* XXX When called from select_task_rq ( ) we only
* hold p - > pi_lock and again violate locking order .
*
* More yuck to audit .
* /
do_set_cpus_allowed ( p , task_cpu_fallback_mask ( p ) ) ;
state = fail ;
break ;
case fail :
BUG ( ) ;
break ;
}
}
out :
if ( state ! = cpuset ) {
/ *
* Don ' t tell them about moving exiting tasks or
* kernel threads ( both mm NULL ) , since they never
* leave kernel .
* /
if ( p - > mm & & printk_ratelimit ( ) ) {
printk_deferred ( " process % d ( % s ) no longer affine to cpu % d \ n " ,
task_pid_nr ( p ) , p - > comm , cpu ) ;
}
}
return dest_cpu ;
}
/ *
* The caller ( fork , wakeup ) owns p - > pi_lock , - > cpus_ptr is stable .
* /
static inline
int select_task_rq ( struct task_struct * p , int cpu , int * wake_flags )
{
lockdep_assert_held ( & p - > pi_lock ) ;
if ( p - > nr_cpus_allowed > 1 & & ! is_migration_disabled ( p ) ) {
cpu = p - > sched_class - > select_task_rq ( p , cpu , * wake_flags ) ;
* wake_flags | = WF_RQ_SELECTED ;
} else {
cpu = cpumask_any ( p - > cpus_ptr ) ;
}
/ *
* In order not to call set_task_cpu ( ) on a blocking task we need
* to rely on ttwu ( ) to place the task on a valid - > cpus_ptr
* CPU .
*
* Since this is common to all placement strategies , this lives here .
*
* [ this allows - > select_task ( ) to simply return task_cpu ( p ) and
* not worry about this generic constraint ]
* /
if ( unlikely ( ! is_cpu_allowed ( p , cpu ) ) )
cpu = select_fallback_rq ( task_cpu ( p ) , p ) ;
return cpu ;
}
void sched_set_stop_task ( int cpu , struct task_struct * stop )
{
static struct lock_class_key stop_pi_lock ;
struct sched_param param = { . sched_priority = MAX_RT_PRIO - 1 } ;
struct task_struct * old_stop = cpu_rq ( cpu ) - > stop ;
if ( stop ) {
/ *
* Make it appear like a SCHED_FIFO task , its something
* userspace knows about and won ' t get confused about .
*
* Also , it will make PI more or less work without too
* much confusion - - but then , stop work should not
* rely on PI working anyway .
* /
sched_setscheduler_nocheck ( stop , SCHED_FIFO , & param ) ;
stop - > sched_class = & stop_sched_class ;
/ *
* The PI code calls rt_mutex_setprio ( ) with - > pi_lock held to
* adjust the effective priority of a task . As a result ,
* rt_mutex_setprio ( ) can trigger ( RT ) balancing operations ,
* which can then trigger wakeups of the stop thread to push
* around the current task .
*
* The stop task itself will never be part of the PI - chain , it
* never blocks , therefore that - > pi_lock recursion is safe .
* Tell lockdep about this by placing the stop - > pi_lock in its
* own class .
* /
lockdep_set_class ( & stop - > pi_lock , & stop_pi_lock ) ;
}
cpu_rq ( cpu ) - > stop = stop ;
if ( old_stop ) {
/ *
* Reset it back to a normal scheduling class so that
* it can die in pieces .
* /
old_stop - > sched_class = & rt_sched_class ;
}
}
static void
ttwu_stat ( struct task_struct * p , int cpu , int wake_flags )
{
struct rq * rq ;
if ( ! schedstat_enabled ( ) )
return ;
rq = this_rq ( ) ;
if ( cpu = = rq - > cpu ) {
_ _ schedstat_inc ( rq - > ttwu_local ) ;
_ _ schedstat_inc ( p - > stats . nr_wakeups_local ) ;
} else {
struct sched_domain * sd ;
_ _ schedstat_inc ( p - > stats . nr_wakeups_remote ) ;
guard ( rcu ) ( ) ;
for_each_domain ( rq - > cpu , sd ) {
if ( cpumask_test_cpu ( cpu , sched_domain_span ( sd ) ) ) {
_ _ schedstat_inc ( sd - > ttwu_wake_remote ) ;
break ;
}
}
}
if ( wake_flags & WF_MIGRATED )
_ _ schedstat_inc ( p - > stats . nr_wakeups_migrate ) ;
_ _ schedstat_inc ( rq - > ttwu_count ) ;
_ _ schedstat_inc ( p - > stats . nr_wakeups ) ;
if ( wake_flags & WF_SYNC )
_ _ schedstat_inc ( p - > stats . nr_wakeups_sync ) ;
}
/ *
* Mark the task runnable .
* /
static inline void ttwu_do_wakeup ( struct task_struct * p )
{
WRITE_ONCE ( p - > _ _ state , TASK_RUNNING ) ;
trace_sched_wakeup ( p ) ;
}
static void
ttwu_do_activate ( struct rq * rq , struct task_struct * p , int wake_flags ,
struct rq_flags * rf )
{
int en_flags = ENQUEUE_WAKEUP | ENQUEUE_NOCLOCK ;
lockdep_assert_rq_held ( rq ) ;
if ( p - > sched_contributes_to_load )
rq - > nr_uninterruptible - - ;
if ( wake_flags & WF_RQ_SELECTED )
en_flags | = ENQUEUE_RQ_SELECTED ;
if ( wake_flags & WF_MIGRATED )
en_flags | = ENQUEUE_MIGRATED ;
else
if ( p - > in_iowait ) {
delayacct_blkio_end ( p ) ;
atomic_dec ( & task_rq ( p ) - > nr_iowait ) ;
}
activate_task ( rq , p , en_flags ) ;
wakeup_preempt ( rq , p , wake_flags ) ;
ttwu_do_wakeup ( p ) ;
if ( p - > sched_class - > task_woken ) {
/ *
* Our task @ p is fully woken up and running ; so it ' s safe to
* drop the rq - > lock , hereafter rq is only used for statistics .
* /
rq_unpin_lock ( rq , rf ) ;
p - > sched_class - > task_woken ( rq , p ) ;
rq_repin_lock ( rq , rf ) ;
}
if ( rq - > idle_stamp ) {
u64 delta = rq_clock ( rq ) - rq - > idle_stamp ;
u64 max = 2 * rq - > max_idle_balance_cost ;
update_avg ( & rq - > avg_idle , delta ) ;
if ( rq - > avg_idle > max )
rq - > avg_idle = max ;
rq - > idle_stamp = 0 ;
}
}
/ *
* Consider @ p being inside a wait loop :
*
* for ( ; ; ) {
* set_current_state ( TASK_UNINTERRUPTIBLE ) ;
*
* if ( CONDITION )
* break ;
*
* schedule ( ) ;
* }
* _ _ set_current_state ( TASK_RUNNING ) ;
*
* between set_current_state ( ) and schedule ( ) . In this case @ p is still
* runnable , so all that needs doing is change p - > state back to TASK_RUNNING in
* an atomic manner .
*
* By taking task_rq ( p ) - > lock we serialize against schedule ( ) , if @ p - > on_rq
* then schedule ( ) must still happen and p - > state can be changed to
* TASK_RUNNING . Otherwise we lost the race , schedule ( ) has happened , and we
* need to do a full wakeup with enqueue .
*
* Returns : % true when the wakeup is done ,
* % false otherwise .
* /
static int ttwu_runnable ( struct task_struct * p , int wake_flags )
{
struct rq_flags rf ;
struct rq * rq ;
int ret = 0 ;
rq = _ _ task_rq_lock ( p , & rf ) ;
if ( task_on_rq_queued ( p ) ) {
update_rq_clock ( rq ) ;
if ( p - > se . sched_delayed )
enqueue_task ( rq , p , ENQUEUE_NOCLOCK | ENQUEUE_DELAYED ) ;
if ( ! task_on_cpu ( rq , p ) ) {
/ *
* When on_rq & & ! on_cpu the task is preempted , see if
* it should preempt the task that is current now .
* /
wakeup_preempt ( rq , p , wake_flags ) ;
}
ttwu_do_wakeup ( p ) ;
ret = 1 ;
}
_ _ task_rq_unlock ( rq , & rf ) ;
return ret ;
}
void sched_ttwu_pending ( void * arg )
{
struct llist_node * llist = arg ;
struct rq * rq = this_rq ( ) ;
struct task_struct * p , * t ;
struct rq_flags rf ;
if ( ! llist )
return ;
rq_lock_irqsave ( rq , & rf ) ;
update_rq_clock ( rq ) ;
llist_for_each_entry_safe ( p , t , llist , wake_entry . llist ) {
if ( WARN_ON_ONCE ( p - > on_cpu ) )
smp_cond_load_acquire ( & p - > on_cpu , ! VAL ) ;
if ( WARN_ON_ONCE ( task_cpu ( p ) ! = cpu_of ( rq ) ) )
set_task_cpu ( p , cpu_of ( rq ) ) ;
ttwu_do_activate ( rq , p , p - > sched_remote_wakeup ? WF_MIGRATED : 0 , & rf ) ;
}
/ *
* Must be after enqueueing at least once task such that
* idle_cpu ( ) does not observe a false - negative - - if it does ,
* it is possible for select_idle_siblings ( ) to stack a number
* of tasks on this CPU during that window .
*
* It is OK to clear ttwu_pending when another task pending .
* We will receive IPI after local IRQ enabled and then enqueue it .
* Since now nr_running > 0 , idle_cpu ( ) will always get correct result .
* /
WRITE_ONCE ( rq - > ttwu_pending , 0 ) ;
rq_unlock_irqrestore ( rq , & rf ) ;
}
/ *
* Prepare the scene for sending an IPI for a remote smp_call
*
* Returns true if the caller can proceed with sending the IPI .
* Returns false otherwise .
* /
bool call_function_single_prep_ipi ( int cpu )
{
if ( set_nr_if_polling ( cpu_rq ( cpu ) - > idle ) ) {
trace_sched_wake_idle_without_ipi ( cpu ) ;
return false ;
}
return true ;
}
/ *
* Queue a task on the target CPUs wake_list and wake the CPU via IPI if
* necessary . The wakee CPU on receipt of the IPI will queue the task
* via sched_ttwu_wakeup ( ) for activation so the wakee incurs the cost
* of the wakeup instead of the waker .
* /
static void _ _ ttwu_queue_wakelist ( struct task_struct * p , int cpu , int wake_flags )
{
struct rq * rq = cpu_rq ( cpu ) ;
p - > sched_remote_wakeup = ! ! ( wake_flags & WF_MIGRATED ) ;
WRITE_ONCE ( rq - > ttwu_pending , 1 ) ;
# ifdef CONFIG_SMP
_ _ smp_call_single_queue ( cpu , & p - > wake_entry . llist ) ;
# endif
}
void wake_up_if_idle ( int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
guard ( rcu ) ( ) ;
if ( is_idle_task ( rcu_dereference ( rq - > curr ) ) ) {
guard ( rq_lock_irqsave ) ( rq ) ;
if ( is_idle_task ( rq - > curr ) )
resched_curr ( rq ) ;
}
}
bool cpus_equal_capacity ( int this_cpu , int that_cpu )
{
if ( ! sched_asym_cpucap_active ( ) )
return true ;
if ( this_cpu = = that_cpu )
return true ;
return arch_scale_cpu_capacity ( this_cpu ) = = arch_scale_cpu_capacity ( that_cpu ) ;
}
bool cpus_share_cache ( int this_cpu , int that_cpu )
{
if ( this_cpu = = that_cpu )
return true ;
return per_cpu ( sd_llc_id , this_cpu ) = = per_cpu ( sd_llc_id , that_cpu ) ;
}
/ *
* Whether CPUs are share cache resources , which means LLC on non - cluster
* machines and LLC tag or L2 on machines with clusters .
* /
bool cpus_share_resources ( int this_cpu , int that_cpu )
{
if ( this_cpu = = that_cpu )
return true ;
return per_cpu ( sd_share_id , this_cpu ) = = per_cpu ( sd_share_id , that_cpu ) ;
}
static inline bool ttwu_queue_cond ( struct task_struct * p , int cpu )
{
/ * See SCX_OPS_ALLOW_QUEUED_WAKEUP . * /
if ( ! scx_allow_ttwu_queue ( p ) )
return false ;
# ifdef CONFIG_SMP
if ( p - > sched_class = = & stop_sched_class )
return false ;
# endif
/ *
* Do not complicate things with the async wake_list while the CPU is
* in hotplug state .
* /
if ( ! cpu_active ( cpu ) )
return false ;
/ * Ensure the task will still be allowed to run on the CPU . * /
if ( ! cpumask_test_cpu ( cpu , p - > cpus_ptr ) )
return false ;
/ *
* If the CPU does not share cache , then queue the task on the
* remote rqs wakelist to avoid accessing remote data .
* /
if ( ! cpus_share_cache ( smp_processor_id ( ) , cpu ) )
return true ;
if ( cpu = = smp_processor_id ( ) )
return false ;
/ *
* If the wakee cpu is idle , or the task is descheduling and the
* only running task on the CPU , then use the wakelist to offload
* the task activation to the idle ( or soon - to - be - idle ) CPU as
* the current CPU is likely busy . nr_running is checked to
* avoid unnecessary task stacking .
*
* Note that we can only get here with ( wakee ) p - > on_rq = 0 ,
* p - > on_cpu can be whatever , we ' ve done the dequeue , so
* the wakee has been accounted out of - > nr_running .
* /
if ( ! cpu_rq ( cpu ) - > nr_running )
return true ;
return false ;
}
static bool ttwu_queue_wakelist ( struct task_struct * p , int cpu , int wake_flags )
{
if ( sched_feat ( TTWU_QUEUE ) & & ttwu_queue_cond ( p , cpu ) ) {
sched_clock_cpu ( cpu ) ; / * Sync clocks across CPUs * /
_ _ ttwu_queue_wakelist ( p , cpu , wake_flags ) ;
return true ;
}
return false ;
}
static void ttwu_queue ( struct task_struct * p , int cpu , int wake_flags )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct rq_flags rf ;
if ( ttwu_queue_wakelist ( p , cpu , wake_flags ) )
return ;
rq_lock ( rq , & rf ) ;
update_rq_clock ( rq ) ;
ttwu_do_activate ( rq , p , wake_flags , & rf ) ;
rq_unlock ( rq , & rf ) ;
}
/ *
* Invoked from try_to_wake_up ( ) to check whether the task can be woken up .
*
* The caller holds p : : pi_lock if p ! = current or has preemption
* disabled when p = = current .
*
* The rules of saved_state :
*
* The related locking code always holds p : : pi_lock when updating
* p : : saved_state , which means the code is fully serialized in both cases .
*
* For PREEMPT_RT , the lock wait and lock wakeups happen via TASK_RTLOCK_WAIT .
* No other bits set . This allows to distinguish all wakeup scenarios .
*
* For FREEZER , the wakeup happens via TASK_FROZEN . No other bits set . This
* allows us to prevent early wakeup of tasks before they can be run on
* asymmetric ISA architectures ( eg ARMv9 ) .
* /
static _ _ always_inline
bool ttwu_state_match ( struct task_struct * p , unsigned int state , int * success )
{
int match ;
if ( IS_ENABLED ( CONFIG_DEBUG_PREEMPT ) ) {
WARN_ON_ONCE ( ( state & TASK_RTLOCK_WAIT ) & &
state ! = TASK_RTLOCK_WAIT ) ;
}
* success = ! ! ( match = _ _ task_state_match ( p , state ) ) ;
/ *
* Saved state preserves the task state across blocking on
* an RT lock or TASK_FREEZABLE tasks . If the state matches ,
* set p : : saved_state to TASK_RUNNING , but do not wake the task
* because it waits for a lock wakeup or _ _ thaw_task ( ) . Also
* indicate success because from the regular waker ' s point of
* view this has succeeded .
*
* After acquiring the lock the task will restore p : : _ _ state
* from p : : saved_state which ensures that the regular
* wakeup is not lost . The restore will also set
* p : : saved_state to TASK_RUNNING so any further tests will
* not result in false positives vs . @ success
* /
if ( match < 0 )
p - > saved_state = TASK_RUNNING ;
return match > 0 ;
}
/ *
* Notes on Program - Order guarantees on SMP systems .
*
* MIGRATION
*
* The basic program - order guarantee on SMP systems is that when a task [ t ]
* migrates , all its activity on its old CPU [ c0 ] happens - before any subsequent
* execution on its new CPU [ c1 ] .
*
* For migration ( of runnable tasks ) this is provided by the following means :
*
* A ) UNLOCK of the rq ( c0 ) - > lock scheduling out task t
* B ) migration for t is required to synchronize * both * rq ( c0 ) - > lock and
* rq ( c1 ) - > lock ( if not at the same time , then in that order ) .
* C ) LOCK of the rq ( c1 ) - > lock scheduling in task
*
* Release / acquire chaining guarantees that B happens after A and C after B .
* Note : the CPU doing B need not be c0 or c1
*
* Example :
*
* CPU0 CPU1 CPU2
*
* LOCK rq ( 0 ) - > lock
* sched - out X
* sched - in Y
* UNLOCK rq ( 0 ) - > lock
*
* LOCK rq ( 0 ) - > lock / / orders against CPU0
* dequeue X
* UNLOCK rq ( 0 ) - > lock
*
* LOCK rq ( 1 ) - > lock
* enqueue X
* UNLOCK rq ( 1 ) - > lock
*
* LOCK rq ( 1 ) - > lock / / orders against CPU2
* sched - out Z
* sched - in X
* UNLOCK rq ( 1 ) - > lock
*
*
* BLOCKING - - aka . SLEEP + WAKEUP
*
* For blocking we ( obviously ) need to provide the same guarantee as for
* migration . However the means are completely different as there is no lock
* chain to provide order . Instead we do :
*
* 1 ) smp_store_release ( X - > on_cpu , 0 ) - - finish_task ( )
* 2 ) smp_cond_load_acquire ( ! X - > on_cpu ) - - try_to_wake_up ( )
*
* Example :
*
* CPU0 ( schedule ) CPU1 ( try_to_wake_up ) CPU2 ( schedule )
*
* LOCK rq ( 0 ) - > lock LOCK X - > pi_lock
* dequeue X
* sched - out X
* smp_store_release ( X - > on_cpu , 0 ) ;
*
* smp_cond_load_acquire ( & X - > on_cpu , ! VAL ) ;
* X - > state = WAKING
* set_task_cpu ( X , 2 )
*
* LOCK rq ( 2 ) - > lock
* enqueue X
* X - > state = RUNNING
* UNLOCK rq ( 2 ) - > lock
*
* LOCK rq ( 2 ) - > lock / / orders against CPU1
* sched - out Z
* sched - in X
* UNLOCK rq ( 2 ) - > lock
*
* UNLOCK X - > pi_lock
* UNLOCK rq ( 0 ) - > lock
*
*
* However , for wakeups there is a second guarantee we must provide , namely we
* must ensure that CONDITION = 1 done by the caller can not be reordered with
* accesses to the task state ; see try_to_wake_up ( ) and set_current_state ( ) .
* /
/ * *
* try_to_wake_up - wake up a thread
* @ p : the thread to be awakened
* @ state : the mask of task states that can be woken
* @ wake_flags : wake modifier flags ( WF_ * )
*
* Conceptually does :
*
* If ( @ state & @ p - > state ) @ p - > state = TASK_RUNNING .
*
* If the task was not queued / runnable , also place it back on a runqueue .
*
* This function is atomic against schedule ( ) which would dequeue the task .
*
* It issues a full memory barrier before accessing @ p - > state , see the comment
* with set_current_state ( ) .
*
* Uses p - > pi_lock to serialize against concurrent wake - ups .
*
* Relies on p - > pi_lock stabilizing :
* - p - > sched_class
* - p - > cpus_ptr
* - p - > sched_task_group
* in order to do migration , see its use of select_task_rq ( ) / set_task_cpu ( ) .
*
* Tries really hard to only take one task_rq ( p ) - > lock for performance .
* Takes rq - > lock in :
* - ttwu_runnable ( ) - - old rq , unavoidable , see comment there ;
* - ttwu_queue ( ) - - new rq , for enqueue of the task ;
* - psi_ttwu_dequeue ( ) - - much sadness : - ( accounting will kill us .
*
* As a consequence we race really badly with just about everything . See the
* many memory barriers and their comments for details .
*
* Return : % true if @ p - > state changes ( an actual wakeup was done ) ,
* % false otherwise .
* /
int try_to_wake_up ( struct task_struct * p , unsigned int state , int wake_flags )
{
guard ( preempt ) ( ) ;
int cpu , success = 0 ;
wake_flags | = WF_TTWU ;
if ( p = = current ) {
/ *
* We ' re waking current , this means ' p - > on_rq ' and ' task_cpu ( p )
* = = smp_processor_id ( ) ' . Together this means we can special
* case the whole ' p - > on_rq & & ttwu_runnable ( ) ' case below
* without taking any locks .
*
* Specifically , given current runs ttwu ( ) we must be before
* schedule ( ) ' s block_task ( ) , as such this must not observe
* sched_delayed .
*
* In particular :
* - we rely on Program - Order guarantees for all the ordering ,
* - we ' re serialized against set_special_state ( ) by virtue of
* it disabling IRQs ( this allows not taking - > pi_lock ) .
* /
WARN_ON_ONCE ( p - > se . sched_delayed ) ;
if ( ! ttwu_state_match ( p , state , & success ) )
goto out ;
trace_sched_waking ( p ) ;
ttwu_do_wakeup ( p ) ;
goto out ;
}
/ *
* If we are going to wake up a thread waiting for CONDITION we
* need to ensure that CONDITION = 1 done by the caller can not be
* reordered with p - > state check below . This pairs with smp_store_mb ( )
* in set_current_state ( ) that the waiting thread does .
* /
scoped_guard ( raw_spinlock_irqsave , & p - > pi_lock ) {
smp_mb__after_spinlock ( ) ;
if ( ! ttwu_state_match ( p , state , & success ) )
break ;
trace_sched_waking ( p ) ;
/ *
* Ensure we load p - > on_rq _ after_ p - > state , otherwise it would
* be possible to , falsely , observe p - > on_rq = = 0 and get stuck
* in smp_cond_load_acquire ( ) below .
*
* sched_ttwu_pending ( ) try_to_wake_up ( )
* STORE p - > on_rq = 1 LOAD p - > state
* UNLOCK rq - > lock
*
* _ _ schedule ( ) ( switch to task ' p ' )
* LOCK rq - > lock smp_rmb ( ) ;
* smp_mb__after_spinlock ( ) ;
* UNLOCK rq - > lock
*
* [ task p ]
* STORE p - > state = UNINTERRUPTIBLE LOAD p - > on_rq
*
* Pairs with the LOCK + smp_mb__after_spinlock ( ) on rq - > lock in
* _ _ schedule ( ) . See the comment for smp_mb__after_spinlock ( ) .
*
* A similar smp_rmb ( ) lives in _ _ task_needs_rq_lock ( ) .
* /
smp_rmb ( ) ;
if ( READ_ONCE ( p - > on_rq ) & & ttwu_runnable ( p , wake_flags ) )
break ;
/ *
* Ensure we load p - > on_cpu _ after_ p - > on_rq , otherwise it would be
* possible to , falsely , observe p - > on_cpu = = 0 .
*
* One must be running ( - > on_cpu = = 1 ) in order to remove oneself
* from the runqueue .
*
* _ _ schedule ( ) ( switch to task ' p ' ) try_to_wake_up ( )
* STORE p - > on_cpu = 1 LOAD p - > on_rq
* UNLOCK rq - > lock
*
* _ _ schedule ( ) ( put ' p ' to sleep )
* LOCK rq - > lock smp_rmb ( ) ;
* smp_mb__after_spinlock ( ) ;
* STORE p - > on_rq = 0 LOAD p - > on_cpu
*
* Pairs with the LOCK + smp_mb__after_spinlock ( ) on rq - > lock in
* _ _ schedule ( ) . See the comment for smp_mb__after_spinlock ( ) .
*
* Form a control - dep - acquire with p - > on_rq = = 0 above , to ensure
* schedule ( ) ' s deactivate_task ( ) has ' happened ' and p will no longer
* care about it ' s own p - > state . See the comment in _ _ schedule ( ) .
* /
smp_acquire__after_ctrl_dep ( ) ;
/ *
* We ' re doing the wakeup ( @ success = = 1 ) , they did a dequeue ( p - > on_rq
* = = 0 ) , which means we need to do an enqueue , change p - > state to
* TASK_WAKING such that we can unlock p - > pi_lock before doing the
* enqueue , such as ttwu_queue_wakelist ( ) .
* /
WRITE_ONCE ( p - > _ _ state , TASK_WAKING ) ;
/ *
* If the owning ( remote ) CPU is still in the middle of schedule ( ) with
* this task as prev , considering queueing p on the remote CPUs wake_list
* which potentially sends an IPI instead of spinning on p - > on_cpu to
* let the waker make forward progress . This is safe because IRQs are
* disabled and the IPI will deliver after on_cpu is cleared .
*
* Ensure we load task_cpu ( p ) after p - > on_cpu :
*
* set_task_cpu ( p , cpu ) ;
* STORE p - > cpu = @ cpu
* _ _ schedule ( ) ( switch to task ' p ' )
* LOCK rq - > lock
* smp_mb__after_spin_lock ( ) smp_cond_load_acquire ( & p - > on_cpu )
* STORE p - > on_cpu = 1 LOAD p - > cpu
*
* to ensure we observe the correct CPU on which the task is currently
* scheduling .
* /
if ( smp_load_acquire ( & p - > on_cpu ) & &
ttwu_queue_wakelist ( p , task_cpu ( p ) , wake_flags ) )
break ;
/ *
* If the owning ( remote ) CPU is still in the middle of schedule ( ) with
* this task as prev , wait until it ' s done referencing the task .
*
* Pairs with the smp_store_release ( ) in finish_task ( ) .
*
* This ensures that tasks getting woken will be fully ordered against
* their previous state and preserve Program Order .
* /
smp_cond_load_acquire ( & p - > on_cpu , ! VAL ) ;
cpu = select_task_rq ( p , p - > wake_cpu , & wake_flags ) ;
if ( task_cpu ( p ) ! = cpu ) {
if ( p - > in_iowait ) {
delayacct_blkio_end ( p ) ;
atomic_dec ( & task_rq ( p ) - > nr_iowait ) ;
}
wake_flags | = WF_MIGRATED ;
psi_ttwu_dequeue ( p ) ;
set_task_cpu ( p , cpu ) ;
}
ttwu_queue ( p , cpu , wake_flags ) ;
}
out :
if ( success )
ttwu_stat ( p , task_cpu ( p ) , wake_flags ) ;
return success ;
}
static bool _ _ task_needs_rq_lock ( struct task_struct * p )
{
unsigned int state = READ_ONCE ( p - > _ _ state ) ;
/ *
* Since pi - > lock blocks try_to_wake_up ( ) , we don ' t need rq - > lock when
* the task is blocked . Make sure to check @ state since ttwu ( ) can drop
* locks at the end , see ttwu_queue_wakelist ( ) .
* /
if ( state = = TASK_RUNNING | | state = = TASK_WAKING )
return true ;
/ *
* Ensure we load p - > on_rq after p - > _ _ state , otherwise it would be
* possible to , falsely , observe p - > on_rq = = 0 .
*
* See try_to_wake_up ( ) for a longer comment .
* /
smp_rmb ( ) ;
if ( p - > on_rq )
return true ;
/ *
* Ensure the task has finished _ _ schedule ( ) and will not be referenced
* anymore . Again , see try_to_wake_up ( ) for a longer comment .
* /
smp_rmb ( ) ;
smp_cond_load_acquire ( & p - > on_cpu , ! VAL ) ;
return false ;
}
/ * *
* task_call_func - Invoke a function on task in fixed state
* @ p : Process for which the function is to be invoked , can be @ current .
* @ func : Function to invoke .
* @ arg : Argument to function .
*
* Fix the task in it ' s current state by avoiding wakeups and or rq operations
* and call @ func ( @ arg ) on it . This function can use task_is_runnable ( ) and
* task_curr ( ) to work out what the state is , if required . Given that @ func
* can be invoked with a runqueue lock held , it had better be quite
* lightweight .
*
* Returns :
* Whatever @ func returns
* /
int task_call_func ( struct task_struct * p , task_call_f func , void * arg )
{
struct rq * rq = NULL ;
struct rq_flags rf ;
int ret ;
raw_spin_lock_irqsave ( & p - > pi_lock , rf . flags ) ;
if ( _ _ task_needs_rq_lock ( p ) )
rq = _ _ task_rq_lock ( p , & rf ) ;
/ *
* At this point the task is pinned ; either :
* - blocked and we ' re holding off wakeups ( pi - > lock )
* - woken , and we ' re holding off enqueue ( rq - > lock )
* - queued , and we ' re holding off schedule ( rq - > lock )
* - running , and we ' re holding off de - schedule ( rq - > lock )
*
* The called function ( @ func ) can use : task_curr ( ) , p - > on_rq and
* p - > _ _ state to differentiate between these states .
* /
ret = func ( p , arg ) ;
if ( rq )
rq_unlock ( rq , & rf ) ;
raw_spin_unlock_irqrestore ( & p - > pi_lock , rf . flags ) ;
return ret ;
}
/ * *
* cpu_curr_snapshot - Return a snapshot of the currently running task
* @ cpu : The CPU on which to snapshot the task .
*
* Returns the task_struct pointer of the task " currently " running on
* the specified CPU .
*
* If the specified CPU was offline , the return value is whatever it
* is , perhaps a pointer to the task_struct structure of that CPU ' s idle
* task , but there is no guarantee . Callers wishing a useful return
* value must take some action to ensure that the specified CPU remains
* online throughout .
*
* This function executes full memory barriers before and after fetching
* the pointer , which permits the caller to confine this function ' s fetch
* with respect to the caller ' s accesses to other shared variables .
* /
struct task_struct * cpu_curr_snapshot ( int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct task_struct * t ;
struct rq_flags rf ;
rq_lock_irqsave ( rq , & rf ) ;
smp_mb__after_spinlock ( ) ; / * Pairing determined by caller ' s synchronization design . * /
t = rcu_dereference ( cpu_curr ( cpu ) ) ;
rq_unlock_irqrestore ( rq , & rf ) ;
smp_mb ( ) ; / * Pairing determined by caller ' s synchronization design . * /
return t ;
}
/ * *
* wake_up_process - Wake up a specific process
* @ p : The process to be woken up .
*
* Attempt to wake up the nominated process and move it to the set of runnable
* processes .
*
* Return : 1 if the process was woken up , 0 if it was already running .
*
* This function executes a full memory barrier before accessing the task state .
* /
int wake_up_process ( struct task_struct * p )
{
return try_to_wake_up ( p , TASK_NORMAL , 0 ) ;
}
EXPORT_SYMBOL ( wake_up_process ) ;
int wake_up_state ( struct task_struct * p , unsigned int state )
{
return try_to_wake_up ( p , state , 0 ) ;
}
/ *
* Perform scheduler related setup for a newly forked process p .
* p is forked by current .
*
* _ _ sched_fork ( ) is basic setup which is also used by sched_init ( ) to
* initialize the boot CPU ' s idle task .
* /
static void _ _ sched_fork ( unsigned long clone_flags , struct task_struct * p )
{
p - > on_rq = 0 ;
p - > se . on_rq = 0 ;
p - > se . exec_start = 0 ;
p - > se . sum_exec_runtime = 0 ;
p - > se . prev_sum_exec_runtime = 0 ;
p - > se . nr_migrations = 0 ;
p - > se . vruntime = 0 ;
p - > se . vlag = 0 ;
INIT_LIST_HEAD ( & p - > se . group_node ) ;
/ * A delayed task cannot be in clone ( ) . * /
WARN_ON_ONCE ( p - > se . sched_delayed ) ;
# ifdef CONFIG_FAIR_GROUP_SCHED
p - > se . cfs_rq = NULL ;
# endif
# ifdef CONFIG_SCHEDSTATS
/ * Even if schedstat is disabled , there should not be garbage * /
memset ( & p - > stats , 0 , sizeof ( p - > stats ) ) ;
# endif
init_dl_entity ( & p - > dl ) ;
INIT_LIST_HEAD ( & p - > rt . run_list ) ;
p - > rt . timeout = 0 ;
p - > rt . time_slice = sched_rr_timeslice ;
p - > rt . on_rq = 0 ;
p - > rt . on_list = 0 ;
# ifdef CONFIG_SCHED_CLASS_EXT
init_scx_entity ( & p - > scx ) ;
# endif
# ifdef CONFIG_PREEMPT_NOTIFIERS
INIT_HLIST_HEAD ( & p - > preempt_notifiers ) ;
# endif
# ifdef CONFIG_COMPACTION
p - > capture_control = NULL ;
# endif
init_numa_balancing ( clone_flags , p ) ;
p - > wake_entry . u_flags = CSD_TYPE_TTWU ;
p - > migration_pending = NULL ;
init_sched_mm_cid ( p ) ;
}
DEFINE_STATIC_KEY_FALSE ( sched_numa_balancing ) ;
# ifdef CONFIG_NUMA_BALANCING
int sysctl_numa_balancing_mode ;
static void _ _ set_numabalancing_state ( bool enabled )
{
if ( enabled )
static_branch_enable ( & sched_numa_balancing ) ;
else
static_branch_disable ( & sched_numa_balancing ) ;
}
void set_numabalancing_state ( bool enabled )
{
if ( enabled )
sysctl_numa_balancing_mode = NUMA_BALANCING_NORMAL ;
else
sysctl_numa_balancing_mode = NUMA_BALANCING_DISABLED ;
_ _ set_numabalancing_state ( enabled ) ;
}
# ifdef CONFIG_PROC_SYSCTL
static void reset_memory_tiering ( void )
{
struct pglist_data * pgdat ;
for_each_online_pgdat ( pgdat ) {
pgdat - > nbp_threshold = 0 ;
pgdat - > nbp_th_nr_cand = node_page_state ( pgdat , PGPROMOTE_CANDIDATE ) ;
pgdat - > nbp_th_start = jiffies_to_msecs ( jiffies ) ;
}
}
static int sysctl_numa_balancing ( const struct ctl_table * table , int write ,
void * buffer , size_t * lenp , loff_t * ppos )
{
struct ctl_table t ;
int err ;
int state = sysctl_numa_balancing_mode ;
if ( write & & ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
t = * table ;
t . data = & state ;
err = proc_dointvec_minmax ( & t , write , buffer , lenp , ppos ) ;
if ( err < 0 )
return err ;
if ( write ) {
if ( ! ( sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING ) & &
( state & NUMA_BALANCING_MEMORY_TIERING ) )
reset_memory_tiering ( ) ;
sysctl_numa_balancing_mode = state ;
_ _ set_numabalancing_state ( state ) ;
}
return err ;
}
# endif / * CONFIG_PROC_SYSCTL * /
# endif / * CONFIG_NUMA_BALANCING * /
# ifdef CONFIG_SCHEDSTATS
DEFINE_STATIC_KEY_FALSE ( sched_schedstats ) ;
static void set_schedstats ( bool enabled )
{
if ( enabled )
static_branch_enable ( & sched_schedstats ) ;
else
static_branch_disable ( & sched_schedstats ) ;
}
void force_schedstat_enabled ( void )
{
if ( ! schedstat_enabled ( ) ) {
pr_info ( " kernel profiling enabled schedstats , disable via kernel . sched_schedstats . \ n " ) ;
static_branch_enable ( & sched_schedstats ) ;
}
}
static int _ _ init setup_schedstats ( char * str )
{
int ret = 0 ;
if ( ! str )
goto out ;
if ( ! strcmp ( str , " enable " ) ) {
set_schedstats ( true ) ;
ret = 1 ;
} else if ( ! strcmp ( str , " disable " ) ) {
set_schedstats ( false ) ;
ret = 1 ;
}
out :
if ( ! ret )
pr_warn ( " Unable to parse schedstats = \ n " ) ;
return ret ;
}
_ _ setup ( " schedstats = " , setup_schedstats ) ;
# ifdef CONFIG_PROC_SYSCTL
static int sysctl_schedstats ( const struct ctl_table * table , int write , void * buffer ,
size_t * lenp , loff_t * ppos )
{
struct ctl_table t ;
int err ;
int state = static_branch_likely ( & sched_schedstats ) ;
if ( write & & ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
t = * table ;
t . data = & state ;
err = proc_dointvec_minmax ( & t , write , buffer , lenp , ppos ) ;
if ( err < 0 )
return err ;
if ( write )
set_schedstats ( state ) ;
return err ;
}
# endif / * CONFIG_PROC_SYSCTL * /
# endif / * CONFIG_SCHEDSTATS * /
# ifdef CONFIG_SYSCTL
static const struct ctl_table sched_core_sysctls [ ] = {
# ifdef CONFIG_SCHEDSTATS
{
. procname = " sched_schedstats " ,
. data = NULL ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_schedstats ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE ,
} ,
# endif / * CONFIG_SCHEDSTATS * /
# ifdef CONFIG_UCLAMP_TASK
{
. procname = " sched_util_clamp_min " ,
. data = & sysctl_sched_uclamp_util_min ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_sched_uclamp_handler ,
} ,
{
. procname = " sched_util_clamp_max " ,
. data = & sysctl_sched_uclamp_util_max ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_sched_uclamp_handler ,
} ,
{
. procname = " sched_util_clamp_min_rt_default " ,
. data = & sysctl_sched_uclamp_util_min_rt_default ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_sched_uclamp_handler ,
} ,
# endif / * CONFIG_UCLAMP_TASK * /
# ifdef CONFIG_NUMA_BALANCING
{
. procname = " numa_balancing " ,
. data = NULL , / * filled in by handler * /
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_numa_balancing ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_FOUR ,
} ,
# endif / * CONFIG_NUMA_BALANCING * /
} ;
static int _ _ init sched_core_sysctl_init ( void )
{
register_sysctl_init ( " kernel " , sched_core_sysctls ) ;
return 0 ;
}
late_initcall ( sched_core_sysctl_init ) ;
# endif / * CONFIG_SYSCTL * /
/ *
* fork ( ) / clone ( ) - time setup :
* /
int sched_fork ( unsigned long clone_flags , struct task_struct * p )
{
_ _ sched_fork ( clone_flags , p ) ;
/ *
* We mark the process as NEW here . This guarantees that
* nobody will actually run it , and a signal or other external
* event cannot wake it up and insert it on the runqueue either .
* /
p - > _ _ state = TASK_NEW ;
/ *
* Make sure we do not leak PI boosting priority to the child .
* /
p - > prio = current - > normal_prio ;
uclamp_fork ( p ) ;
/ *
* Revert to default priority / policy on fork if requested .
* /
if ( unlikely ( p - > sched_reset_on_fork ) ) {
if ( task_has_dl_policy ( p ) | | task_has_rt_policy ( p ) ) {
p - > policy = SCHED_NORMAL ;
p - > static_prio = NICE_TO_PRIO ( 0 ) ;
p - > rt_priority = 0 ;
} else if ( PRIO_TO_NICE ( p - > static_prio ) < 0 )
p - > static_prio = NICE_TO_PRIO ( 0 ) ;
p - > prio = p - > normal_prio = p - > static_prio ;
set_load_weight ( p , false ) ;
p - > se . custom_slice = 0 ;
p - > se . slice = sysctl_sched_base_slice ;
/ *
* We don ' t need the reset flag anymore after the fork . It has
* fulfilled its duty :
* /
p - > sched_reset_on_fork = 0 ;
}
if ( dl_prio ( p - > prio ) )
return - EAGAIN ;
scx_pre_fork ( p ) ;
if ( rt_prio ( p - > prio ) ) {
p - > sched_class = & rt_sched_class ;
# ifdef CONFIG_SCHED_CLASS_EXT
} else if ( task_should_scx ( p - > policy ) ) {
p - > sched_class = & ext_sched_class ;
# endif
} else {
p - > sched_class = & fair_sched_class ;
}
init_entity_runnable_average ( & p - > se ) ;
# ifdef CONFIG_SCHED_INFO
if ( likely ( sched_info_on ( ) ) )
memset ( & p - > sched_info , 0 , sizeof ( p - > sched_info ) ) ;
# endif
p - > on_cpu = 0 ;
init_task_preempt_count ( p ) ;
plist_node_init ( & p - > pushable_tasks , MAX_PRIO ) ;
RB_CLEAR_NODE ( & p - > pushable_dl_tasks ) ;
return 0 ;
}
int sched_cgroup_fork ( struct task_struct * p , struct kernel_clone_args * kargs )
{
unsigned long flags ;
/ *
* Because we ' re not yet on the pid - hash , p - > pi_lock isn ' t strictly
* required yet , but lockdep gets upset if rules are violated .
* /
raw_spin_lock_irqsave ( & p - > pi_lock , flags ) ;
# ifdef CONFIG_CGROUP_SCHED
if ( 1 ) {
struct task_group * tg ;
tg = container_of ( kargs - > cset - > subsys [ cpu_cgrp_id ] ,
struct task_group , css ) ;
tg = autogroup_task_group ( p , tg ) ;
p - > sched_task_group = tg ;
}
# endif
rseq_migrate ( p ) ;
/ *
* We ' re setting the CPU for the first time , we don ' t migrate ,
* so use _ _ set_task_cpu ( ) .
* /
_ _ set_task_cpu ( p , smp_processor_id ( ) ) ;
if ( p - > sched_class - > task_fork )
p - > sched_class - > task_fork ( p ) ;
raw_spin_unlock_irqrestore ( & p - > pi_lock , flags ) ;
return scx_fork ( p ) ;
}
void sched_cancel_fork ( struct task_struct * p )
{
scx_cancel_fork ( p ) ;
}
void sched_post_fork ( struct task_struct * p )
{
uclamp_post_fork ( p ) ;
scx_post_fork ( p ) ;
}
unsigned long to_ratio ( u64 period , u64 runtime )
{
if ( runtime = = RUNTIME_INF )
return BW_UNIT ;
/ *
* Doing this here saves a lot of checks in all
* the calling paths , and returning zero seems
* safe for them anyway .
* /
if ( period = = 0 )
return 0 ;
return div64_u64 ( runtime < < BW_SHIFT , period ) ;
}
/ *
* wake_up_new_task - wake up a newly created task for the first time .
*
* This function will do some initial scheduler statistics housekeeping
* that must be done for every newly created context , then puts the task
* on the runqueue and wakes it .
* /
void wake_up_new_task ( struct task_struct * p )
{
struct rq_flags rf ;
struct rq * rq ;
int wake_flags = WF_FORK ;
raw_spin_lock_irqsave ( & p - > pi_lock , rf . flags ) ;
WRITE_ONCE ( p - > _ _ state , TASK_RUNNING ) ;
/ *
* Fork balancing , do it here and not earlier because :
* - cpus_ptr can change in the fork path
* - any previously selected CPU might disappear through hotplug
*
* Use _ _ set_task_cpu ( ) to avoid calling sched_class : : migrate_task_rq ,
* as we ' re not fully set - up yet .
* /
p - > recent_used_cpu = task_cpu ( p ) ;
rseq_migrate ( p ) ;
_ _ set_task_cpu ( p , select_task_rq ( p , task_cpu ( p ) , & wake_flags ) ) ;
rq = _ _ task_rq_lock ( p , & rf ) ;
update_rq_clock ( rq ) ;
post_init_entity_util_avg ( p ) ;
activate_task ( rq , p , ENQUEUE_NOCLOCK | ENQUEUE_INITIAL ) ;
trace_sched_wakeup_new ( p ) ;
wakeup_preempt ( rq , p , wake_flags ) ;
if ( p - > sched_class - > task_woken ) {
/ *
* Nothing relies on rq - > lock after this , so it ' s fine to
* drop it .
* /
rq_unpin_lock ( rq , & rf ) ;
p - > sched_class - > task_woken ( rq , p ) ;
rq_repin_lock ( rq , & rf ) ;
}
task_rq_unlock ( rq , p , & rf ) ;
}
# ifdef CONFIG_PREEMPT_NOTIFIERS
static DEFINE_STATIC_KEY_FALSE ( preempt_notifier_key ) ;
void preempt_notifier_inc ( void )
{
static_branch_inc ( & preempt_notifier_key ) ;
}
EXPORT_SYMBOL_GPL ( preempt_notifier_inc ) ;
void preempt_notifier_dec ( void )
{
static_branch_dec ( & preempt_notifier_key ) ;
}
EXPORT_SYMBOL_GPL ( preempt_notifier_dec ) ;
/ * *
* preempt_notifier_register - tell me when current is being preempted & rescheduled
* @ notifier : notifier struct to register
* /
void preempt_notifier_register ( struct preempt_notifier * notifier )
{
if ( ! static_branch_unlikely ( & preempt_notifier_key ) )
WARN ( 1 , " registering preempt_notifier while notifiers disabled \ n " ) ;
hlist_add_head ( & notifier - > link , & current - > preempt_notifiers ) ;
}
EXPORT_SYMBOL_GPL ( preempt_notifier_register ) ;
/ * *
* preempt_notifier_unregister - no longer interested in preemption notifications
* @ notifier : notifier struct to unregister
*
* This is * not * safe to call from within a preemption notifier .
* /
void preempt_notifier_unregister ( struct preempt_notifier * notifier )
{
hlist_del ( & notifier - > link ) ;
}
EXPORT_SYMBOL_GPL ( preempt_notifier_unregister ) ;
static void _ _ fire_sched_in_preempt_notifiers ( struct task_struct * curr )
{
struct preempt_notifier * notifier ;
hlist_for_each_entry ( notifier , & curr - > preempt_notifiers , link )
notifier - > ops - > sched_in ( notifier , raw_smp_processor_id ( ) ) ;
}
static _ _ always_inline void fire_sched_in_preempt_notifiers ( struct task_struct * curr )
{
if ( static_branch_unlikely ( & preempt_notifier_key ) )
_ _ fire_sched_in_preempt_notifiers ( curr ) ;
}
static void
_ _ fire_sched_out_preempt_notifiers ( struct task_struct * curr ,
struct task_struct * next )
{
struct preempt_notifier * notifier ;
hlist_for_each_entry ( notifier , & curr - > preempt_notifiers , link )
notifier - > ops - > sched_out ( notifier , next ) ;
}
static _ _ always_inline void
fire_sched_out_preempt_notifiers ( struct task_struct * curr ,
struct task_struct * next )
{
if ( static_branch_unlikely ( & preempt_notifier_key ) )
_ _ fire_sched_out_preempt_notifiers ( curr , next ) ;
}
# else / * ! CONFIG_PREEMPT_NOTIFIERS : * /
static inline void fire_sched_in_preempt_notifiers ( struct task_struct * curr )
{
}
static inline void
fire_sched_out_preempt_notifiers ( struct task_struct * curr ,
struct task_struct * next )
{
}
# endif / * ! CONFIG_PREEMPT_NOTIFIERS * /
static inline void prepare_task ( struct task_struct * next )
{
/ *
* Claim the task as running , we do this before switching to it
* such that any running task will have this set .
*
* See the smp_load_acquire ( & p - > on_cpu ) case in ttwu ( ) and
* its ordering comment .
* /
WRITE_ONCE ( next - > on_cpu , 1 ) ;
}
static inline void finish_task ( struct task_struct * prev )
{
/ *
* This must be the very last reference to @ prev from this CPU . After
* p - > on_cpu is cleared , the task can be moved to a different CPU . We
* must ensure this doesn ' t happen until the switch is completely
* finished .
*
* In particular , the load of prev - > state in finish_task_switch ( ) must
* happen before this .
*
* Pairs with the smp_cond_load_acquire ( ) in try_to_wake_up ( ) .
* /
smp_store_release ( & prev - > on_cpu , 0 ) ;
}
static void do_balance_callbacks ( struct rq * rq , struct balance_callback * head )
{
void ( * func ) ( struct rq * rq ) ;
struct balance_callback * next ;
lockdep_assert_rq_held ( rq ) ;
while ( head ) {
func = ( void ( * ) ( struct rq * ) ) head - > func ;
next = head - > next ;
head - > next = NULL ;
head = next ;
func ( rq ) ;
}
}
static void balance_push ( struct rq * rq ) ;
/ *
* balance_push_callback is a right abuse of the callback interface and plays
* by significantly different rules .
*
* Where the normal balance_callback ' s purpose is to be ran in the same context
* that queued it ( only later , when it ' s safe to drop rq - > lock again ) ,
* balance_push_callback is specifically targeted at _ _ schedule ( ) .
*
* This abuse is tolerated because it places all the unlikely / odd cases behind
* a single test , namely : rq - > balance_callback = = NULL .
* /
struct balance_callback balance_push_callback = {
. next = NULL ,
. func = balance_push ,
} ;
static inline struct balance_callback *
_ _ splice_balance_callbacks ( struct rq * rq , bool split )
{
struct balance_callback * head = rq - > balance_callback ;
if ( likely ( ! head ) )
return NULL ;
lockdep_assert_rq_held ( rq ) ;
/ *
* Must not take balance_push_callback off the list when
* splice_balance_callbacks ( ) and balance_callbacks ( ) are not
* in the same rq - > lock section .
*
* In that case it would be possible for _ _ schedule ( ) to interleave
* and observe the list empty .
* /
if ( split & & head = = & balance_push_callback )
head = NULL ;
else
rq - > balance_callback = NULL ;
return head ;
}
struct balance_callback * splice_balance_callbacks ( struct rq * rq )
{
return _ _ splice_balance_callbacks ( rq , true ) ;
}
static void _ _ balance_callbacks ( struct rq * rq )
{
do_balance_callbacks ( rq , _ _ splice_balance_callbacks ( rq , false ) ) ;
}
void balance_callbacks ( struct rq * rq , struct balance_callback * head )
{
unsigned long flags ;
if ( unlikely ( head ) ) {
raw_spin_rq_lock_irqsave ( rq , flags ) ;
do_balance_callbacks ( rq , head ) ;
raw_spin_rq_unlock_irqrestore ( rq , flags ) ;
}
}
static inline void
prepare_lock_switch ( struct rq * rq , struct task_struct * next , struct rq_flags * rf )
{
/ *
* Since the runqueue lock will be released by the next
* task ( which is an invalid locking op but in the case
* of the scheduler it ' s an obvious special - case ) , so we
* do an early lockdep release here :
* /
rq_unpin_lock ( rq , rf ) ;
spin_release ( & _ _ rq_lockp ( rq ) - > dep_map , _ THIS_IP_ ) ;
# ifdef CONFIG_DEBUG_SPINLOCK
/ * this is a valid case when another task releases the spinlock * /
rq_lockp ( rq ) - > owner = next ;
# endif
}
static inline void finish_lock_switch ( struct rq * rq )
{
/ *
* If we are tracking spinlock dependencies then we have to
* fix up the runqueue lock - which gets ' carried over ' from
* prev into current :
* /
spin_acquire ( & _ _ rq_lockp ( rq ) - > dep_map , 0 , 0 , _ THIS_IP_ ) ;
_ _ balance_callbacks ( rq ) ;
raw_spin_rq_unlock_irq ( rq ) ;
}
/ *
* NOP if the arch has not defined these :
* /
# ifndef prepare_arch_switch
# define prepare_arch_switch ( next ) do { } while ( 0 )
# endif
# ifndef finish_arch_post_lock_switch
# define finish_arch_post_lock_switch ( ) do { } while ( 0 )
# endif
static inline void kmap_local_sched_out ( void )
{
# ifdef CONFIG_KMAP_LOCAL
if ( unlikely ( current - > kmap_ctrl . idx ) )
_ _ kmap_local_sched_out ( ) ;
# endif
}
static inline void kmap_local_sched_in ( void )
{
# ifdef CONFIG_KMAP_LOCAL
if ( unlikely ( current - > kmap_ctrl . idx ) )
_ _ kmap_local_sched_in ( ) ;
# endif
}
/ * *
* prepare_task_switch - prepare to switch tasks
* @ rq : the runqueue preparing to switch
* @ prev : the current task that is being switched out
* @ next : the task we are going to switch to .
*
* This is called with the rq lock held and interrupts off . It must
* be paired with a subsequent finish_task_switch after the context
* switch .
*
* prepare_task_switch sets up locking and calls architecture specific
* hooks .
* /
static inline void
prepare_task_switch ( struct rq * rq , struct task_struct * prev ,
struct task_struct * next )
{
kcov_prepare_switch ( prev ) ;
sched_info_switch ( rq , prev , next ) ;
perf_event_task_sched_out ( prev , next ) ;
rseq_preempt ( prev ) ;
fire_sched_out_preempt_notifiers ( prev , next ) ;
kmap_local_sched_out ( ) ;
prepare_task ( next ) ;
prepare_arch_switch ( next ) ;
}
/ * *
* finish_task_switch - clean up after a task - switch
* @ prev : the thread we just switched away from .
*
* finish_task_switch must be called after the context switch , paired
* with a prepare_task_switch call before the context switch .
* finish_task_switch will reconcile locking set up by prepare_task_switch ,
* and do any other architecture - specific cleanup actions .
*
* Note that we may have delayed dropping an mm in context_switch ( ) . If
* so , we finish that here outside of the runqueue lock . ( Doing it
* with the lock held can cause deadlocks ; see schedule ( ) for
* details . )
*
* The context switch have flipped the stack from under us and restored the
* local variables which were saved when this task called schedule ( ) in the
* past . ' prev = = current ' is still correct but we need to recalculate this_rq
* because prev may have moved to another CPU .
* /
static struct rq * finish_task_switch ( struct task_struct * prev )
_ _ releases ( rq - > lock )
{
struct rq * rq = this_rq ( ) ;
struct mm_struct * mm = rq - > prev_mm ;
unsigned int prev_state ;
/ *
* The previous task will have left us with a preempt_count of 2
* because it left us after :
*
* schedule ( )
* preempt_disable ( ) ; / / 1
* _ _ schedule ( )
* raw_spin_lock_irq ( & rq - > lock ) / / 2
*
* Also , see FORK_PREEMPT_COUNT .
* /
if ( WARN_ONCE ( preempt_count ( ) ! = 2 * PREEMPT_DISABLE_OFFSET ,
" corrupted preempt_count : % s / % d / 0 x % x \ n " ,
current - > comm , current - > pid , preempt_count ( ) ) )
preempt_count_set ( FORK_PREEMPT_COUNT ) ;
rq - > prev_mm = NULL ;
/ *
* A task struct has one reference for the use as " current " .
* If a task dies , then it sets TASK_DEAD in tsk - > state and calls
* schedule one last time . The schedule call will never return , and
* the scheduled task must drop that reference .
*
* We must observe prev - > state before clearing prev - > on_cpu ( in
* finish_task ) , otherwise a concurrent wakeup can get prev
* running on another CPU and we could rave with its RUNNING - > DEAD
* transition , resulting in a double drop .
* /
prev_state = READ_ONCE ( prev - > _ _ state ) ;
vtime_task_switch ( prev ) ;
perf_event_task_sched_in ( prev , current ) ;
finish_task ( prev ) ;
tick_nohz_task_switch ( ) ;
finish_lock_switch ( rq ) ;
finish_arch_post_lock_switch ( ) ;
kcov_finish_switch ( current ) ;
/ *
* kmap_local_sched_out ( ) is invoked with rq : : lock held and
* interrupts disabled . There is no requirement for that , but the
* sched out code does not have an interrupt enabled section .
* Restoring the maps on sched in does not require interrupts being
* disabled either .
* /
kmap_local_sched_in ( ) ;
fire_sched_in_preempt_notifiers ( current ) ;
/ *
* When switching through a kernel thread , the loop in
* membarrier_ { private , global } _ expedited ( ) may have observed that
* kernel thread and not issued an IPI . It is therefore possible to
* schedule between user - > kernel - > user threads without passing though
* switch_mm ( ) . Membarrier requires a barrier after storing to
* rq - > curr , before returning to userspace , so provide them here :
*
* - a full memory barrier for { PRIVATE , GLOBAL } _ EXPEDITED , implicitly
* provided by mmdrop_lazy_tlb ( ) ,
* - a sync_core for SYNC_CORE .
* /
if ( mm ) {
membarrier_mm_sync_core_before_usermode ( mm ) ;
mmdrop_lazy_tlb_sched ( mm ) ;
}
if ( unlikely ( prev_state = = TASK_DEAD ) ) {
if ( prev - > sched_class - > task_dead )
prev - > sched_class - > task_dead ( prev ) ;
/ * Task is done with its stack . * /
put_task_stack ( prev ) ;
put_task_struct_rcu_user ( prev ) ;
}
return rq ;
}
/ * *
* schedule_tail - first thing a freshly forked thread must call .
* @ prev : the thread we just switched away from .
* /
asmlinkage _ _ visible void schedule_tail ( struct task_struct * prev )
_ _ releases ( rq - > lock )
{
/ *
* New tasks start with FORK_PREEMPT_COUNT , see there and
* finish_task_switch ( ) for details .
*
* finish_task_switch ( ) will drop rq - > lock ( ) and lower preempt_count
* and the preempt_enable ( ) will end up enabling preemption ( on
* PREEMPT_COUNT kernels ) .
* /
finish_task_switch ( prev ) ;
/ *
* This is a special case : the newly created task has just
* switched the context for the first time . It is returning from
* schedule for the first time in this path .
* /
trace_sched_exit_tp ( true ) ;
preempt_enable ( ) ;
if ( current - > set_child_tid )
put_user ( task_pid_vnr ( current ) , current - > set_child_tid ) ;
calculate_sigpending ( ) ;
}
/ *
* context_switch - switch to the new MM and the new thread ' s register state .
* /
static _ _ always_inline struct rq *
context_switch ( struct rq * rq , struct task_struct * prev ,
struct task_struct * next , struct rq_flags * rf )
{
prepare_task_switch ( rq , prev , next ) ;
/ *
* For paravirt , this is coupled with an exit in switch_to to
* combine the page table reload and the switch backend into
* one hypercall .
* /
arch_start_context_switch ( prev ) ;
/ *
* kernel - > kernel lazy + transfer active
* user - > kernel lazy + mmgrab_lazy_tlb ( ) active
*
* kernel - > user switch + mmdrop_lazy_tlb ( ) active
* user - > user switch
*
* switch_mm_cid ( ) needs to be updated if the barriers provided
* by context_switch ( ) are modified .
* /
if ( ! next - > mm ) { / / to kernel
enter_lazy_tlb ( prev - > active_mm , next ) ;
next - > active_mm = prev - > active_mm ;
if ( prev - > mm ) / / from user
mmgrab_lazy_tlb ( prev - > active_mm ) ;
else
prev - > active_mm = NULL ;
} else { / / to user
membarrier_switch_mm ( rq , prev - > active_mm , next - > mm ) ;
/ *
* sys_membarrier ( ) requires an smp_mb ( ) between setting
* rq - > curr / membarrier_switch_mm ( ) and returning to userspace .
*
* The below provides this either through switch_mm ( ) , or in
* case ' prev - > active_mm = = next - > mm ' through
* finish_task_switch ( ) ' s mmdrop ( ) .
* /
switch_mm_irqs_off ( prev - > active_mm , next - > mm , next ) ;
lru_gen_use_mm ( next - > mm ) ;
if ( ! prev - > mm ) { / / from kernel
/ * will mmdrop_lazy_tlb ( ) in finish_task_switch ( ) . * /
rq - > prev_mm = prev - > active_mm ;
prev - > active_mm = NULL ;
}
}
/ * switch_mm_cid ( ) requires the memory barriers above . * /
switch_mm_cid ( rq , prev , next ) ;
prepare_lock_switch ( rq , next , rf ) ;
/ * Here we just switch the register state and the stack . * /
switch_to ( prev , next , prev ) ;
barrier ( ) ;
return finish_task_switch ( prev ) ;
}
/ *
* nr_running and nr_context_switches :
*
* externally visible scheduler statistics : current number of runnable
* threads , total number of context switches performed since bootup .
* /
unsigned int nr_running ( void )
{
unsigned int i , sum = 0 ;
for_each_online_cpu ( i )
sum + = cpu_rq ( i ) - > nr_running ;
return sum ;
}
/ *
* Check if only the current task is running on the CPU .
*
* Caution : this function does not check that the caller has disabled
* preemption , thus the result might have a time - of - check - to - time - of - use
* race . The caller is responsible to use it correctly , for example :
*
* - from a non - preemptible section ( of course )
*
* - from a thread that is bound to a single CPU
*
* - in a loop with very short iterations ( e . g . a polling loop )
* /
bool single_task_running ( void )
{
return raw_rq ( ) - > nr_running = = 1 ;
}
EXPORT_SYMBOL ( single_task_running ) ;
unsigned long long nr_context_switches_cpu ( int cpu )
{
return cpu_rq ( cpu ) - > nr_switches ;
}
unsigned long long nr_context_switches ( void )
{
int i ;
unsigned long long sum = 0 ;
for_each_possible_cpu ( i )
sum + = cpu_rq ( i ) - > nr_switches ;
return sum ;
}
/ *
* Consumers of these two interfaces , like for example the cpuidle menu
* governor , are using nonsensical data . Preferring shallow idle state selection
* for a CPU that has IO - wait which might not even end up running the task when
* it does become runnable .
* /
unsigned int nr_iowait_cpu ( int cpu )
{
return atomic_read ( & cpu_rq ( cpu ) - > nr_iowait ) ;
}
/ *
* IO - wait accounting , and how it ' s mostly bollocks ( on SMP ) .
*
* The idea behind IO - wait account is to account the idle time that we could
* have spend running if it were not for IO . That is , if we were to improve the
* storage performance , we ' d have a proportional reduction in IO - wait time .
*
* This all works nicely on UP , where , when a task blocks on IO , we account
* idle time as IO - wait , because if the storage were faster , it could ' ve been
* running and we ' d not be idle .
*
* This has been extended to SMP , by doing the same for each CPU . This however
* is broken .
*
* Imagine for instance the case where two tasks block on one CPU , only the one
* CPU will have IO - wait accounted , while the other has regular idle . Even
* though , if the storage were faster , both could ' ve ran at the same time ,
* utilising both CPUs .
*
* This means , that when looking globally , the current IO - wait accounting on
* SMP is a lower bound , by reason of under accounting .
*
* Worse , since the numbers are provided per CPU , they are sometimes
* interpreted per CPU , and that is nonsensical . A blocked task isn ' t strictly
* associated with any one particular CPU , it can wake to another CPU than it
* blocked on . This means the per CPU IO - wait number is meaningless .
*
* Task CPU affinities can make all that even more ' interesting ' .
* /
unsigned int nr_iowait ( void )
{
unsigned int i , sum = 0 ;
for_each_possible_cpu ( i )
sum + = nr_iowait_cpu ( i ) ;
return sum ;
}
/ *
* sched_exec - execve ( ) is a valuable balancing opportunity , because at
* this point the task has the smallest effective memory and cache footprint .
* /
void sched_exec ( void )
{
struct task_struct * p = current ;
struct migration_arg arg ;
int dest_cpu ;
scoped_guard ( raw_spinlock_irqsave , & p - > pi_lock ) {
dest_cpu = p - > sched_class - > select_task_rq ( p , task_cpu ( p ) , WF_EXEC ) ;
if ( dest_cpu = = smp_processor_id ( ) )
return ;
if ( unlikely ( ! cpu_active ( dest_cpu ) ) )
return ;
arg = ( struct migration_arg ) { p , dest_cpu } ;
}
stop_one_cpu ( task_cpu ( p ) , migration_cpu_stop , & arg ) ;
}
DEFINE_PER_CPU ( struct kernel_stat , kstat ) ;
DEFINE_PER_CPU ( struct kernel_cpustat , kernel_cpustat ) ;
EXPORT_PER_CPU_SYMBOL ( kstat ) ;
EXPORT_PER_CPU_SYMBOL ( kernel_cpustat ) ;
/ *
* The function fair_sched_class . update_curr accesses the struct curr
* and its field curr - > exec_start ; when called from task_sched_runtime ( ) ,
* we observe a high rate of cache misses in practice .
* Prefetching this data results in improved performance .
* /
static inline void prefetch_curr_exec_start ( struct task_struct * p )
{
# ifdef CONFIG_FAIR_GROUP_SCHED
struct sched_entity * curr = p - > se . cfs_rq - > curr ;
# else
struct sched_entity * curr = task_rq ( p ) - > cfs . curr ;
# endif
prefetch ( curr ) ;
prefetch ( & curr - > exec_start ) ;
}
/ *
* Return accounted runtime for the task .
* In case the task is currently running , return the runtime plus current ' s
* pending runtime that have not been accounted yet .
* /
unsigned long long task_sched_runtime ( struct task_struct * p )
{
struct rq_flags rf ;
struct rq * rq ;
u64 ns ;
# ifdef CONFIG_64BIT
/ *
* 64 - bit doesn ' t need locks to atomically read a 64 - bit value .
* So we have a optimization chance when the task ' s delta_exec is 0 .
* Reading - > on_cpu is racy , but this is OK .
*
* If we race with it leaving CPU , we ' ll take a lock . So we ' re correct .
* If we race with it entering CPU , unaccounted time is 0 . This is
* indistinguishable from the read occurring a few cycles earlier .
* If we see - > on_cpu without - > on_rq , the task is leaving , and has
* been accounted , so we ' re correct here as well .
* /
if ( ! p - > on_cpu | | ! task_on_rq_queued ( p ) )
return p - > se . sum_exec_runtime ;
# endif
rq = task_rq_lock ( p , & rf ) ;
/ *
* Must be - > curr _ and_ - > on_rq . If dequeued , we would
* project cycles that may never be accounted to this
* thread , breaking clock_gettime ( ) .
* /
if ( task_current_donor ( rq , p ) & & task_on_rq_queued ( p ) ) {
prefetch_curr_exec_start ( p ) ;
update_rq_clock ( rq ) ;
p - > sched_class - > update_curr ( rq ) ;
}
ns = p - > se . sum_exec_runtime ;
task_rq_unlock ( rq , p , & rf ) ;
return ns ;
}
static u64 cpu_resched_latency ( struct rq * rq )
{
int latency_warn_ms = READ_ONCE ( sysctl_resched_latency_warn_ms ) ;
u64 resched_latency , now = rq_clock ( rq ) ;
static bool warned_once ;
if ( sysctl_resched_latency_warn_once & & warned_once )
return 0 ;
if ( ! need_resched ( ) | | ! latency_warn_ms )
return 0 ;
if ( system_state = = SYSTEM_BOOTING )
return 0 ;
if ( ! rq - > last_seen_need_resched_ns ) {
rq - > last_seen_need_resched_ns = now ;
rq - > ticks_without_resched = 0 ;
return 0 ;
}
rq - > ticks_without_resched + + ;
resched_latency = now - rq - > last_seen_need_resched_ns ;
if ( resched_latency < = latency_warn_ms * NSEC_PER_MSEC )
return 0 ;
warned_once = true ;
return resched_latency ;
}
static int _ _ init setup_resched_latency_warn_ms ( char * str )
{
long val ;
if ( ( kstrtol ( str , 0 , & val ) ) ) {
pr_warn ( " Unable to set resched_latency_warn_ms \ n " ) ;
return 1 ;
}
sysctl_resched_latency_warn_ms = val ;
return 1 ;
}
_ _ setup ( " resched_latency_warn_ms = " , setup_resched_latency_warn_ms ) ;
/ *
* This function gets called by the timer code , with HZ frequency .
* We call it with interrupts disabled .
* /
void sched_tick ( void )
{
int cpu = smp_processor_id ( ) ;
struct rq * rq = cpu_rq ( cpu ) ;
/ * accounting goes to the donor task * /
struct task_struct * donor ;
struct rq_flags rf ;
unsigned long hw_pressure ;
u64 resched_latency ;
if ( housekeeping_cpu ( cpu , HK_TYPE_KERNEL_NOISE ) )
arch_scale_freq_tick ( ) ;
sched_clock_tick ( ) ;
rq_lock ( rq , & rf ) ;
donor = rq - > donor ;
psi_account_irqtime ( rq , donor , NULL ) ;
update_rq_clock ( rq ) ;
hw_pressure = arch_scale_hw_pressure ( cpu_of ( rq ) ) ;
update_hw_load_avg ( rq_clock_task ( rq ) , rq , hw_pressure ) ;
if ( dynamic_preempt_lazy ( ) & & tif_test_bit ( TIF_NEED_RESCHED_LAZY ) )
resched_curr ( rq ) ;
donor - > sched_class - > task_tick ( rq , donor , 0 ) ;
if ( sched_feat ( LATENCY_WARN ) )
resched_latency = cpu_resched_latency ( rq ) ;
calc_global_load_tick ( rq ) ;
sched_core_tick ( rq ) ;
task_tick_mm_cid ( rq , donor ) ;
scx_tick ( rq ) ;
rq_unlock ( rq , & rf ) ;
if ( sched_feat ( LATENCY_WARN ) & & resched_latency )
resched_latency_warn ( cpu , resched_latency ) ;
perf_event_task_tick ( ) ;
if ( donor - > flags & PF_WQ_WORKER )
wq_worker_tick ( donor ) ;
if ( ! scx_switched_all ( ) ) {
rq - > idle_balance = idle_cpu ( cpu ) ;
sched_balance_trigger ( rq ) ;
}
}
# ifdef CONFIG_NO_HZ_FULL
struct tick_work {
int cpu ;
atomic_t state ;
struct delayed_work work ;
} ;
/ * Values for - > state , see diagram below . * /
# define TICK_SCHED_REMOTE_OFFLINE 0
# define TICK_SCHED_REMOTE_OFFLINING 1
# define TICK_SCHED_REMOTE_RUNNING 2
/ *
* State diagram for - > state :
*
*
* TICK_SCHED_REMOTE_OFFLINE
* | ^
* | |
* | | sched_tick_remote ( )
* | |
* | |
* + - - TICK_SCHED_REMOTE_OFFLINING
* | ^
* | |
* sched_tick_start ( ) | | sched_tick_stop ( )
* | |
* V |
* TICK_SCHED_REMOTE_RUNNING
*
*
* Other transitions get WARN_ON_ONCE ( ) , except that sched_tick_remote ( )
* and sched_tick_start ( ) are happy to leave the state in RUNNING .
* /
static struct tick_work _ _ percpu * tick_work_cpu ;
static void sched_tick_remote ( struct work_struct * work )
{
struct delayed_work * dwork = to_delayed_work ( work ) ;
struct tick_work * twork = container_of ( dwork , struct tick_work , work ) ;
int cpu = twork - > cpu ;
struct rq * rq = cpu_rq ( cpu ) ;
int os ;
/ *
* Handle the tick only if it appears the remote CPU is running in full
* dynticks mode . The check is racy by nature , but missing a tick or
* having one too much is no big deal because the scheduler tick updates
* statistics and checks timeslices in a time - independent way , regardless
* of when exactly it is running .
* /
if ( tick_nohz_tick_stopped_cpu ( cpu ) ) {
guard ( rq_lock_irq ) ( rq ) ;
struct task_struct * curr = rq - > curr ;
if ( cpu_online ( cpu ) ) {
/ *
* Since this is a remote tick for full dynticks mode ,
* we are always sure that there is no proxy ( only a
* single task is running ) .
* /
WARN_ON_ONCE ( rq - > curr ! = rq - > donor ) ;
update_rq_clock ( rq ) ;
if ( ! is_idle_task ( curr ) ) {
/ *
* Make sure the next tick runs within a
* reasonable amount of time .
* /
u64 delta = rq_clock_task ( rq ) - curr - > se . exec_start ;
WARN_ON_ONCE ( delta > ( u64 ) NSEC_PER_SEC * 3 ) ;
}
curr - > sched_class - > task_tick ( rq , curr , 0 ) ;
calc_load_nohz_remote ( rq ) ;
}
}
/ *
* Run the remote tick once per second ( 1 Hz ) . This arbitrary
* frequency is large enough to avoid overload but short enough
* to keep scheduler internal stats reasonably up to date . But
* first update state to reflect hotplug activity if required .
* /
os = atomic_fetch_add_unless ( & twork - > state , - 1 , TICK_SCHED_REMOTE_RUNNING ) ;
WARN_ON_ONCE ( os = = TICK_SCHED_REMOTE_OFFLINE ) ;
if ( os = = TICK_SCHED_REMOTE_RUNNING )
queue_delayed_work ( system_unbound_wq , dwork , HZ ) ;
}
static void sched_tick_start ( int cpu )
{
int os ;
struct tick_work * twork ;
if ( housekeeping_cpu ( cpu , HK_TYPE_KERNEL_NOISE ) )
return ;
WARN_ON_ONCE ( ! tick_work_cpu ) ;
twork = per_cpu_ptr ( tick_work_cpu , cpu ) ;
os = atomic_xchg ( & twork - > state , TICK_SCHED_REMOTE_RUNNING ) ;
WARN_ON_ONCE ( os = = TICK_SCHED_REMOTE_RUNNING ) ;
if ( os = = TICK_SCHED_REMOTE_OFFLINE ) {
twork - > cpu = cpu ;
INIT_DELAYED_WORK ( & twork - > work , sched_tick_remote ) ;
queue_delayed_work ( system_unbound_wq , & twork - > work , HZ ) ;
}
}
# ifdef CONFIG_HOTPLUG_CPU
static void sched_tick_stop ( int cpu )
{
struct tick_work * twork ;
int os ;
if ( housekeeping_cpu ( cpu , HK_TYPE_KERNEL_NOISE ) )
return ;
WARN_ON_ONCE ( ! tick_work_cpu ) ;
twork = per_cpu_ptr ( tick_work_cpu , cpu ) ;
/ * There cannot be competing actions , but don ' t rely on stop - machine . * /
os = atomic_xchg ( & twork - > state , TICK_SCHED_REMOTE_OFFLINING ) ;
WARN_ON_ONCE ( os ! = TICK_SCHED_REMOTE_RUNNING ) ;
/ * Don ' t cancel , as this would mess up the state machine . * /
}
# endif / * CONFIG_HOTPLUG_CPU * /
int _ _ init sched_tick_offload_init ( void )
{
tick_work_cpu = alloc_percpu ( struct tick_work ) ;
BUG_ON ( ! tick_work_cpu ) ;
return 0 ;
}
# else / * ! CONFIG_NO_HZ_FULL : * /
static inline void sched_tick_start ( int cpu ) { }
static inline void sched_tick_stop ( int cpu ) { }
# endif / * ! CONFIG_NO_HZ_FULL * /
# if defined ( CONFIG_PREEMPTION ) & & ( defined ( CONFIG_DEBUG_PREEMPT ) | | \
defined ( CONFIG_TRACE_PREEMPT_TOGGLE ) )
/ *
* If the value passed in is equal to the current preempt count
* then we just disabled preemption . Start timing the latency .
* /
static inline void preempt_latency_start ( int val )
{
if ( preempt_count ( ) = = val ) {
unsigned long ip = get_lock_parent_ip ( ) ;
# ifdef CONFIG_DEBUG_PREEMPT
current - > preempt_disable_ip = ip ;
# endif
trace_preempt_off ( CALLER_ADDR0 , ip ) ;
}
}
void preempt_count_add ( int val )
{
# ifdef CONFIG_DEBUG_PREEMPT
/ *
* Underflow ?
* /
if ( DEBUG_LOCKS_WARN_ON ( ( preempt_count ( ) < 0 ) ) )
return ;
# endif
_ _ preempt_count_add ( val ) ;
# ifdef CONFIG_DEBUG_PREEMPT
/ *
* Spinlock count overflowing soon ?
* /
DEBUG_LOCKS_WARN_ON ( ( preempt_count ( ) & PREEMPT_MASK ) > =
PREEMPT_MASK - 10 ) ;
# endif
preempt_latency_start ( val ) ;
}
EXPORT_SYMBOL ( preempt_count_add ) ;
NOKPROBE_SYMBOL ( preempt_count_add ) ;
/ *
* If the value passed in equals to the current preempt count
* then we just enabled preemption . Stop timing the latency .
* /
static inline void preempt_latency_stop ( int val )
{
if ( preempt_count ( ) = = val )
trace_preempt_on ( CALLER_ADDR0 , get_lock_parent_ip ( ) ) ;
}
void preempt_count_sub ( int val )
{
# ifdef CONFIG_DEBUG_PREEMPT
/ *
* Underflow ?
* /
if ( DEBUG_LOCKS_WARN_ON ( val > preempt_count ( ) ) )
return ;
/ *
* Is the spinlock portion underflowing ?
* /
if ( DEBUG_LOCKS_WARN_ON ( ( val < PREEMPT_MASK ) & &
! ( preempt_count ( ) & PREEMPT_MASK ) ) )
return ;
# endif
preempt_latency_stop ( val ) ;
_ _ preempt_count_sub ( val ) ;
}
EXPORT_SYMBOL ( preempt_count_sub ) ;
NOKPROBE_SYMBOL ( preempt_count_sub ) ;
# else
static inline void preempt_latency_start ( int val ) { }
static inline void preempt_latency_stop ( int val ) { }
# endif
static inline unsigned long get_preempt_disable_ip ( struct task_struct * p )
{
# ifdef CONFIG_DEBUG_PREEMPT
return p - > preempt_disable_ip ;
# else
return 0 ;
# endif
}
/ *
* Print scheduling while atomic bug :
* /
static noinline void _ _ schedule_bug ( struct task_struct * prev )
{
/ * Save this before calling printk ( ) , since that will clobber it * /
unsigned long preempt_disable_ip = get_preempt_disable_ip ( current ) ;
if ( oops_in_progress )
return ;
printk ( KERN_ERR " BUG : scheduling while atomic : % s / % d / 0 x % 08 x \ n " ,
prev - > comm , prev - > pid , preempt_count ( ) ) ;
debug_show_held_locks ( prev ) ;
print_modules ( ) ;
if ( irqs_disabled ( ) )
print_irqtrace_events ( prev ) ;
if ( IS_ENABLED ( CONFIG_DEBUG_PREEMPT ) ) {
pr_err ( " Preemption disabled at : " ) ;
print_ip_sym ( KERN_ERR , preempt_disable_ip ) ;
}
check_panic_on_warn ( " scheduling while atomic " ) ;
dump_stack ( ) ;
add_taint ( TAINT_WARN , LOCKDEP_STILL_OK ) ;
}
/ *
* Various schedule ( ) - time debugging checks and statistics :
* /
static inline void schedule_debug ( struct task_struct * prev , bool preempt )
{
# ifdef CONFIG_SCHED_STACK_END_CHECK
if ( task_stack_end_corrupted ( prev ) )
panic ( " corrupted stack end detected inside scheduler \ n " ) ;
if ( task_scs_end_corrupted ( prev ) )
panic ( " corrupted shadow stack detected inside scheduler \ n " ) ;
# endif
# ifdef CONFIG_DEBUG_ATOMIC_SLEEP
if ( ! preempt & & READ_ONCE ( prev - > _ _ state ) & & prev - > non_block_count ) {
printk ( KERN_ERR " BUG : scheduling in a non - blocking section : % s / % d / % i \ n " ,
prev - > comm , prev - > pid , prev - > non_block_count ) ;
dump_stack ( ) ;
add_taint ( TAINT_WARN , LOCKDEP_STILL_OK ) ;
}
# endif
if ( unlikely ( in_atomic_preempt_off ( ) ) ) {
_ _ schedule_bug ( prev ) ;
preempt_count_set ( PREEMPT_DISABLED ) ;
}
rcu_sleep_check ( ) ;
WARN_ON_ONCE ( ct_state ( ) = = CT_STATE_USER ) ;
profile_hit ( SCHED_PROFILING , _ _ builtin_return_address ( 0 ) ) ;
schedstat_inc ( this_rq ( ) - > sched_count ) ;
}
static void prev_balance ( struct rq * rq , struct task_struct * prev ,
struct rq_flags * rf )
{
const struct sched_class * start_class = prev - > sched_class ;
const struct sched_class * class ;
# ifdef CONFIG_SCHED_CLASS_EXT
/ *
* SCX requires a balance ( ) call before every pick_task ( ) including when
* waking up from SCHED_IDLE . If @ start_class is below SCX , start from
* SCX instead . Also , set a flag to detect missing balance ( ) call .
* /
if ( scx_enabled ( ) ) {
rq - > scx . flags | = SCX_RQ_BAL_PENDING ;
if ( sched_class_above ( & ext_sched_class , start_class ) )
start_class = & ext_sched_class ;
}
# endif
/ *
* We must do the balancing pass before put_prev_task ( ) , such
* that when we release the rq - > lock the task is in the same
* state as before we took rq - > lock .
*
* We can terminate the balance pass as soon as we know there is
* a runnable task of @ class priority or higher .
* /
for_active_class_range ( class , start_class , & idle_sched_class ) {
if ( class - > balance & & class - > balance ( rq , prev , rf ) )
break ;
}
}
/ *
* Pick up the highest - prio task :
* /
static inline struct task_struct *
_ _ pick_next_task ( struct rq * rq , struct task_struct * prev , struct rq_flags * rf )
{
const struct sched_class * class ;
struct task_struct * p ;
rq - > dl_server = NULL ;
if ( scx_enabled ( ) )
goto restart ;
/ *
* Optimization : we know that if all tasks are in the fair class we can
* call that function directly , but only if the @ prev task wasn ' t of a
* higher scheduling class , because otherwise those lose the
* opportunity to pull in more work from other CPUs .
* /
if ( likely ( ! sched_class_above ( prev - > sched_class , & fair_sched_class ) & & >
rq - > nr_running = = rq - > cfs . h_nr_queued ) ) {
p = pick_next_task_fair ( rq , prev , rf ) ;
if ( unlikely ( p = = RETRY_TASK ) )
goto restart ;
/ * Assume the next prioritized class is idle_sched_class * /
if ( ! p ) {
p = pick_task_idle ( rq ) ;
put_prev_set_next_task ( rq , prev , p ) ;
}
return p ;
}
restart :
prev_balance ( rq , prev , rf ) ;
for_each_active_class ( class ) {
if ( class - > pick_next_task ) {
p = class - > pick_next_task ( rq , prev ) ;
if ( p )
return p ;
} else {
p = class - > pick_task ( rq ) ;
if ( p ) {
put_prev_set_next_task ( rq , prev , p ) ;
return p ;
}
}
}
BUG ( ) ; / * The idle class should always have a runnable task . * /
}
# ifdef CONFIG_SCHED_CORE
static inline bool is_task_rq_idle ( struct task_struct * t )
{
return ( task_rq ( t ) - > idle = = t ) ;
}
static inline bool cookie_equals ( struct task_struct * a , unsigned long cookie )
{
return is_task_rq_idle ( a ) | | ( a - > core_cookie = = cookie ) ;
}
static inline bool cookie_match ( struct task_struct * a , struct task_struct * b )
{
if ( is_task_rq_idle ( a ) | | is_task_rq_idle ( b ) )
return true ;
return a - > core_cookie = = b - > core_cookie ;
}
static inline struct task_struct * pick_task ( struct rq * rq )
{
const struct sched_class * class ;
struct task_struct * p ;
rq - > dl_server = NULL ;
for_each_active_class ( class ) {
p = class - > pick_task ( rq ) ;
if ( p )
return p ;
}
BUG ( ) ; / * The idle class should always have a runnable task . * /
}
extern void task_vruntime_update ( struct rq * rq , struct task_struct * p , bool in_fi ) ;
static void queue_core_balance ( struct rq * rq ) ;
static struct task_struct *
pick_next_task ( struct rq * rq , struct task_struct * prev , struct rq_flags * rf )
{
struct task_struct * next , * p , * max = NULL ;
const struct cpumask * smt_mask ;
bool fi_before = false ;
bool core_clock_updated = ( rq = = rq - > core ) ;
unsigned long cookie ;
int i , cpu , occ = 0 ;
struct rq * rq_i ;
bool need_sync ;
if ( ! sched_core_enabled ( rq ) )
return _ _ pick_next_task ( rq , prev , rf ) ;
cpu = cpu_of ( rq ) ;
/ * Stopper task is switching into idle , no need core - wide selection . * /
if ( cpu_is_offline ( cpu ) ) {
/ *
* Reset core_pick so that we don ' t enter the fastpath when
* coming online . core_pick would already be migrated to
* another cpu during offline .
* /
rq - > core_pick = NULL ;
rq - > core_dl_server = NULL ;
return _ _ pick_next_task ( rq , prev , rf ) ;
}
/ *
* If there were no { en , de } queues since we picked ( IOW , the task
* pointers are all still valid ) , and we haven ' t scheduled the last
* pick yet , do so now .
*
* rq - > core_pick can be NULL if no selection was made for a CPU because
* it was either offline or went offline during a sibling ' s core - wide
* selection . In this case , do a core - wide selection .
* /
if ( rq - > core - > core_pick_seq = = rq - > core - > core_task_seq & &
rq - > core - > core_pick_seq ! = rq - > core_sched_seq & &
rq - > core_pick ) {
WRITE_ONCE ( rq - > core_sched_seq , rq - > core - > core_pick_seq ) ;
next = rq - > core_pick ;
rq - > dl_server = rq - > core_dl_server ;
rq - > core_pick = NULL ;
rq - > core_dl_server = NULL ;
goto out_set_next ;
}
prev_balance ( rq , prev , rf ) ;
smt_mask = cpu_smt_mask ( cpu ) ;
need_sync = ! ! rq - > core - > core_cookie ;
/ * reset state * /
rq - > core - > core_cookie = 0 UL ;
if ( rq - > core - > core_forceidle_count ) {
if ( ! core_clock_updated ) {
update_rq_clock ( rq - > core ) ;
core_clock_updated = true ;
}
sched_core_account_forceidle ( rq ) ;
/ * reset after accounting force idle * /
rq - > core - > core_forceidle_start = 0 ;
rq - > core - > core_forceidle_count = 0 ;
rq - > core - > core_forceidle_occupation = 0 ;
need_sync = true ;
fi_before = true ;
}
/ *
* core - > core_task_seq , core - > core_pick_seq , rq - > core_sched_seq
*
* @ task_seq guards the task state ( { en , de } queues )
* @ pick_seq is the @ task_seq we did a selection on
* @ sched_seq is the @ pick_seq we scheduled
*
* However , preemptions can cause multiple picks on the same task set .
* ' Fix ' this by also increasing @ task_seq for every pick .
* /
rq - > core - > core_task_seq + + ;
/ *
* Optimize for common case where this CPU has no cookies
* and there are no cookied tasks running on siblings .
* /
if ( ! need_sync ) {
next = pick_task ( rq ) ;
if ( ! next - > core_cookie ) {
rq - > core_pick = NULL ;
rq - > core_dl_server = NULL ;
/ *
* For robustness , update the min_vruntime_fi for
* unconstrained picks as well .
* /
WARN_ON_ONCE ( fi_before ) ;
task_vruntime_update ( rq , next , false ) ;
goto out_set_next ;
}
}
/ *
* For each thread : do the regular task pick and find the max prio task
* amongst them .
*
* Tie - break prio towards the current CPU
* /
for_each_cpu_wrap ( i , smt_mask , cpu ) {
rq_i = cpu_rq ( i ) ;
/ *
* Current cpu always has its clock updated on entrance to
* pick_next_task ( ) . If the current cpu is not the core ,
* the core may also have been updated above .
* /
if ( i ! = cpu & & ( rq_i ! = rq - > core | | ! core_clock_updated ) )
update_rq_clock ( rq_i ) ;
rq_i - > core_pick = p = pick_task ( rq_i ) ;
rq_i - > core_dl_server = rq_i - > dl_server ;
if ( ! max | | prio_less ( max , p , fi_before ) )
max = p ;
}
cookie = rq - > core - > core_cookie = max - > core_cookie ;
/ *
* For each thread : try and find a runnable task that matches @ max or
* force idle .
* /
for_each_cpu ( i , smt_mask ) {
rq_i = cpu_rq ( i ) ;
p = rq_i - > core_pick ;
if ( ! cookie_equals ( p , cookie ) ) {
p = NULL ;
if ( cookie )
p = sched_core_find ( rq_i , cookie ) ;
if ( ! p )
p = idle_sched_class . pick_task ( rq_i ) ;
}
rq_i - > core_pick = p ;
rq_i - > core_dl_server = NULL ;
if ( p = = rq_i - > idle ) {
if ( rq_i - > nr_running ) {
rq - > core - > core_forceidle_count + + ;
if ( ! fi_before )
rq - > core - > core_forceidle_seq + + ;
}
} else {
occ + + ;
}
}
if ( schedstat_enabled ( ) & & rq - > core - > core_forceidle_count ) {
rq - > core - > core_forceidle_start = rq_clock ( rq - > core ) ;
rq - > core - > core_forceidle_occupation = occ ;
}
rq - > core - > core_pick_seq = rq - > core - > core_task_seq ;
next = rq - > core_pick ;
rq - > core_sched_seq = rq - > core - > core_pick_seq ;
/ * Something should have been selected for current CPU * /
WARN_ON_ONCE ( ! next ) ;
/ *
* Reschedule siblings
*
* NOTE : L1TF - - at this point we ' re no longer running the old task and
* sending an IPI ( below ) ensures the sibling will no longer be running
* their task . This ensures there is no inter - sibling overlap between
* non - matching user state .
* /
for_each_cpu ( i , smt_mask ) {
rq_i = cpu_rq ( i ) ;
/ *
* An online sibling might have gone offline before a task
* could be picked for it , or it might be offline but later
* happen to come online , but its too late and nothing was
* picked for it . That ' s Ok - it will pick tasks for itself ,
* so ignore it .
* /
if ( ! rq_i - > core_pick )
continue ;
/ *
* Update for new ! FI - > FI transitions , or if continuing to be in ! FI :
* fi_before fi update ?
* 0 0 1
* 0 1 1
* 1 0 1
* 1 1 0
* /
if ( ! ( fi_before & & rq - > core - > core_forceidle_count ) )
task_vruntime_update ( rq_i , rq_i - > core_pick , ! ! rq - > core - > core_forceidle_count ) ;
rq_i - > core_pick - > core_occupation = occ ;
if ( i = = cpu ) {
rq_i - > core_pick = NULL ;
rq_i - > core_dl_server = NULL ;
continue ;
}
/ * Did we break L1TF mitigation requirements ? * /
WARN_ON_ONCE ( ! cookie_match ( next , rq_i - > core_pick ) ) ;
if ( rq_i - > curr = = rq_i - > core_pick ) {
rq_i - > core_pick = NULL ;
rq_i - > core_dl_server = NULL ;
continue ;
}
resched_curr ( rq_i ) ;
}
out_set_next :
put_prev_set_next_task ( rq , prev , next ) ;
if ( rq - > core - > core_forceidle_count & & next = = rq - > idle )
queue_core_balance ( rq ) ;
return next ;
}
static bool try_steal_cookie ( int this , int that )
{
struct rq * dst = cpu_rq ( this ) , * src = cpu_rq ( that ) ;
struct task_struct * p ;
unsigned long cookie ;
bool success = false ;
guard ( irq ) ( ) ;
guard ( double_rq_lock ) ( dst , src ) ;
cookie = dst - > core - > core_cookie ;
if ( ! cookie )
return false ;
if ( dst - > curr ! = dst - > idle )
return false ;
p = sched_core_find ( src , cookie ) ;
if ( ! p )
return false ;
do {
if ( p = = src - > core_pick | | p = = src - > curr )
goto next ;
if ( ! is_cpu_allowed ( p , this ) )
goto next ;
if ( p - > core_occupation > dst - > idle - > core_occupation )
goto next ;
/ *
* sched_core_find ( ) and sched_core_next ( ) will ensure
* that task @ p is not throttled now , we also need to
* check whether the runqueue of the destination CPU is
* being throttled .
* /
if ( sched_task_is_throttled ( p , this ) )
goto next ;
move_queued_task_locked ( src , dst , p ) ;
resched_curr ( dst ) ;
success = true ;
break ;
next :
p = sched_core_next ( p , cookie ) ;
} while ( p ) ;
return success ;
}
static bool steal_cookie_task ( int cpu , struct sched_domain * sd )
{
int i ;
for_each_cpu_wrap ( i , sched_domain_span ( sd ) , cpu + 1 ) {
if ( i = = cpu )
continue ;
if ( need_resched ( ) )
break ;
if ( try_steal_cookie ( cpu , i ) )
return true ;
}
return false ;
}
static void sched_core_balance ( struct rq * rq )
{
struct sched_domain * sd ;
int cpu = cpu_of ( rq ) ;
guard ( preempt ) ( ) ;
guard ( rcu ) ( ) ;
raw_spin_rq_unlock_irq ( rq ) ;
for_each_domain ( cpu , sd ) {
if ( need_resched ( ) )
break ;
if ( steal_cookie_task ( cpu , sd ) )
break ;
}
raw_spin_rq_lock_irq ( rq ) ;
}
static DEFINE_PER_CPU ( struct balance_callback , core_balance_head ) ;
static void queue_core_balance ( struct rq * rq )
{
if ( ! sched_core_enabled ( rq ) )
return ;
if ( ! rq - > core - > core_cookie )
return ;
if ( ! rq - > nr_running ) / * not forced idle * /
return ;
queue_balance_callback ( rq , & per_cpu ( core_balance_head , rq - > cpu ) , sched_core_balance ) ;
}
DEFINE_LOCK_GUARD_1 ( core_lock , int ,
sched_core_lock ( * _ T - > lock , & _ T - > flags ) ,
sched_core_unlock ( * _ T - > lock , & _ T - > flags ) ,
unsigned long flags )
static void sched_core_cpu_starting ( unsigned int cpu )
{
const struct cpumask * smt_mask = cpu_smt_mask ( cpu ) ;
struct rq * rq = cpu_rq ( cpu ) , * core_rq = NULL ;
int t ;
guard ( core_lock ) ( & cpu ) ;
WARN_ON_ONCE ( rq - > core ! = rq ) ;
/ * if we ' re the first , we ' ll be our own leader * /
if ( cpumask_weight ( smt_mask ) = = 1 )
return ;
/ * find the leader * /
for_each_cpu ( t , smt_mask ) {
if ( t = = cpu )
continue ;
rq = cpu_rq ( t ) ;
if ( rq - > core = = rq ) {
core_rq = rq ;
break ;
}
}
if ( WARN_ON_ONCE ( ! core_rq ) ) / * whoopsie * /
return ;
/ * install and validate core_rq * /
for_each_cpu ( t , smt_mask ) {
rq = cpu_rq ( t ) ;
if ( t = = cpu )
rq - > core = core_rq ;
WARN_ON_ONCE ( rq - > core ! = core_rq ) ;
}
}
static void sched_core_cpu_deactivate ( unsigned int cpu )
{
const struct cpumask * smt_mask = cpu_smt_mask ( cpu ) ;
struct rq * rq = cpu_rq ( cpu ) , * core_rq = NULL ;
int t ;
guard ( core_lock ) ( & cpu ) ;
/ * if we ' re the last man standing , nothing to do * /
if ( cpumask_weight ( smt_mask ) = = 1 ) {
WARN_ON_ONCE ( rq - > core ! = rq ) ;
return ;
}
/ * if we ' re not the leader , nothing to do * /
if ( rq - > core ! = rq )
return ;
/ * find a new leader * /
for_each_cpu ( t , smt_mask ) {
if ( t = = cpu )
continue ;
core_rq = cpu_rq ( t ) ;
break ;
}
if ( WARN_ON_ONCE ( ! core_rq ) ) / * impossible * /
return ;
/ * copy the shared state to the new leader * /
core_rq - > core_task_seq = rq - > core_task_seq ;
core_rq - > core_pick_seq = rq - > core_pick_seq ;
core_rq - > core_cookie = rq - > core_cookie ;
core_rq - > core_forceidle_count = rq - > core_forceidle_count ;
core_rq - > core_forceidle_seq = rq - > core_forceidle_seq ;
core_rq - > core_forceidle_occupation = rq - > core_forceidle_occupation ;
/ *
* Accounting edge for forced idle is handled in pick_next_task ( ) .
* Don ' t need another one here , since the hotplug thread shouldn ' t
* have a cookie .
* /
core_rq - > core_forceidle_start = 0 ;
/ * install new leader * /
for_each_cpu ( t , smt_mask ) {
rq = cpu_rq ( t ) ;
rq - > core = core_rq ;
}
}
static inline void sched_core_cpu_dying ( unsigned int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
if ( rq - > core ! = rq )
rq - > core = rq ;
}
# else / * ! CONFIG_SCHED_CORE : * /
static inline void sched_core_cpu_starting ( unsigned int cpu ) { }
static inline void sched_core_cpu_deactivate ( unsigned int cpu ) { }
static inline void sched_core_cpu_dying ( unsigned int cpu ) { }
static struct task_struct *
pick_next_task ( struct rq * rq , struct task_struct * prev , struct rq_flags * rf )
{
return _ _ pick_next_task ( rq , prev , rf ) ;
}
# endif / * ! CONFIG_SCHED_CORE * /
/ *
* Constants for the sched_mode argument of _ _ schedule ( ) .
*
* The mode argument allows RT enabled kernels to differentiate a
* preemption from blocking on an ' sleeping ' spin / rwlock .
* /
# define SM_IDLE ( - 1 )
# define SM_NONE 0
# define SM_PREEMPT 1
# define SM_RTLOCK_WAIT 2
/ *
* Helper function for _ _ schedule ( )
*
* Tries to deactivate the task , unless the should_block arg
* is false or if a signal is pending . In the case a signal
* is pending , marks the task ' s _ _ state as RUNNING ( and clear
* blocked_on ) .
* /
static bool try_to_block_task ( struct rq * rq , struct task_struct * p ,
unsigned long * task_state_p , bool should_block )
{
unsigned long task_state = * task_state_p ;
int flags = DEQUEUE_NOCLOCK ;
if ( signal_pending_state ( task_state , p ) ) {
WRITE_ONCE ( p - > _ _ state , TASK_RUNNING ) ;
* task_state_p = TASK_RUNNING ;
return false ;
}
/ *
* We check should_block after signal_pending because we
* will want to wake the task in that case . But if
* should_block is false , its likely due to the task being
* blocked on a mutex , and we want to keep it on the runqueue
* to be selectable for proxy - execution .
* /
if ( ! should_block )
return false ;
p - > sched_contributes_to_load =
( task_state & TASK_UNINTERRUPTIBLE ) & &
! ( task_state & TASK_NOLOAD ) & &
! ( task_state & TASK_FROZEN ) ;
if ( unlikely ( is_special_task_state ( task_state ) ) )
flags | = DEQUEUE_SPECIAL ;
/ *
* _ _ schedule ( ) ttwu ( )
* prev_state = prev - > state ; if ( p - > on_rq & & . . . )
* if ( prev_state ) goto out ;
* p - > on_rq = 0 ; smp_acquire__after_ctrl_dep ( ) ;
* p - > state = TASK_WAKING
*
* Where _ _ schedule ( ) and ttwu ( ) have matching control dependencies .
*
* After this , schedule ( ) must not care about p - > state any more .
* /
block_task ( rq , p , flags ) ;
return true ;
}
# ifdef CONFIG_SCHED_PROXY_EXEC
static inline struct task_struct * proxy_resched_idle ( struct rq * rq )
{
put_prev_set_next_task ( rq , rq - > donor , rq - > idle ) ;
rq_set_donor ( rq , rq - > idle ) ;
set_tsk_need_resched ( rq - > idle ) ;
return rq - > idle ;
}
static bool _ _ proxy_deactivate ( struct rq * rq , struct task_struct * donor )
{
unsigned long state = READ_ONCE ( donor - > _ _ state ) ;
/ * Don ' t deactivate if the state has been changed to TASK_RUNNING * /
if ( state = = TASK_RUNNING )
return false ;
/ *
* Because we got donor from pick_next_task ( ) , it is * crucial *
* that we call proxy_resched_idle ( ) before we deactivate it .
* As once we deactivate donor , donor - > on_rq is set to zero ,
* which allows ttwu ( ) to immediately try to wake the task on
* another rq . So we cannot use * any * references to donor
* after that point . So things like cfs_rq - > curr or rq - > donor
* need to be changed from next * before * we deactivate .
* /
proxy_resched_idle ( rq ) ;
return try_to_block_task ( rq , donor , & state , true ) ;
}
static struct task_struct * proxy_deactivate ( struct rq * rq , struct task_struct * donor )
{
if ( ! _ _ proxy_deactivate ( rq , donor ) ) {
/ *
* XXX : For now , if deactivation failed , set donor
* as unblocked , as we aren ' t doing proxy - migrations
* yet ( more logic will be needed then ) .
* /
donor - > blocked_on = NULL ;
}
return NULL ;
}
/ *
* Find runnable lock owner to proxy for mutex blocked donor
*
* Follow the blocked - on relation :
* task - > blocked_on - > mutex - > owner - > task . . .
*
* Lock order :
*
* p - > pi_lock
* rq - > lock
* mutex - > wait_lock
*
* Returns the task that is going to be used as execution context ( the one
* that is actually going to be run on cpu_of ( rq ) ) .
* /
static struct task_struct *
find_proxy_task ( struct rq * rq , struct task_struct * donor , struct rq_flags * rf )
{
struct task_struct * owner = NULL ;
int this_cpu = cpu_of ( rq ) ;
struct task_struct * p ;
struct mutex * mutex ;
/ * Follow blocked_on chain . * /
for ( p = donor ; task_is_blocked ( p ) ; p = owner ) {
mutex = p - > blocked_on ;
/ * Something changed in the chain , so pick again * /
if ( ! mutex )
return NULL ;
/ *
* By taking mutex - > wait_lock we hold off concurrent mutex_unlock ( )
* and ensure @ owner sticks around .
* /
guard ( raw_spinlock ) ( & mutex - > wait_lock ) ;
/ * Check again that p is blocked with wait_lock held * /
if ( mutex ! = _ _ get_task_blocked_on ( p ) ) {
/ *
* Something changed in the blocked_on chain and
* we don ' t know if only at this level . So , let ' s
* just bail out completely and let _ _ schedule ( )
* figure things out ( pick_again loop ) .
* /
return NULL ;
}
owner = _ _ mutex_owner ( mutex ) ;
if ( ! owner ) {
_ _ clear_task_blocked_on ( p , mutex ) ;
return p ;
}
if ( ! READ_ONCE ( owner - > on_rq ) | | owner - > se . sched_delayed ) {
/ * XXX Don ' t handle blocked owners / delayed dequeue yet * /
return proxy_deactivate ( rq , donor ) ;
}
if ( task_cpu ( owner ) ! = this_cpu ) {
/ * XXX Don ' t handle migrations yet * /
return proxy_deactivate ( rq , donor ) ;
}
if ( task_on_rq_migrating ( owner ) ) {
/ *
* One of the chain of mutex owners is currently migrating to this
* CPU , but has not yet been enqueued because we are holding the
* rq lock . As a simple solution , just schedule rq - > idle to give
* the migration a chance to complete . Much like the migrate_task
* case we should end up back in find_proxy_task ( ) , this time
* hopefully with all relevant tasks already enqueued .
* /
return proxy_resched_idle ( rq ) ;
}
/ *
* Its possible to race where after we check owner - > on_rq
* but before we check ( owner_cpu ! = this_cpu ) that the
* task on another cpu was migrated back to this cpu . In
* that case it could slip by our checks . So double check
* we are still on this cpu and not migrating . If we get
* inconsistent results , try again .
* /
if ( ! task_on_rq_queued ( owner ) | | task_cpu ( owner ) ! = this_cpu )
return NULL ;
if ( owner = = p ) {
/ *
* It ' s possible we interleave with mutex_unlock like :
*
* lock ( & rq - > lock ) ;
* find_proxy_task ( )
* mutex_unlock ( )
* lock ( & wait_lock ) ;
* donor ( owner ) = current - > blocked_donor ;
* unlock ( & wait_lock ) ;
*
* wake_up_q ( ) ;
* . . .
* ttwu_runnable ( )
* _ _ task_rq_lock ( )
* lock ( & wait_lock ) ;
* owner = = p
*
* Which leaves us to finish the ttwu_runnable ( ) and make it go .
*
* So schedule rq - > idle so that ttwu_runnable ( ) can get the rq
* lock and mark owner as running .
* /
return proxy_resched_idle ( rq ) ;
}
/ *
* OK , now we ' re absolutely sure @ owner is on this
* rq , therefore holding @ rq - > lock is sufficient to
* guarantee its existence , as per ttwu_remote ( ) .
* /
}
WARN_ON_ONCE ( owner & & ! owner - > on_rq ) ;
return owner ;
}
# else / * SCHED_PROXY_EXEC * /
static struct task_struct *
find_proxy_task ( struct rq * rq , struct task_struct * donor , struct rq_flags * rf )
{
WARN_ONCE ( 1 , " This should never be called in the ! SCHED_PROXY_EXEC case \ n " ) ;
return donor ;
}
# endif / * SCHED_PROXY_EXEC * /
static inline void proxy_tag_curr ( struct rq * rq , struct task_struct * owner )
{
if ( ! sched_proxy_exec ( ) )
return ;
/ *
* pick_next_task ( ) calls set_next_task ( ) on the chosen task
* at some point , which ensures it is not push / pullable .
* However , the chosen / donor task * and * the mutex owner form an
* atomic pair wrt push / pull .
*
* Make sure owner we run is not pushable . Unfortunately we can
* only deal with that by means of a dequeue / enqueue cycle . : - /
* /
dequeue_task ( rq , owner , DEQUEUE_NOCLOCK | DEQUEUE_SAVE ) ;
enqueue_task ( rq , owner , ENQUEUE_NOCLOCK | ENQUEUE_RESTORE ) ;
}
/ *
* _ _ schedule ( ) is the main scheduler function .
*
* The main means of driving the scheduler and thus entering this function are :
*
* 1 . Explicit blocking : mutex , semaphore , waitqueue , etc .
*
* 2 . TIF_NEED_RESCHED flag is checked on interrupt and userspace return
* paths . For example , see arch / x86 / entry_64 . S .
*
* To drive preemption between tasks , the scheduler sets the flag in timer
* interrupt handler sched_tick ( ) .
*
* 3 . Wakeups don ' t really cause entry into schedule ( ) . They add a
* task to the run - queue and that ' s it .
*
* Now , if the new task added to the run - queue preempts the current
* task , then the wakeup sets TIF_NEED_RESCHED and schedule ( ) gets
* called on the nearest possible occasion :
*
* - If the kernel is preemptible ( CONFIG_PREEMPTION = y ) :
*
* - in syscall or exception context , at the next outmost
* preempt_enable ( ) . ( this might be as soon as the wake_up ( ) ' s
* spin_unlock ( ) ! )
*
* - in IRQ context , return from interrupt - handler to
* preemptible context
*
* - If the kernel is not preemptible ( CONFIG_PREEMPTION is not set )
* then at the next :
*
* - cond_resched ( ) call
* - explicit schedule ( ) call
* - return from syscall or exception to user - space
* - return from interrupt - handler to user - space
*
* WARNING : must be called with preemption disabled !
* /
static void _ _ sched notrace _ _ schedule ( int sched_mode )
{
struct task_struct * prev , * next ;
/ *
* On PREEMPT_RT kernel , SM_RTLOCK_WAIT is noted
* as a preemption by schedule_debug ( ) and RCU .
* /
bool preempt = sched_mode > SM_NONE ;
bool is_switch = false ;
unsigned long * switch_count ;
unsigned long prev_state ;
struct rq_flags rf ;
struct rq * rq ;
int cpu ;
/ * Trace preemptions consistently with task switches * /
trace_sched_entry_tp ( sched_mode = = SM_PREEMPT ) ;
cpu = smp_processor_id ( ) ;
rq = cpu_rq ( cpu ) ;
prev = rq - > curr ;
schedule_debug ( prev , preempt ) ;
if ( sched_feat ( HRTICK ) | | sched_feat ( HRTICK_DL ) )
hrtick_clear ( rq ) ;
klp_sched_try_switch ( prev ) ;
local_irq_disable ( ) ;
rcu_note_context_switch ( preempt ) ;
/ *
* Make sure that signal_pending_state ( ) - > signal_pending ( ) below
* can ' t be reordered with _ _ set_current_state ( TASK_INTERRUPTIBLE )
* done by the caller to avoid the race with signal_wake_up ( ) :
*
* _ _ set_current_state ( @ state ) signal_wake_up ( )
* schedule ( ) set_tsk_thread_flag ( p , TIF_SIGPENDING )
* wake_up_state ( p , state )
* LOCK rq - > lock LOCK p - > pi_state
* smp_mb__after_spinlock ( ) smp_mb__after_spinlock ( )
* if ( signal_pending_state ( ) ) if ( p - > state & @ state )
*
* Also , the membarrier system call requires a full memory barrier
* after coming from user - space , before storing to rq - > curr ; this
* barrier matches a full barrier in the proximity of the membarrier
* system call exit .
* /
rq_lock ( rq , & rf ) ;
smp_mb__after_spinlock ( ) ;
/ * Promote REQ to ACT * /
rq - > clock_update_flags < < = 1 ;
update_rq_clock ( rq ) ;
rq - > clock_update_flags = RQCF_UPDATED ;
switch_count = & prev - > nivcsw ;
/ * Task state changes only considers SM_PREEMPT as preemption * /
preempt = sched_mode = = SM_PREEMPT ;
/ *
* We must load prev - > state once ( task_struct : : state is volatile ) , such
* that we form a control dependency vs deactivate_task ( ) below .
* /
prev_state = READ_ONCE ( prev - > _ _ state ) ;
if ( sched_mode = = SM_IDLE ) {
/ * SCX must consult the BPF scheduler to tell if rq is empty * /
if ( ! rq - > nr_running & & ! scx_enabled ( ) ) {
next = prev ;
goto picked ;
}
} else if ( ! preempt & & prev_state ) {
/ *
* We pass task_is_blocked ( ) as the should_block arg
* in order to keep mutex - blocked tasks on the runqueue
* for slection with proxy - exec ( without proxy - exec
* task_is_blocked ( ) will always be false ) .
* /
try_to_block_task ( rq , prev , & prev_state ,
! task_is_blocked ( prev ) ) ;
switch_count = & prev - > nvcsw ;
}
pick_again :
next = pick_next_task ( rq , rq - > donor , & rf ) ;
rq_set_donor ( rq , next ) ;
if ( unlikely ( task_is_blocked ( next ) ) ) {
next = find_proxy_task ( rq , next , & rf ) ;
if ( ! next )
goto pick_again ;
if ( next = = rq - > idle )
goto keep_resched ;
}
picked :
clear_tsk_need_resched ( prev ) ;
clear_preempt_need_resched ( ) ;
keep_resched :
rq - > last_seen_need_resched_ns = 0 ;
is_switch = prev ! = next ;
if ( likely ( is_switch ) ) {
rq - > nr_switches + + ;
/ *
* RCU users of rcu_dereference ( rq - > curr ) may not see
* changes to task_struct made by pick_next_task ( ) .
* /
RCU_INIT_POINTER ( rq - > curr , next ) ;
if ( ! task_current_donor ( rq , next ) )
proxy_tag_curr ( rq , next ) ;
/ *
* The membarrier system call requires each architecture
* to have a full memory barrier after updating
* rq - > curr , before returning to user - space .
*
* Here are the schemes providing that barrier on the
* various architectures :
* - mm ? switch_mm ( ) : mmdrop ( ) for x86 , s390 , sparc , PowerPC ,
* RISC - V . switch_mm ( ) relies on membarrier_arch_switch_mm ( )
* on PowerPC and on RISC - V .
* - finish_lock_switch ( ) for weakly - ordered
* architectures where spin_unlock is a full barrier ,
* - switch_to ( ) for arm64 ( weakly - ordered , spin_unlock
* is a RELEASE barrier ) ,
*
* The barrier matches a full barrier in the proximity of
* the membarrier system call entry .
*
* On RISC - V , this barrier pairing is also needed for the
* SYNC_CORE command when switching between processes , cf .
* the inline comments in membarrier_arch_switch_mm ( ) .
* /
+ + * switch_count ;
migrate_disable_switch ( rq , prev ) ;
psi_account_irqtime ( rq , prev , next ) ;
psi_sched_switch ( prev , next , ! task_on_rq_queued ( prev ) | |
prev - > se . sched_delayed ) ;
trace_sched_switch ( preempt , prev , next , prev_state ) ;
/ * Also unlocks the rq : * /
rq = context_switch ( rq , prev , next , & rf ) ;
} else {
/ * In case next was already curr but just got blocked_donor * /
if ( ! task_current_donor ( rq , next ) )
proxy_tag_curr ( rq , next ) ;
rq_unpin_lock ( rq , & rf ) ;
_ _ balance_callbacks ( rq ) ;
raw_spin_rq_unlock_irq ( rq ) ;
}
trace_sched_exit_tp ( is_switch ) ;
}
void _ _ noreturn do_task_dead ( void )
{
/ * Causes final put_task_struct in finish_task_switch ( ) : * /
set_special_state ( TASK_DEAD ) ;
/ * Tell freezer to ignore us : * /
current - > flags | = PF_NOFREEZE ;
_ _ schedule ( SM_NONE ) ;
BUG ( ) ;
/ * Avoid " noreturn function does return " - but don ' t continue if BUG ( ) is a NOP : * /
for ( ; ; )
cpu_relax ( ) ;
}
static inline void sched_submit_work ( struct task_struct * tsk )
{
static DEFINE_WAIT_OVERRIDE_MAP ( sched_map , LD_WAIT_CONFIG ) ;
unsigned int task_flags ;
/ *
* Establish LD_WAIT_CONFIG context to ensure none of the code called
* will use a blocking primitive - - which would lead to recursion .
* /
lock_map_acquire_try ( & sched_map ) ;
task_flags = tsk - > flags ;
/ *
* If a worker goes to sleep , notify and ask workqueue whether it
* wants to wake up a task to maintain concurrency .
* /
if ( task_flags & PF_WQ_WORKER )
wq_worker_sleeping ( tsk ) ;
else if ( task_flags & PF_IO_WORKER )
io_wq_worker_sleeping ( tsk ) ;
/ *
* spinlock and rwlock must not flush block requests . This will
* deadlock if the callback attempts to acquire a lock which is
* already acquired .
* /
WARN_ON_ONCE ( current - > _ _ state & TASK_RTLOCK_WAIT ) ;
/ *
* If we are going to sleep and we have plugged IO queued ,
* make sure to submit it to avoid deadlocks .
* /
blk_flush_plug ( tsk - > plug , true ) ;
lock_map_release ( & sched_map ) ;
}
static void sched_update_worker ( struct task_struct * tsk )
{
if ( tsk - > flags & ( PF_WQ_WORKER | PF_IO_WORKER | PF_BLOCK_TS ) ) {
if ( tsk - > flags & PF_BLOCK_TS )
blk_plug_invalidate_ts ( tsk ) ;
if ( tsk - > flags & PF_WQ_WORKER )
wq_worker_running ( tsk ) ;
else if ( tsk - > flags & PF_IO_WORKER )
io_wq_worker_running ( tsk ) ;
}
}
static _ _ always_inline void _ _ schedule_loop ( int sched_mode )
{
do {
preempt_disable ( ) ;
_ _ schedule ( sched_mode ) ;
sched_preempt_enable_no_resched ( ) ;
} while ( need_resched ( ) ) ;
}
asmlinkage _ _ visible void _ _ sched schedule ( void )
{
struct task_struct * tsk = current ;
# ifdef CONFIG_RT_MUTEXES
lockdep_assert ( ! tsk - > sched_rt_mutex ) ;
# endif
if ( ! task_is_running ( tsk ) )
sched_submit_work ( tsk ) ;
_ _ schedule_loop ( SM_NONE ) ;
sched_update_worker ( tsk ) ;
}
EXPORT_SYMBOL ( schedule ) ;
/ *
* synchronize_rcu_tasks ( ) makes sure that no task is stuck in preempted
* state ( have scheduled out non - voluntarily ) by making sure that all
* tasks have either left the run queue or have gone into user space .
* As idle tasks do not do either , they must not ever be preempted
* ( schedule out non - voluntarily ) .
*
* schedule_idle ( ) is similar to schedule_preempt_disable ( ) except that it
* never enables preemption because it does not call sched_submit_work ( ) .
* /
void _ _ sched schedule_idle ( void )
{
/ *
* As this skips calling sched_submit_work ( ) , which the idle task does
* regardless because that function is a NOP when the task is in a
* TASK_RUNNING state , make sure this isn ' t used someplace that the
* current task can be in any other state . Note , idle is always in the
* TASK_RUNNING state .
* /
WARN_ON_ONCE ( current - > _ _ state ) ;
do {
_ _ schedule ( SM_IDLE ) ;
} while ( need_resched ( ) ) ;
}
# if defined ( CONFIG_CONTEXT_TRACKING_USER ) & & ! defined ( CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK )
asmlinkage _ _ visible void _ _ sched schedule_user ( void )
{
/ *
* If we come here after a random call to set_need_resched ( ) ,
* or we have been woken up remotely but the IPI has not yet arrived ,
* we haven ' t yet exited the RCU idle mode . Do it here manually until
* we find a better solution .
*
* NB : There are buggy callers of this function . Ideally we
* should warn if prev_state ! = CT_STATE_USER , but that will trigger
* too frequently to make sense yet .
* /
enum ctx_state prev_state = exception_enter ( ) ;
schedule ( ) ;
exception_exit ( prev_state ) ;
}
# endif
/ * *
* schedule_preempt_disabled - called with preemption disabled
*
* Returns with preemption disabled . Note : preempt_count must be 1
* /
void _ _ sched schedule_preempt_disabled ( void )
{
sched_preempt_enable_no_resched ( ) ;
schedule ( ) ;
preempt_disable ( ) ;
}
# ifdef CONFIG_PREEMPT_RT
void _ _ sched notrace schedule_rtlock ( void )
{
_ _ schedule_loop ( SM_RTLOCK_WAIT ) ;
}
NOKPROBE_SYMBOL ( schedule_rtlock ) ;
# endif
static void _ _ sched notrace preempt_schedule_common ( void )
{
do {
/ *
* Because the function tracer can trace preempt_count_sub ( )
* and it also uses preempt_enable / disable_notrace ( ) , if
* NEED_RESCHED is set , the preempt_enable_notrace ( ) called
* by the function tracer will call this function again and
* cause infinite recursion .
*
* Preemption must be disabled here before the function
* tracer can trace . Break up preempt_disable ( ) into two
* calls . One to disable preemption without fear of being
* traced . The other to still record the preemption latency ,
* which can also be traced by the function tracer .
* /
preempt_disable_notrace ( ) ;
preempt_latency_start ( 1 ) ;
_ _ schedule ( SM_PREEMPT ) ;
preempt_latency_stop ( 1 ) ;
preempt_enable_no_resched_notrace ( ) ;
/ *
* Check again in case we missed a preemption opportunity
* between schedule and now .
* /
} while ( need_resched ( ) ) ;
}
# ifdef CONFIG_PREEMPTION
/ *
* This is the entry point to schedule ( ) from in - kernel preemption
* off of preempt_enable .
* /
asmlinkage _ _ visible void _ _ sched notrace preempt_schedule ( void )
{
/ *
* If there is a non - zero preempt_count or interrupts are disabled ,
* we do not want to preempt the current task . Just return . .
* /
if ( likely ( ! preemptible ( ) ) )
return ;
preempt_schedule_common ( ) ;
}
NOKPROBE_SYMBOL ( preempt_schedule ) ;
EXPORT_SYMBOL ( preempt_schedule ) ;
# ifdef CONFIG_PREEMPT_DYNAMIC
# ifdef CONFIG_HAVE_PREEMPT_DYNAMIC_CALL
# ifndef preempt_schedule_dynamic_enabled
# define preempt_schedule_dynamic_enabled preempt_schedule
# define preempt_schedule_dynamic_disabled NULL
# endif
DEFINE_STATIC_CALL ( preempt_schedule , preempt_schedule_dynamic_enabled ) ;
EXPORT_STATIC_CALL_TRAMP ( preempt_schedule ) ;
# elif defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_KEY )
static DEFINE_STATIC_KEY_TRUE ( sk_dynamic_preempt_schedule ) ;
void _ _ sched notrace dynamic_preempt_schedule ( void )
{
if ( ! static_branch_unlikely ( & sk_dynamic_preempt_schedule ) )
return ;
preempt_schedule ( ) ;
}
NOKPROBE_SYMBOL ( dynamic_preempt_schedule ) ;
EXPORT_SYMBOL ( dynamic_preempt_schedule ) ;
# endif
# endif / * CONFIG_PREEMPT_DYNAMIC * /
/ * *
* preempt_schedule_notrace - preempt_schedule called by tracing
*
* The tracing infrastructure uses preempt_enable_notrace to prevent
* recursion and tracing preempt enabling caused by the tracing
* infrastructure itself . But as tracing can happen in areas coming
* from userspace or just about to enter userspace , a preempt enable
* can occur before user_exit ( ) is called . This will cause the scheduler
* to be called when the system is still in usermode .
*
* To prevent this , the preempt_enable_notrace will use this function
* instead of preempt_schedule ( ) to exit user context if needed before
* calling the scheduler .
* /
asmlinkage _ _ visible void _ _ sched notrace preempt_schedule_notrace ( void )
{
enum ctx_state prev_ctx ;
if ( likely ( ! preemptible ( ) ) )
return ;
do {
/ *
* Because the function tracer can trace preempt_count_sub ( )
* and it also uses preempt_enable / disable_notrace ( ) , if
* NEED_RESCHED is set , the preempt_enable_notrace ( ) called
* by the function tracer will call this function again and
* cause infinite recursion .
*
* Preemption must be disabled here before the function
* tracer can trace . Break up preempt_disable ( ) into two
* calls . One to disable preemption without fear of being
* traced . The other to still record the preemption latency ,
* which can also be traced by the function tracer .
* /
preempt_disable_notrace ( ) ;
preempt_latency_start ( 1 ) ;
/ *
* Needs preempt disabled in case user_exit ( ) is traced
* and the tracer calls preempt_enable_notrace ( ) causing
* an infinite recursion .
* /
prev_ctx = exception_enter ( ) ;
_ _ schedule ( SM_PREEMPT ) ;
exception_exit ( prev_ctx ) ;
preempt_latency_stop ( 1 ) ;
preempt_enable_no_resched_notrace ( ) ;
} while ( need_resched ( ) ) ;
}
EXPORT_SYMBOL_GPL ( preempt_schedule_notrace ) ;
# ifdef CONFIG_PREEMPT_DYNAMIC
# if defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_CALL )
# ifndef preempt_schedule_notrace_dynamic_enabled
# define preempt_schedule_notrace_dynamic_enabled preempt_schedule_notrace
# define preempt_schedule_notrace_dynamic_disabled NULL
# endif
DEFINE_STATIC_CALL ( preempt_schedule_notrace , preempt_schedule_notrace_dynamic_enabled ) ;
EXPORT_STATIC_CALL_TRAMP ( preempt_schedule_notrace ) ;
# elif defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_KEY )
static DEFINE_STATIC_KEY_TRUE ( sk_dynamic_preempt_schedule_notrace ) ;
void _ _ sched notrace dynamic_preempt_schedule_notrace ( void )
{
if ( ! static_branch_unlikely ( & sk_dynamic_preempt_schedule_notrace ) )
return ;
preempt_schedule_notrace ( ) ;
}
NOKPROBE_SYMBOL ( dynamic_preempt_schedule_notrace ) ;
EXPORT_SYMBOL ( dynamic_preempt_schedule_notrace ) ;
# endif
# endif
# endif / * CONFIG_PREEMPTION * /
/ *
* This is the entry point to schedule ( ) from kernel preemption
* off of IRQ context .
* Note , that this is called and return with IRQs disabled . This will
* protect us against recursive calling from IRQ contexts .
* /
asmlinkage _ _ visible void _ _ sched preempt_schedule_irq ( void )
{
enum ctx_state prev_state ;
/ * Catch callers which need to be fixed * /
BUG_ON ( preempt_count ( ) | | ! irqs_disabled ( ) ) ;
prev_state = exception_enter ( ) ;
do {
preempt_disable ( ) ;
local_irq_enable ( ) ;
_ _ schedule ( SM_PREEMPT ) ;
local_irq_disable ( ) ;
sched_preempt_enable_no_resched ( ) ;
} while ( need_resched ( ) ) ;
exception_exit ( prev_state ) ;
}
int default_wake_function ( wait_queue_entry_t * curr , unsigned mode , int wake_flags ,
void * key )
{
WARN_ON_ONCE ( wake_flags & ~ ( WF_SYNC | WF_CURRENT_CPU ) ) ;
return try_to_wake_up ( curr - > private , mode , wake_flags ) ;
}
EXPORT_SYMBOL ( default_wake_function ) ;
const struct sched_class * _ _ setscheduler_class ( int policy , int prio )
{
if ( dl_prio ( prio ) )
return & dl_sched_class ;
if ( rt_prio ( prio ) )
return & rt_sched_class ;
# ifdef CONFIG_SCHED_CLASS_EXT
if ( task_should_scx ( policy ) )
return & ext_sched_class ;
# endif
return & fair_sched_class ;
}
# ifdef CONFIG_RT_MUTEXES
/ *
* Would be more useful with typeof ( ) / auto_type but they don ' t mix with
* bit - fields . Since it ' s a local thing , use int . Keep the generic sounding
* name such that if someone were to implement this function we get to compare
* notes .
* /
# define fetch_and_set ( x , v ) ( { int _ x = ( x ) ; ( x ) = ( v ) ; _ x ; } )
void rt_mutex_pre_schedule ( void )
{
lockdep_assert ( ! fetch_and_set ( current - > sched_rt_mutex , 1 ) ) ;
sched_submit_work ( current ) ;
}
void rt_mutex_schedule ( void )
{
lockdep_assert ( current - > sched_rt_mutex ) ;
_ _ schedule_loop ( SM_NONE ) ;
}
void rt_mutex_post_schedule ( void )
{
sched_update_worker ( current ) ;
lockdep_assert ( fetch_and_set ( current - > sched_rt_mutex , 0 ) ) ;
}
/ *
* rt_mutex_setprio - set the current priority of a task
* @ p : task to boost
* @ pi_task : donor task
*
* This function changes the ' effective ' priority of a task . It does
* not touch - > normal_prio like _ _ setscheduler ( ) .
*
* Used by the rt_mutex code to implement priority inheritance
* logic . Call site only calls if the priority of the task changed .
* /
void rt_mutex_setprio ( struct task_struct * p , struct task_struct * pi_task )
{
int prio , oldprio , queued , running , queue_flag =
DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK ;
const struct sched_class * prev_class , * next_class ;
struct rq_flags rf ;
struct rq * rq ;
/ * XXX used to be waiter - > prio , not waiter - > task - > prio * /
prio = _ _ rt_effective_prio ( pi_task , p - > normal_prio ) ;
/ *
* If nothing changed ; bail early .
* /
if ( p - > pi_top_task = = pi_task & & prio = = p - > prio & & ! dl_prio ( prio ) )
return ;
rq = _ _ task_rq_lock ( p , & rf ) ;
update_rq_clock ( rq ) ;
/ *
* Set under pi_lock & & rq - > lock , such that the value can be used under
* either lock .
*
* Note that there is loads of tricky to make this pointer cache work
* right . rt_mutex_slowunlock ( ) + rt_mutex_postunlock ( ) work together to
* ensure a task is de - boosted ( pi_task is set to NULL ) before the
* task is allowed to run again ( and can exit ) . This ensures the pointer
* points to a blocked task - - which guarantees the task is present .
* /
p - > pi_top_task = pi_task ;
/ *
* For FIFO / RR we only need to set prio , if that matches we ' re done .
* /
if ( prio = = p - > prio & & ! dl_prio ( prio ) )
goto out_unlock ;
/ *
* Idle task boosting is a no - no in general . There is one
* exception , when PREEMPT_RT and NOHZ is active :
*
* The idle task calls get_next_timer_interrupt ( ) and holds
* the timer wheel base - > lock on the CPU and another CPU wants
* to access the timer ( probably to cancel it ) . We can safely
* ignore the boosting request , as the idle CPU runs this code
* with interrupts disabled and will complete the lock
* protected section without being interrupted . So there is no
* real need to boost .
* /
if ( unlikely ( p = = rq - > idle ) ) {
WARN_ON ( p ! = rq - > curr ) ;
WARN_ON ( p - > pi_blocked_on ) ;
goto out_unlock ;
}
trace_sched_pi_setprio ( p , pi_task ) ;
oldprio = p - > prio ;
if ( oldprio = = prio )
queue_flag & = ~ DEQUEUE_MOVE ;
prev_class = p - > sched_class ;
next_class = _ _ setscheduler_class ( p - > policy , prio ) ;
if ( prev_class ! = next_class & & p - > se . sched_delayed )
dequeue_task ( rq , p , DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK ) ;
queued = task_on_rq_queued ( p ) ;
running = task_current_donor ( rq , p ) ;
if ( queued )
dequeue_task ( rq , p , queue_flag ) ;
if ( running )
put_prev_task ( rq , p ) ;
/ *
* Boosting condition are :
* 1 . - rt task is running and holds mutex A
* - - > - dl task blocks on mutex A
*
* 2 . - dl task is running and holds mutex A
* - - > - dl task blocks on mutex A and could preempt the
* running task
* /
if ( dl_prio ( prio ) ) {
if ( ! dl_prio ( p - > normal_prio ) | |
( pi_task & & dl_prio ( pi_task - > prio ) & &
dl_entity_preempt ( & pi_task - > dl , & p - > dl ) ) ) {
p - > dl . pi_se = pi_task - > dl . pi_se ;
queue_flag | = ENQUEUE_REPLENISH ;
} else {
p - > dl . pi_se = & p - > dl ;
}
} else if ( rt_prio ( prio ) ) {
if ( dl_prio ( oldprio ) )
p - > dl . pi_se = & p - > dl ;
if ( oldprio < prio )
queue_flag | = ENQUEUE_HEAD ;
} else {
if ( dl_prio ( oldprio ) )
p - > dl . pi_se = & p - > dl ;
if ( rt_prio ( oldprio ) )
p - > rt . timeout = 0 ;
}
p - > sched_class = next_class ;
p - > prio = prio ;
check_class_changing ( rq , p , prev_class ) ;
if ( queued )
enqueue_task ( rq , p , queue_flag ) ;
if ( running )
set_next_task ( rq , p ) ;
check_class_changed ( rq , p , prev_class , oldprio ) ;
out_unlock :
/ * Avoid rq from going away on us : * /
preempt_disable ( ) ;
rq_unpin_lock ( rq , & rf ) ;
_ _ balance_callbacks ( rq ) ;
raw_spin_rq_unlock ( rq ) ;
preempt_enable ( ) ;
}
# endif / * CONFIG_RT_MUTEXES * /
# if ! defined ( CONFIG_PREEMPTION ) | | defined ( CONFIG_PREEMPT_DYNAMIC )
int _ _ sched _ _ cond_resched ( void )
{
if ( should_resched ( 0 ) & & ! irqs_disabled ( ) ) {
preempt_schedule_common ( ) ;
return 1 ;
}
/ *
* In PREEMPT_RCU kernels , - > rcu_read_lock_nesting tells the tick
* whether the current CPU is in an RCU read - side critical section ,
* so the tick can report quiescent states even for CPUs looping
* in kernel context . In contrast , in non - preemptible kernels ,
* RCU readers leave no in - memory hints , which means that CPU - bound
* processes executing in kernel context might never report an
* RCU quiescent state . Therefore , the following code causes
* cond_resched ( ) to report a quiescent state , but only when RCU
* is in urgent need of one .
* A third case , preemptible , but non - PREEMPT_RCU provides for
* urgently needed quiescent states via rcu_flavor_sched_clock_irq ( ) .
* /
# ifndef CONFIG_PREEMPT_RCU
rcu_all_qs ( ) ;
# endif
return 0 ;
}
EXPORT_SYMBOL ( _ _ cond_resched ) ;
# endif
# ifdef CONFIG_PREEMPT_DYNAMIC
# ifdef CONFIG_HAVE_PREEMPT_DYNAMIC_CALL
# define cond_resched_dynamic_enabled _ _ cond_resched
# define cond_resched_dynamic_disabled ( ( void * ) & _ _ static_call_return0 )
DEFINE_STATIC_CALL_RET0 ( cond_resched , _ _ cond_resched ) ;
EXPORT_STATIC_CALL_TRAMP ( cond_resched ) ;
# define might_resched_dynamic_enabled _ _ cond_resched
# define might_resched_dynamic_disabled ( ( void * ) & _ _ static_call_return0 )
DEFINE_STATIC_CALL_RET0 ( might_resched , _ _ cond_resched ) ;
EXPORT_STATIC_CALL_TRAMP ( might_resched ) ;
# elif defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_KEY )
static DEFINE_STATIC_KEY_FALSE ( sk_dynamic_cond_resched ) ;
int _ _ sched dynamic_cond_resched ( void )
{
if ( ! static_branch_unlikely ( & sk_dynamic_cond_resched ) )
return 0 ;
return _ _ cond_resched ( ) ;
}
EXPORT_SYMBOL ( dynamic_cond_resched ) ;
static DEFINE_STATIC_KEY_FALSE ( sk_dynamic_might_resched ) ;
int _ _ sched dynamic_might_resched ( void )
{
if ( ! static_branch_unlikely ( & sk_dynamic_might_resched ) )
return 0 ;
return _ _ cond_resched ( ) ;
}
EXPORT_SYMBOL ( dynamic_might_resched ) ;
# endif
# endif / * CONFIG_PREEMPT_DYNAMIC * /
/ *
* _ _ cond_resched_lock ( ) - if a reschedule is pending , drop the given lock ,
* call schedule , and on return reacquire the lock .
*
* This works OK both with and without CONFIG_PREEMPTION . We do strange low - level
* operations here to prevent schedule ( ) from being called twice ( once via
* spin_unlock ( ) , once by hand ) .
* /
int _ _ cond_resched_lock ( spinlock_t * lock )
{
int resched = should_resched ( PREEMPT_LOCK_OFFSET ) ;
int ret = 0 ;
lockdep_assert_held ( lock ) ;
if ( spin_needbreak ( lock ) | | resched ) {
spin_unlock ( lock ) ;
if ( ! _ cond_resched ( ) )
cpu_relax ( ) ;
ret = 1 ;
spin_lock ( lock ) ;
}
return ret ;
}
EXPORT_SYMBOL ( _ _ cond_resched_lock ) ;
int _ _ cond_resched_rwlock_read ( rwlock_t * lock )
{
int resched = should_resched ( PREEMPT_LOCK_OFFSET ) ;
int ret = 0 ;
lockdep_assert_held_read ( lock ) ;
if ( rwlock_needbreak ( lock ) | | resched ) {
read_unlock ( lock ) ;
if ( ! _ cond_resched ( ) )
cpu_relax ( ) ;
ret = 1 ;
read_lock ( lock ) ;
}
return ret ;
}
EXPORT_SYMBOL ( _ _ cond_resched_rwlock_read ) ;
int _ _ cond_resched_rwlock_write ( rwlock_t * lock )
{
int resched = should_resched ( PREEMPT_LOCK_OFFSET ) ;
int ret = 0 ;
lockdep_assert_held_write ( lock ) ;
if ( rwlock_needbreak ( lock ) | | resched ) {
write_unlock ( lock ) ;
if ( ! _ cond_resched ( ) )
cpu_relax ( ) ;
ret = 1 ;
write_lock ( lock ) ;
}
return ret ;
}
EXPORT_SYMBOL ( _ _ cond_resched_rwlock_write ) ;
# ifdef CONFIG_PREEMPT_DYNAMIC
# ifdef CONFIG_GENERIC_IRQ_ENTRY
# include < linux / irq - entry - common . h >
# endif
/ *
* SC : cond_resched
* SC : might_resched
* SC : preempt_schedule
* SC : preempt_schedule_notrace
* SC : irqentry_exit_cond_resched
*
*
* NONE :
* cond_resched < - _ _ cond_resched
* might_resched < - RET0
* preempt_schedule < - NOP
* preempt_schedule_notrace < - NOP
* irqentry_exit_cond_resched < - NOP
* dynamic_preempt_lazy < - false
*
* VOLUNTARY :
* cond_resched < - _ _ cond_resched
* might_resched < - _ _ cond_resched
* preempt_schedule < - NOP
* preempt_schedule_notrace < - NOP
* irqentry_exit_cond_resched < - NOP
* dynamic_preempt_lazy < - false
*
* FULL :
* cond_resched < - RET0
* might_resched < - RET0
* preempt_schedule < - preempt_schedule
* preempt_schedule_notrace < - preempt_schedule_notrace
* irqentry_exit_cond_resched < - irqentry_exit_cond_resched
* dynamic_preempt_lazy < - false
*
* LAZY :
* cond_resched < - RET0
* might_resched < - RET0
* preempt_schedule < - preempt_schedule
* preempt_schedule_notrace < - preempt_schedule_notrace
* irqentry_exit_cond_resched < - irqentry_exit_cond_resched
* dynamic_preempt_lazy < - true
* /
enum {
preempt_dynamic_undefined = - 1 ,
preempt_dynamic_none ,
preempt_dynamic_voluntary ,
preempt_dynamic_full ,
preempt_dynamic_lazy ,
} ;
int preempt_dynamic_mode = preempt_dynamic_undefined ;
int sched_dynamic_mode ( const char * str )
{
# ifndef CONFIG_PREEMPT_RT
if ( ! strcmp ( str , " none " ) )
return preempt_dynamic_none ;
if ( ! strcmp ( str , " voluntary " ) )
return preempt_dynamic_voluntary ;
# endif
if ( ! strcmp ( str , " full " ) )
return preempt_dynamic_full ;
# ifdef CONFIG_ARCH_HAS_PREEMPT_LAZY
if ( ! strcmp ( str , " lazy " ) )
return preempt_dynamic_lazy ;
# endif
return - EINVAL ;
}
# define preempt_dynamic_key_enable ( f ) static_key_enable ( & sk_dynamic_ # # f . key )
# define preempt_dynamic_key_disable ( f ) static_key_disable ( & sk_dynamic_ # # f . key )
# if defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_CALL )
# define preempt_dynamic_enable ( f ) static_call_update ( f , f # # _ dynamic_enabled )
# define preempt_dynamic_disable ( f ) static_call_update ( f , f # # _ dynamic_disabled )
# elif defined ( CONFIG_HAVE_PREEMPT_DYNAMIC_KEY )
# define preempt_dynamic_enable ( f ) preempt_dynamic_key_enable ( f )
# define preempt_dynamic_disable ( f ) preempt_dynamic_key_disable ( f )
# else
# error " Unsupported PREEMPT_DYNAMIC mechanism "
# endif
static DEFINE_MUTEX ( sched_dynamic_mutex ) ;
static void _ _ sched_dynamic_update ( int mode )
{
/ *
* Avoid { NONE , VOLUNTARY } - > FULL transitions from ever ending up in
* the ZERO state , which is invalid .
* /
preempt_dynamic_enable ( cond_resched ) ;
preempt_dynamic_enable ( might_resched ) ;
preempt_dynamic_enable ( preempt_schedule ) ;
preempt_dynamic_enable ( preempt_schedule_notrace ) ;
preempt_dynamic_enable ( irqentry_exit_cond_resched ) ;
preempt_dynamic_key_disable ( preempt_lazy ) ;
switch ( mode ) {
case preempt_dynamic_none :
preempt_dynamic_enable ( cond_resched ) ;
preempt_dynamic_disable ( might_resched ) ;
preempt_dynamic_disable ( preempt_schedule ) ;
preempt_dynamic_disable ( preempt_schedule_notrace ) ;
preempt_dynamic_disable ( irqentry_exit_cond_resched ) ;
preempt_dynamic_key_disable ( preempt_lazy ) ;
if ( mode ! = preempt_dynamic_mode )
pr_info ( " Dynamic Preempt : none \ n " ) ;
break ;
case preempt_dynamic_voluntary :
preempt_dynamic_enable ( cond_resched ) ;
preempt_dynamic_enable ( might_resched ) ;
preempt_dynamic_disable ( preempt_schedule ) ;
preempt_dynamic_disable ( preempt_schedule_notrace ) ;
preempt_dynamic_disable ( irqentry_exit_cond_resched ) ;
preempt_dynamic_key_disable ( preempt_lazy ) ;
if ( mode ! = preempt_dynamic_mode )
pr_info ( " Dynamic Preempt : voluntary \ n " ) ;
break ;
case preempt_dynamic_full :
preempt_dynamic_disable ( cond_resched ) ;
preempt_dynamic_disable ( might_resched ) ;
preempt_dynamic_enable ( preempt_schedule ) ;
preempt_dynamic_enable ( preempt_schedule_notrace ) ;
preempt_dynamic_enable ( irqentry_exit_cond_resched ) ;
preempt_dynamic_key_disable ( preempt_lazy ) ;
if ( mode ! = preempt_dynamic_mode )
pr_info ( " Dynamic Preempt : full \ n " ) ;
break ;
case preempt_dynamic_lazy :
preempt_dynamic_disable ( cond_resched ) ;
preempt_dynamic_disable ( might_resched ) ;
preempt_dynamic_enable ( preempt_schedule ) ;
preempt_dynamic_enable ( preempt_schedule_notrace ) ;
preempt_dynamic_enable ( irqentry_exit_cond_resched ) ;
preempt_dynamic_key_enable ( preempt_lazy ) ;
if ( mode ! = preempt_dynamic_mode )
pr_info ( " Dynamic Preempt : lazy \ n " ) ;
break ;
}
preempt_dynamic_mode = mode ;
}
void sched_dynamic_update ( int mode )
{
mutex_lock ( & sched_dynamic_mutex ) ;
_ _ sched_dynamic_update ( mode ) ;
mutex_unlock ( & sched_dynamic_mutex ) ;
}
static int _ _ init setup_preempt_mode ( char * str )
{
int mode = sched_dynamic_mode ( str ) ;
if ( mode < 0 ) {
pr_warn ( " Dynamic Preempt : unsupported mode : % s \ n " , str ) ;
return 0 ;
}
sched_dynamic_update ( mode ) ;
return 1 ;
}
_ _ setup ( " preempt = " , setup_preempt_mode ) ;
static void _ _ init preempt_dynamic_init ( void )
{
if ( preempt_dynamic_mode = = preempt_dynamic_undefined ) {
if ( IS_ENABLED ( CONFIG_PREEMPT_NONE ) ) {
sched_dynamic_update ( preempt_dynamic_none ) ;
} else if ( IS_ENABLED ( CONFIG_PREEMPT_VOLUNTARY ) ) {
sched_dynamic_update ( preempt_dynamic_voluntary ) ;
} else if ( IS_ENABLED ( CONFIG_PREEMPT_LAZY ) ) {
sched_dynamic_update ( preempt_dynamic_lazy ) ;
} else {
/ * Default static call setting , nothing to do * /
WARN_ON_ONCE ( ! IS_ENABLED ( CONFIG_PREEMPT ) ) ;
preempt_dynamic_mode = preempt_dynamic_full ;
pr_info ( " Dynamic Preempt : full \ n " ) ;
}
}
}
# define PREEMPT_MODEL_ACCESSOR ( mode ) \
bool preempt_model_ # # mode ( void ) \
{ \
WARN_ON_ONCE ( preempt_dynamic_mode = = preempt_dynamic_undefined ) ; \
return preempt_dynamic_mode = = preempt_dynamic_ # # mode ; \
} \
EXPORT_SYMBOL_GPL ( preempt_model_ # # mode )
PREEMPT_MODEL_ACCESSOR ( none ) ;
PREEMPT_MODEL_ACCESSOR ( voluntary ) ;
PREEMPT_MODEL_ACCESSOR ( full ) ;
PREEMPT_MODEL_ACCESSOR ( lazy ) ;
# else / * ! CONFIG_PREEMPT_DYNAMIC : * /
# define preempt_dynamic_mode - 1
static inline void preempt_dynamic_init ( void ) { }
# endif / * CONFIG_PREEMPT_DYNAMIC * /
const char * preempt_modes [ ] = {
" none " , " voluntary " , " full " , " lazy " , NULL ,
} ;
const char * preempt_model_str ( void )
{
bool brace = IS_ENABLED ( CONFIG_PREEMPT_RT ) & &
( IS_ENABLED ( CONFIG_PREEMPT_DYNAMIC ) | |
IS_ENABLED ( CONFIG_PREEMPT_LAZY ) ) ;
static char buf [ 128 ] ;
if ( IS_ENABLED ( CONFIG_PREEMPT_BUILD ) ) {
struct seq_buf s ;
seq_buf_init ( & s , buf , sizeof ( buf ) ) ;
seq_buf_puts ( & s , " PREEMPT " ) ;
if ( IS_ENABLED ( CONFIG_PREEMPT_RT ) )
seq_buf_printf ( & s , " % sRT % s " ,
brace ? " _ { " : " _ " ,
brace ? " , " : " " ) ;
if ( IS_ENABLED ( CONFIG_PREEMPT_DYNAMIC ) ) {
seq_buf_printf ( & s , " ( % s ) % s " ,
preempt_dynamic_mode > = 0 ?
preempt_modes [ preempt_dynamic_mode ] : " undef " ,
brace ? " } " : " " ) ;
return seq_buf_str ( & s ) ;
}
if ( IS_ENABLED ( CONFIG_PREEMPT_LAZY ) ) {
seq_buf_printf ( & s , " LAZY % s " ,
brace ? " } " : " " ) ;
return seq_buf_str ( & s ) ;
}
return seq_buf_str ( & s ) ;
}
if ( IS_ENABLED ( CONFIG_PREEMPT_VOLUNTARY_BUILD ) )
return " VOLUNTARY " ;
return " NONE " ;
}
int io_schedule_prepare ( void )
{
int old_iowait = current - > in_iowait ;
current - > in_iowait = 1 ;
blk_flush_plug ( current - > plug , true ) ;
return old_iowait ;
}
void io_schedule_finish ( int token )
{
current - > in_iowait = token ;
}
/ *
* This task is about to go to sleep on IO . Increment rq - > nr_iowait so
* that process accounting knows that this is a task in IO wait state .
* /
long _ _ sched io_schedule_timeout ( long timeout )
{
int token ;
long ret ;
token = io_schedule_prepare ( ) ;
ret = schedule_timeout ( timeout ) ;
io_schedule_finish ( token ) ;
return ret ;
}
EXPORT_SYMBOL ( io_schedule_timeout ) ;
void _ _ sched io_schedule ( void )
{
int token ;
token = io_schedule_prepare ( ) ;
schedule ( ) ;
io_schedule_finish ( token ) ;
}
EXPORT_SYMBOL ( io_schedule ) ;
void sched_show_task ( struct task_struct * p )
{
unsigned long free ;
int ppid ;
if ( ! try_get_task_stack ( p ) )
return ;
pr_info ( " task : % - 15 . 15 s state : % c " , p - > comm , task_state_to_char ( p ) ) ;
if ( task_is_running ( p ) )
pr_cont ( " running task " ) ;
free = stack_not_used ( p ) ;
ppid = 0 ;
rcu_read_lock ( ) ;
if ( pid_alive ( p ) )
ppid = task_pid_nr ( rcu_dereference ( p - > real_parent ) ) ;
rcu_read_unlock ( ) ;
pr_cont ( " stack : % - 5 lu pid : % - 5 d tgid : % - 5 d ppid : % - 6 d task_flags : 0 x % 04 x flags : 0 x % 08 lx \ n " ,
free , task_pid_nr ( p ) , task_tgid_nr ( p ) ,
ppid , p - > flags , read_task_thread_flags ( p ) ) ;
print_worker_info ( KERN_INFO , p ) ;
print_stop_info ( KERN_INFO , p ) ;
print_scx_info ( KERN_INFO , p ) ;
show_stack ( p , NULL , KERN_INFO ) ;
put_task_stack ( p ) ;
}
EXPORT_SYMBOL_GPL ( sched_show_task ) ;
static inline bool
state_filter_match ( unsigned long state_filter , struct task_struct * p )
{
unsigned int state = READ_ONCE ( p - > _ _ state ) ;
/ * no filter , everything matches * /
if ( ! state_filter )
return true ;
/ * filter , but doesn ' t match * /
if ( ! ( state & state_filter ) )
return false ;
/ *
* When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE ( allows
* TASK_KILLABLE ) .
* /
if ( state_filter = = TASK_UNINTERRUPTIBLE & & ( state & TASK_NOLOAD ) )
return false ;
return true ;
}
void show_state_filter ( unsigned int state_filter )
{
struct task_struct * g , * p ;
rcu_read_lock ( ) ;
for_each_process_thread ( g , p ) {
/ *
* reset the NMI - timeout , listing all files on a slow
* console might take a lot of time :
* Also , reset softlockup watchdogs on all CPUs , because
* another CPU might be blocked waiting for us to process
* an IPI .
* /
touch_nmi_watchdog ( ) ;
touch_all_softlockup_watchdogs ( ) ;
if ( state_filter_match ( state_filter , p ) )
sched_show_task ( p ) ;
}
if ( ! state_filter )
sysrq_sched_debug_show ( ) ;
rcu_read_unlock ( ) ;
/ *
* Only show locks if all tasks are dumped :
* /
if ( ! state_filter )
debug_show_all_locks ( ) ;
}
/ * *
* init_idle - set up an idle thread for a given CPU
* @ idle : task in question
* @ cpu : CPU the idle task belongs to
*
* NOTE : this function does not set the idle thread ' s NEED_RESCHED
* flag , to make booting more robust .
* /
void _ _ init init_idle ( struct task_struct * idle , int cpu )
{
struct affinity_context ac = ( struct affinity_context ) {
. new_mask = cpumask_of ( cpu ) ,
. flags = 0 ,
} ;
struct rq * rq = cpu_rq ( cpu ) ;
unsigned long flags ;
raw_spin_lock_irqsave ( & idle - > pi_lock , flags ) ;
raw_spin_rq_lock ( rq ) ;
idle - > _ _ state = TASK_RUNNING ;
idle - > se . exec_start = sched_clock ( ) ;
/ *
* PF_KTHREAD should already be set at this point ; regardless , make it
* look like a proper per - CPU kthread .
* /
idle - > flags | = PF_KTHREAD | PF_NO_SETAFFINITY ;
kthread_set_per_cpu ( idle , cpu ) ;
/ *
* No validation and serialization required at boot time and for
* setting up the idle tasks of not yet online CPUs .
* /
set_cpus_allowed_common ( idle , & ac ) ;
/ *
* We ' re having a chicken and egg problem , even though we are
* holding rq - > lock , the CPU isn ' t yet set to this CPU so the
* lockdep check in task_group ( ) will fail .
*
* Similar case to sched_fork ( ) . / Alternatively we could
* use task_rq_lock ( ) here and obtain the other rq - > lock .
*
* Silence PROVE_RCU
* /
rcu_read_lock ( ) ;
_ _ set_task_cpu ( idle , cpu ) ;
rcu_read_unlock ( ) ;
rq - > idle = idle ;
rq_set_donor ( rq , idle ) ;
rcu_assign_pointer ( rq - > curr , idle ) ;
idle - > on_rq = TASK_ON_RQ_QUEUED ;
idle - > on_cpu = 1 ;
raw_spin_rq_unlock ( rq ) ;
raw_spin_unlock_irqrestore ( & idle - > pi_lock , flags ) ;
/ * Set the preempt count _ outside_ the spinlocks ! * /
init_idle_preempt_count ( idle , cpu ) ;
/ *
* The idle tasks have their own , simple scheduling class :
* /
idle - > sched_class = & idle_sched_class ;
ftrace_graph_init_idle_task ( idle , cpu ) ;
vtime_init_idle ( idle , cpu ) ;
sprintf ( idle - > comm , " % s / % d " , INIT_TASK_COMM , cpu ) ;
}
int cpuset_cpumask_can_shrink ( const struct cpumask * cur ,
const struct cpumask * trial )
{
int ret = 1 ;
if ( cpumask_empty ( cur ) )
return ret ;
ret = dl_cpuset_cpumask_can_shrink ( cur , trial ) ;
return ret ;
}
int task_can_attach ( struct task_struct * p )
{
int ret = 0 ;
/ *
* Kthreads which disallow setaffinity shouldn ' t be moved
* to a new cpuset ; we don ' t want to change their CPU
* affinity and isolating such threads by their set of
* allowed nodes is unnecessary . Thus , cpusets are not
* applicable for such threads . This prevents checking for
* success of set_cpus_allowed_ptr ( ) on all attached tasks
* before cpus_mask may be changed .
* /
if ( p - > flags & PF_NO_SETAFFINITY )
ret = - EINVAL ;
return ret ;
}
bool sched_smp_initialized _ _ read_mostly ;
# ifdef CONFIG_NUMA_BALANCING
/ * Migrate current task p to target_cpu * /
int migrate_task_to ( struct task_struct * p , int target_cpu )
{
struct migration_arg arg = { p , target_cpu } ;
int curr_cpu = task_cpu ( p ) ;
if ( curr_cpu = = target_cpu )
return 0 ;
if ( ! cpumask_test_cpu ( target_cpu , p - > cpus_ptr ) )
return - EINVAL ;
/ * TODO : This is not properly updating schedstats * /
trace_sched_move_numa ( p , curr_cpu , target_cpu ) ;
return stop_one_cpu ( curr_cpu , migration_cpu_stop , & arg ) ;
}
/ *
* Requeue a task on a given node and accurately track the number of NUMA
* tasks on the runqueues
* /
void sched_setnuma ( struct task_struct * p , int nid )
{
bool queued , running ;
struct rq_flags rf ;
struct rq * rq ;
rq = task_rq_lock ( p , & rf ) ;
queued = task_on_rq_queued ( p ) ;
running = task_current_donor ( rq , p ) ;
if ( queued )
dequeue_task ( rq , p , DEQUEUE_SAVE ) ;
if ( running )
put_prev_task ( rq , p ) ;
p - > numa_preferred_nid = nid ;
if ( queued )
enqueue_task ( rq , p , ENQUEUE_RESTORE | ENQUEUE_NOCLOCK ) ;
if ( running )
set_next_task ( rq , p ) ;
task_rq_unlock ( rq , p , & rf ) ;
}
# endif / * CONFIG_NUMA_BALANCING * /
# ifdef CONFIG_HOTPLUG_CPU
/ *
* Invoked on the outgoing CPU in context of the CPU hotplug thread
* after ensuring that there are no user space tasks left on the CPU .
*
* If there is a lazy mm in use on the hotplug thread , drop it and
* switch to init_mm .
*
* The reference count on init_mm is dropped in finish_cpu ( ) .
* /
static void sched_force_init_mm ( void )
{
struct mm_struct * mm = current - > active_mm ;
if ( mm ! = & init_mm ) {
mmgrab_lazy_tlb ( & init_mm ) ;
local_irq_disable ( ) ;
current - > active_mm = & init_mm ;
switch_mm_irqs_off ( mm , & init_mm , current ) ;
local_irq_enable ( ) ;
finish_arch_post_lock_switch ( ) ;
mmdrop_lazy_tlb ( mm ) ;
}
/ * finish_cpu ( ) , as ran on the BP , will clean up the active_mm state * /
}
static int _ _ balance_push_cpu_stop ( void * arg )
{
struct task_struct * p = arg ;
struct rq * rq = this_rq ( ) ;
struct rq_flags rf ;
int cpu ;
raw_spin_lock_irq ( & p - > pi_lock ) ;
rq_lock ( rq , & rf ) ;
update_rq_clock ( rq ) ;
if ( task_rq ( p ) = = rq & & task_on_rq_queued ( p ) ) {
cpu = select_fallback_rq ( rq - > cpu , p ) ;
rq = _ _ migrate_task ( rq , & rf , p , cpu ) ;
}
rq_unlock ( rq , & rf ) ;
raw_spin_unlock_irq ( & p - > pi_lock ) ;
put_task_struct ( p ) ;
return 0 ;
}
static DEFINE_PER_CPU ( struct cpu_stop_work , push_work ) ;
/ *
* Ensure we only run per - cpu kthreads once the CPU goes ! active .
*
* This is enabled below SCHED_AP_ACTIVE ; when ! cpu_active ( ) , but only
* effective when the hotplug motion is down .
* /
static void balance_push ( struct rq * rq )
{
struct task_struct * push_task = rq - > curr ;
lockdep_assert_rq_held ( rq ) ;
/ *
* Ensure the thing is persistent until balance_push_set ( . on = false ) ;
* /
rq - > balance_callback = & balance_push_callback ;
/ *
* Only active while going offline and when invoked on the outgoing
* CPU .
* /
if ( ! cpu_dying ( rq - > cpu ) | | rq ! = this_rq ( ) )
return ;
/ *
* Both the cpu - hotplug and stop task are in this case and are
* required to complete the hotplug process .
* /
if ( kthread_is_per_cpu ( push_task ) | |
is_migration_disabled ( push_task ) ) {
/ *
* If this is the idle task on the outgoing CPU try to wake
* up the hotplug control thread which might wait for the
* last task to vanish . The rcuwait_active ( ) check is
* accurate here because the waiter is pinned on this CPU
* and can ' t obviously be running in parallel .
*
* On RT kernels this also has to check whether there are
* pinned and scheduled out tasks on the runqueue . They
* need to leave the migrate disabled section first .
* /
if ( ! rq - > nr_running & & ! rq_has_pinned_tasks ( rq ) & &
rcuwait_active ( & rq - > hotplug_wait ) ) {
raw_spin_rq_unlock ( rq ) ;
rcuwait_wake_up ( & rq - > hotplug_wait ) ;
raw_spin_rq_lock ( rq ) ;
}
return ;
}
get_task_struct ( push_task ) ;
/ *
* Temporarily drop rq - > lock such that we can wake - up the stop task .
* Both preemption and IRQs are still disabled .
* /
preempt_disable ( ) ;
raw_spin_rq_unlock ( rq ) ;
stop_one_cpu_nowait ( rq - > cpu , _ _ balance_push_cpu_stop , push_task ,
this_cpu_ptr ( & push_work ) ) ;
preempt_enable ( ) ;
/ *
* At this point need_resched ( ) is true and we ' ll take the loop in
* schedule ( ) . The next pick is obviously going to be the stop task
* which kthread_is_per_cpu ( ) and will push this task away .
* /
raw_spin_rq_lock ( rq ) ;
}
static void balance_push_set ( int cpu , bool on )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct rq_flags rf ;
rq_lock_irqsave ( rq , & rf ) ;
if ( on ) {
WARN_ON_ONCE ( rq - > balance_callback ) ;
rq - > balance_callback = & balance_push_callback ;
} else if ( rq - > balance_callback = = & balance_push_callback ) {
rq - > balance_callback = NULL ;
}
rq_unlock_irqrestore ( rq , & rf ) ;
}
/ *
* Invoked from a CPUs hotplug control thread after the CPU has been marked
* inactive . All tasks which are not per CPU kernel threads are either
* pushed off this CPU now via balance_push ( ) or placed on a different CPU
* during wakeup . Wait until the CPU is quiescent .
* /
static void balance_hotplug_wait ( void )
{
struct rq * rq = this_rq ( ) ;
rcuwait_wait_event ( & rq - > hotplug_wait ,
rq - > nr_running = = 1 & & ! rq_has_pinned_tasks ( rq ) ,
TASK_UNINTERRUPTIBLE ) ;
}
# else / * ! CONFIG_HOTPLUG_CPU : * /
static inline void balance_push ( struct rq * rq )
{
}
static inline void balance_push_set ( int cpu , bool on )
{
}
static inline void balance_hotplug_wait ( void )
{
}
# endif / * ! CONFIG_HOTPLUG_CPU * /
void set_rq_online ( struct rq * rq )
{
if ( ! rq - > online ) {
const struct sched_class * class ;
cpumask_set_cpu ( rq - > cpu , rq - > rd - > online ) ;
rq - > online = 1 ;
for_each_class ( class ) {
if ( class - > rq_online )
class - > rq_online ( rq ) ;
}
}
}
void set_rq_offline ( struct rq * rq )
{
if ( rq - > online ) {
const struct sched_class * class ;
update_rq_clock ( rq ) ;
for_each_class ( class ) {
if ( class - > rq_offline )
class - > rq_offline ( rq ) ;
}
cpumask_clear_cpu ( rq - > cpu , rq - > rd - > online ) ;
rq - > online = 0 ;
}
}
static inline void sched_set_rq_online ( struct rq * rq , int cpu )
{
struct rq_flags rf ;
rq_lock_irqsave ( rq , & rf ) ;
if ( rq - > rd ) {
BUG_ON ( ! cpumask_test_cpu ( cpu , rq - > rd - > span ) ) ;
set_rq_online ( rq ) ;
}
rq_unlock_irqrestore ( rq , & rf ) ;
}
static inline void sched_set_rq_offline ( struct rq * rq , int cpu )
{
struct rq_flags rf ;
rq_lock_irqsave ( rq , & rf ) ;
if ( rq - > rd ) {
BUG_ON ( ! cpumask_test_cpu ( cpu , rq - > rd - > span ) ) ;
set_rq_offline ( rq ) ;
}
rq_unlock_irqrestore ( rq , & rf ) ;
}
/ *
* used to mark begin / end of suspend / resume :
* /
static int num_cpus_frozen ;
/ *
* Update cpusets according to cpu_active mask . If cpusets are
* disabled , cpuset_update_active_cpus ( ) becomes a simple wrapper
* around partition_sched_domains ( ) .
*
* If we come here as part of a suspend / resume , don ' t touch cpusets because we
* want to restore it back to its original state upon resume anyway .
* /
static void cpuset_cpu_active ( void )
{
if ( cpuhp_tasks_frozen ) {
/ *
* num_cpus_frozen tracks how many CPUs are involved in suspend
* resume sequence . As long as this is not the last online
* operation in the resume sequence , just build a single sched
* domain , ignoring cpusets .
* /
cpuset_reset_sched_domains ( ) ;
if ( - - num_cpus_frozen )
return ;
/ *
* This is the last CPU online operation . So fall through and
* restore the original sched domains by considering the
* cpuset configurations .
* /
cpuset_force_rebuild ( ) ;
}
cpuset_update_active_cpus ( ) ;
}
static void cpuset_cpu_inactive ( unsigned int cpu )
{
if ( ! cpuhp_tasks_frozen ) {
cpuset_update_active_cpus ( ) ;
} else {
num_cpus_frozen + + ;
cpuset_reset_sched_domains ( ) ;
}
}
static inline void sched_smt_present_inc ( int cpu )
{
# ifdef CONFIG_SCHED_SMT
if ( cpumask_weight ( cpu_smt_mask ( cpu ) ) = = 2 )
static_branch_inc_cpuslocked ( & sched_smt_present ) ;
# endif
}
static inline void sched_smt_present_dec ( int cpu )
{
# ifdef CONFIG_SCHED_SMT
if ( cpumask_weight ( cpu_smt_mask ( cpu ) ) = = 2 )
static_branch_dec_cpuslocked ( & sched_smt_present ) ;
# endif
}
int sched_cpu_activate ( unsigned int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
/ *
* Clear the balance_push callback and prepare to schedule
* regular tasks .
* /
balance_push_set ( cpu , false ) ;
/ *
* When going up , increment the number of cores with SMT present .
* /
sched_smt_present_inc ( cpu ) ;
set_cpu_active ( cpu , true ) ;
if ( sched_smp_initialized ) {
sched_update_numa ( cpu , true ) ;
sched_domains_numa_masks_set ( cpu ) ;
cpuset_cpu_active ( ) ;
}
scx_rq_activate ( rq ) ;
/ *
* Put the rq online , if not already . This happens :
*
* 1 ) In the early boot process , because we build the real domains
* after all CPUs have been brought up .
*
* 2 ) At runtime , if cpuset_cpu_active ( ) fails to rebuild the
* domains .
* /
sched_set_rq_online ( rq , cpu ) ;
return 0 ;
}
int sched_cpu_deactivate ( unsigned int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
int ret ;
ret = dl_bw_deactivate ( cpu ) ;
if ( ret )
return ret ;
/ *
* Remove CPU from nohz . idle_cpus_mask to prevent participating in
* load balancing when not active
* /
nohz_balance_exit_idle ( rq ) ;
set_cpu_active ( cpu , false ) ;
/ *
* From this point forward , this CPU will refuse to run any task that
* is not : migrate_disable ( ) or KTHREAD_IS_PER_CPU , and will actively
* push those tasks away until this gets cleared , see
* sched_cpu_dying ( ) .
* /
balance_push_set ( cpu , true ) ;
/ *
* We ' ve cleared cpu_active_mask / set balance_push , wait for all
* preempt - disabled and RCU users of this state to go away such that
* all new such users will observe it .
*
* Specifically , we rely on ttwu to no longer target this CPU , see
* ttwu_queue_cond ( ) and is_cpu_allowed ( ) .
*
* Do sync before park smpboot threads to take care the RCU boost case .
* /
synchronize_rcu ( ) ;
sched_set_rq_offline ( rq , cpu ) ;
scx_rq_deactivate ( rq ) ;
/ *
* When going down , decrement the number of cores with SMT present .
* /
sched_smt_present_dec ( cpu ) ;
# ifdef CONFIG_SCHED_SMT
sched_core_cpu_deactivate ( cpu ) ;
# endif
if ( ! sched_smp_initialized )
return 0 ;
sched_update_numa ( cpu , false ) ;
cpuset_cpu_inactive ( cpu ) ;
sched_domains_numa_masks_clear ( cpu ) ;
return 0 ;
}
static void sched_rq_cpu_starting ( unsigned int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
rq - > calc_load_update = calc_load_update ;
update_max_interval ( ) ;
}
int sched_cpu_starting ( unsigned int cpu )
{
sched_core_cpu_starting ( cpu ) ;
sched_rq_cpu_starting ( cpu ) ;
sched_tick_start ( cpu ) ;
return 0 ;
}
# ifdef CONFIG_HOTPLUG_CPU
/ *
* Invoked immediately before the stopper thread is invoked to bring the
* CPU down completely . At this point all per CPU kthreads except the
* hotplug thread ( current ) and the stopper thread ( inactive ) have been
* either parked or have been unbound from the outgoing CPU . Ensure that
* any of those which might be on the way out are gone .
*
* If after this point a bound task is being woken on this CPU then the
* responsible hotplug callback has failed to do it ' s job .
* sched_cpu_dying ( ) will catch it with the appropriate fireworks .
* /
int sched_cpu_wait_empty ( unsigned int cpu )
{
balance_hotplug_wait ( ) ;
sched_force_init_mm ( ) ;
return 0 ;
}
/ *
* Since this CPU is going ' away ' for a while , fold any nr_active delta we
* might have . Called from the CPU stopper task after ensuring that the
* stopper is the last running task on the CPU , so nr_active count is
* stable . We need to take the tear - down thread which is calling this into
* account , so we hand in adjust = 1 to the load calculation .
*
* Also see the comment " Global load - average calculations " .
* /
static void calc_load_migrate ( struct rq * rq )
{
long delta = calc_load_fold_active ( rq , 1 ) ;
if ( delta )
atomic_long_add ( delta , & calc_load_tasks ) ;
}
static void dump_rq_tasks ( struct rq * rq , const char * loglvl )
{
struct task_struct * g , * p ;
int cpu = cpu_of ( rq ) ;
lockdep_assert_rq_held ( rq ) ;
printk ( " % sCPU % d enqueued tasks ( % u total ) : \ n " , loglvl , cpu , rq - > nr_running ) ;
for_each_process_thread ( g , p ) {
if ( task_cpu ( p ) ! = cpu )
continue ;
if ( ! task_on_rq_queued ( p ) )
continue ;
printk ( " % s \ tpid : % d , name : % s \ n " , loglvl , p - > pid , p - > comm ) ;
}
}
int sched_cpu_dying ( unsigned int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct rq_flags rf ;
/ * Handle pending wakeups and then migrate everything off * /
sched_tick_stop ( cpu ) ;
rq_lock_irqsave ( rq , & rf ) ;
update_rq_clock ( rq ) ;
if ( rq - > nr_running ! = 1 | | rq_has_pinned_tasks ( rq ) ) {
WARN ( true , " Dying CPU not properly vacated ! " ) ;
dump_rq_tasks ( rq , KERN_WARNING ) ;
}
dl_server_stop ( & rq - > fair_server ) ;
rq_unlock_irqrestore ( rq , & rf ) ;
calc_load_migrate ( rq ) ;
update_max_interval ( ) ;
hrtick_clear ( rq ) ;
sched_core_cpu_dying ( cpu ) ;
return 0 ;
}
# endif / * CONFIG_HOTPLUG_CPU * /
void _ _ init sched_init_smp ( void )
{
sched_init_numa ( NUMA_NO_NODE ) ;
/ *
* There ' s no userspace yet to cause hotplug operations ; hence all the
* CPU masks are stable and all blatant races in the below code cannot
* happen .
* /
sched_domains_mutex_lock ( ) ;
sched_init_domains ( cpu_active_mask ) ;
sched_domains_mutex_unlock ( ) ;
/ * Move init over to a non - isolated CPU * /
if ( set_cpus_allowed_ptr ( current , housekeeping_cpumask ( HK_TYPE_DOMAIN ) ) < 0 )
BUG ( ) ;
current - > flags & = ~ PF_NO_SETAFFINITY ;
sched_init_granularity ( ) ;
init_sched_rt_class ( ) ;
init_sched_dl_class ( ) ;
sched_init_dl_servers ( ) ;
sched_smp_initialized = true ;
}
static int _ _ init migration_init ( void )
{
sched_cpu_starting ( smp_processor_id ( ) ) ;
return 0 ;
}
early_initcall ( migration_init ) ;
int in_sched_functions ( unsigned long addr )
{
return in_lock_functions ( addr ) | |
( addr > = ( unsigned long ) _ _ sched_text_start
& & addr < ( unsigned long ) _ _ sched_text_end ) ;
}
# ifdef CONFIG_CGROUP_SCHED
/ *
* Default task group .
* Every task in system belongs to this group at bootup .
* /
struct task_group root_task_group ;
LIST_HEAD ( task_groups ) ;
/ * Cacheline aligned slab cache for task_group * /
static struct kmem_cache * task_group_cache _ _ ro_after_init ;
# endif
void _ _ init sched_init ( void )
{
unsigned long ptr = 0 ;
int i ;
/ * Make sure the linker didn ' t screw up * /
BUG_ON ( ! sched_class_above ( & stop_sched_class , & dl_sched_class ) ) ;
BUG_ON ( ! sched_class_above ( & dl_sched_class , & rt_sched_class ) ) ;
BUG_ON ( ! sched_class_above ( & rt_sched_class , & fair_sched_class ) ) ;
BUG_ON ( ! sched_class_above ( & fair_sched_class , & idle_sched_class ) ) ;
# ifdef CONFIG_SCHED_CLASS_EXT
BUG_ON ( ! sched_class_above ( & fair_sched_class , & ext_sched_class ) ) ;
BUG_ON ( ! sched_class_above ( & ext_sched_class , & idle_sched_class ) ) ;
# endif
wait_bit_init ( ) ;
# ifdef CONFIG_FAIR_GROUP_SCHED
ptr + = 2 * nr_cpu_ids * sizeof ( void * * ) ;
# endif
# ifdef CONFIG_RT_GROUP_SCHED
ptr + = 2 * nr_cpu_ids * sizeof ( void * * ) ;
# endif
if ( ptr ) {
ptr = ( unsigned long ) kzalloc ( ptr , GFP_NOWAIT ) ;
# ifdef CONFIG_FAIR_GROUP_SCHED
root_task_group . se = ( struct sched_entity * * ) ptr ;
ptr + = nr_cpu_ids * sizeof ( void * * ) ;
root_task_group . cfs_rq = ( struct cfs_rq * * ) ptr ;
ptr + = nr_cpu_ids * sizeof ( void * * ) ;
root_task_group . shares = ROOT_TASK_GROUP_LOAD ;
init_cfs_bandwidth ( & root_task_group . cfs_bandwidth , NULL ) ;
# endif / * CONFIG_FAIR_GROUP_SCHED * /
# ifdef CONFIG_EXT_GROUP_SCHED
scx_tg_init ( & root_task_group ) ;
# endif / * CONFIG_EXT_GROUP_SCHED * /
# ifdef CONFIG_RT_GROUP_SCHED
root_task_group . rt_se = ( struct sched_rt_entity * * ) ptr ;
ptr + = nr_cpu_ids * sizeof ( void * * ) ;
root_task_group . rt_rq = ( struct rt_rq * * ) ptr ;
ptr + = nr_cpu_ids * sizeof ( void * * ) ;
# endif / * CONFIG_RT_GROUP_SCHED * /
}
init_defrootdomain ( ) ;
# ifdef CONFIG_RT_GROUP_SCHED
init_rt_bandwidth ( & root_task_group . rt_bandwidth ,
global_rt_period ( ) , global_rt_runtime ( ) ) ;
# endif / * CONFIG_RT_GROUP_SCHED * /
# ifdef CONFIG_CGROUP_SCHED
task_group_cache = KMEM_CACHE ( task_group , 0 ) ;
list_add ( & root_task_group . list , & task_groups ) ;
INIT_LIST_HEAD ( & root_task_group . children ) ;
INIT_LIST_HEAD ( & root_task_group . siblings ) ;
autogroup_init ( & init_task ) ;
# endif / * CONFIG_CGROUP_SCHED * /
for_each_possible_cpu ( i ) {
struct rq * rq ;
rq = cpu_rq ( i ) ;
raw_spin_lock_init ( & rq - > _ _ lock ) ;
rq - > nr_running = 0 ;
rq - > calc_load_active = 0 ;
rq - > calc_load_update = jiffies + LOAD_FREQ ;
init_cfs_rq ( & rq - > cfs ) ;
init_rt_rq ( & rq - > rt ) ;
init_dl_rq ( & rq - > dl ) ;
# ifdef CONFIG_FAIR_GROUP_SCHED
INIT_LIST_HEAD ( & rq - > leaf_cfs_rq_list ) ;
rq - > tmp_alone_branch = & rq - > leaf_cfs_rq_list ;
/ *
* How much CPU bandwidth does root_task_group get ?
*
* In case of task - groups formed through the cgroup filesystem , it
* gets 100 % of the CPU resources in the system . This overall
* system CPU resource is divided among the tasks of
* root_task_group and its child task - groups in a fair manner ,
* based on each entity ' s ( task or task - group ' s ) weight
* ( se - > load . weight ) .
*
* In other words , if root_task_group has 10 tasks of weight
* 1024 ) and two child groups A0 and A1 ( of weight 1024 each ) ,
* then A0 ' s share of the CPU resource is :
*
* A0 ' s bandwidth = 1024 / ( 10 * 1024 + 1024 + 1024 ) = 8 . 33 %
*
* We achieve this by letting root_task_group ' s tasks sit
* directly in rq - > cfs ( i . e root_task_group - > se [ ] = NULL ) .
* /
init_tg_cfs_entry ( & root_task_group , & rq - > cfs , NULL , i , NULL ) ;
# endif / * CONFIG_FAIR_GROUP_SCHED * /
# ifdef CONFIG_RT_GROUP_SCHED
/ *
* This is required for init cpu because rt . c : _ _ enable_runtime ( )
* starts working after scheduler_running , which is not the case
* yet .
* /
rq - > rt . rt_runtime = global_rt_runtime ( ) ;
init_tg_rt_entry ( & root_task_group , & rq - > rt , NULL , i , NULL ) ;
# endif
rq - > sd = NULL ;
rq - > rd = NULL ;
rq - > cpu_capacity = SCHED_CAPACITY_SCALE ;
rq - > balance_callback = & balance_push_callback ;
rq - > active_balance = 0 ;
rq - > next_balance = jiffies ;
rq - > push_cpu = 0 ;
rq - > cpu = i ;
rq - > online = 0 ;
rq - > idle_stamp = 0 ;
rq - > avg_idle = 2 * sysctl_sched_migration_cost ;
rq - > max_idle_balance_cost = sysctl_sched_migration_cost ;
INIT_LIST_HEAD ( & rq - > cfs_tasks ) ;
rq_attach_root ( rq , & def_root_domain ) ;
# ifdef CONFIG_NO_HZ_COMMON
rq - > last_blocked_load_update_tick = jiffies ;
atomic_set ( & rq - > nohz_flags , 0 ) ;
INIT_CSD ( & rq - > nohz_csd , nohz_csd_func , rq ) ;
# endif
# ifdef CONFIG_HOTPLUG_CPU
rcuwait_init ( & rq - > hotplug_wait ) ;
# endif
hrtick_rq_init ( rq ) ;
atomic_set ( & rq - > nr_iowait , 0 ) ;
fair_server_init ( rq ) ;
# ifdef CONFIG_SCHED_CORE
rq - > core = rq ;
rq - > core_pick = NULL ;
rq - > core_dl_server = NULL ;
rq - > core_enabled = 0 ;
rq - > core_tree = RB_ROOT ;
rq - > core_forceidle_count = 0 ;
rq - > core_forceidle_occupation = 0 ;
rq - > core_forceidle_start = 0 ;
rq - > core_cookie = 0 UL ;
# endif
zalloc_cpumask_var_node ( & rq - > scratch_mask , GFP_KERNEL , cpu_to_node ( i ) ) ;
}
set_load_weight ( & init_task , false ) ;
init_task . se . slice = sysctl_sched_base_slice ,
/ *
* The boot idle thread does lazy MMU switching as well :
* /
mmgrab_lazy_tlb ( & init_mm ) ;
enter_lazy_tlb ( & init_mm , current ) ;
/ *
* The idle task doesn ' t need the kthread struct to function , but it
* is dressed up as a per - CPU kthread and thus needs to play the part
* if we want to avoid special - casing it in code that deals with per - CPU
* kthreads .
* /
WARN_ON ( ! set_kthread_struct ( current ) ) ;
/ *
* Make us the idle thread . Technically , schedule ( ) should not be
* called from this thread , however somewhere below it might be ,
* but because we are the idle thread , we just pick up running again
* when this runqueue becomes " idle " .
* /
_ _ sched_fork ( 0 , current ) ;
init_idle ( current , smp_processor_id ( ) ) ;
calc_load_update = jiffies + LOAD_FREQ ;
idle_thread_set_boot_cpu ( ) ;
balance_push_set ( smp_processor_id ( ) , false ) ;
init_sched_fair_class ( ) ;
init_sched_ext_class ( ) ;
psi_init ( ) ;
init_uclamp ( ) ;
preempt_dynamic_init ( ) ;
scheduler_running = 1 ;
}
# ifdef CONFIG_DEBUG_ATOMIC_SLEEP
void _ _ might_sleep ( const char * file , int line )
{
unsigned int state = get_current_state ( ) ;
/ *
* Blocking primitives will set ( and therefore destroy ) current - > state ,
* since we will exit with TASK_RUNNING make sure we enter with it ,
* otherwise we will destroy state .
* /
WARN_ONCE ( state ! = TASK_RUNNING & & current - > task_state_change ,
" do not call blocking ops when ! TASK_RUNNING ; "
" state = % x set at [ < % p > ] % pS \ n " , state ,
( void * ) current - > task_state_change ,
( void * ) current - > task_state_change ) ;
_ _ might_resched ( file , line , 0 ) ;
}
EXPORT_SYMBOL ( _ _ might_sleep ) ;
static void print_preempt_disable_ip ( int preempt_offset , unsigned long ip )
{
if ( ! IS_ENABLED ( CONFIG_DEBUG_PREEMPT ) )
return ;
if ( preempt_count ( ) = = preempt_offset )
return ;
pr_err ( " Preemption disabled at : " ) ;
print_ip_sym ( KERN_ERR , ip ) ;
}
static inline bool resched_offsets_ok ( unsigned int offsets )
{
unsigned int nested = preempt_count ( ) ;
nested + = rcu_preempt_depth ( ) < < MIGHT_RESCHED_RCU_SHIFT ;
return nested = = offsets ;
}
void _ _ might_resched ( const char * file , int line , unsigned int offsets )
{
/ * Ratelimiting timestamp : * /
static unsigned long prev_jiffy ;
unsigned long preempt_disable_ip ;
/ * WARN_ON_ONCE ( ) by default , no rate limit required : * /
rcu_sleep_check ( ) ;
if ( ( resched_offsets_ok ( offsets ) & & ! irqs_disabled ( ) & &
! is_idle_task ( current ) & & ! current - > non_block_count ) | |
system_state = = SYSTEM_BOOTING | | system_state > SYSTEM_RUNNING | |
oops_in_progress )
return ;
if ( time_before ( jiffies , prev_jiffy + HZ ) & & prev_jiffy )
return ;
prev_jiffy = jiffies ;
/ * Save this before calling printk ( ) , since that will clobber it : * /
preempt_disable_ip = get_preempt_disable_ip ( current ) ;
pr_err ( " BUG : sleeping function called from invalid context at % s : % d \ n " ,
file , line ) ;
pr_err ( " in_atomic ( ) : % d , irqs_disabled ( ) : % d , non_block : % d , pid : % d , name : % s \ n " ,
in_atomic ( ) , irqs_disabled ( ) , current - > non_block_count ,
current - > pid , current - > comm ) ;
pr_err ( " preempt_count : % x , expected : % x \ n " , preempt_count ( ) ,
offsets & MIGHT_RESCHED_PREEMPT_MASK ) ;
if ( IS_ENABLED ( CONFIG_PREEMPT_RCU ) ) {
pr_err ( " RCU nest depth : % d , expected : % u \ n " ,
rcu_preempt_depth ( ) , offsets > > MIGHT_RESCHED_RCU_SHIFT ) ;
}
if ( task_stack_end_corrupted ( current ) )
pr_emerg ( " Thread overran stack , or stack corrupted \ n " ) ;
debug_show_held_locks ( current ) ;
if ( irqs_disabled ( ) )
print_irqtrace_events ( current ) ;
print_preempt_disable_ip ( offsets & MIGHT_RESCHED_PREEMPT_MASK ,
preempt_disable_ip ) ;
dump_stack ( ) ;
add_taint ( TAINT_WARN , LOCKDEP_STILL_OK ) ;
}
EXPORT_SYMBOL ( _ _ might_resched ) ;
void _ _ cant_sleep ( const char * file , int line , int preempt_offset )
{
static unsigned long prev_jiffy ;
if ( irqs_disabled ( ) )
return ;
if ( ! IS_ENABLED ( CONFIG_PREEMPT_COUNT ) )
return ;
if ( preempt_count ( ) > preempt_offset )
return ;
if ( time_before ( jiffies , prev_jiffy + HZ ) & & prev_jiffy )
return ;
prev_jiffy = jiffies ;
printk ( KERN_ERR " BUG : assuming atomic context at % s : % d \ n " , file , line ) ;
printk ( KERN_ERR " in_atomic ( ) : % d , irqs_disabled ( ) : % d , pid : % d , name : % s \ n " ,
in_atomic ( ) , irqs_disabled ( ) ,
current - > pid , current - > comm ) ;
debug_show_held_locks ( current ) ;
dump_stack ( ) ;
add_taint ( TAINT_WARN , LOCKDEP_STILL_OK ) ;
}
EXPORT_SYMBOL_GPL ( _ _ cant_sleep ) ;
# ifdef CONFIG_SMP
void _ _ cant_migrate ( const char * file , int line )
{
static unsigned long prev_jiffy ;
if ( irqs_disabled ( ) )
return ;
if ( is_migration_disabled ( current ) )
return ;
if ( ! IS_ENABLED ( CONFIG_PREEMPT_COUNT ) )
return ;
if ( preempt_count ( ) > 0 )
return ;
if ( time_before ( jiffies , prev_jiffy + HZ ) & & prev_jiffy )
return ;
prev_jiffy = jiffies ;
pr_err ( " BUG : assuming non migratable context at % s : % d \ n " , file , line ) ;
pr_err ( " in_atomic ( ) : % d , irqs_disabled ( ) : % d , migration_disabled ( ) % u pid : % d , name : % s \ n " ,
in_atomic ( ) , irqs_disabled ( ) , is_migration_disabled ( current ) ,
current - > pid , current - > comm ) ;
debug_show_held_locks ( current ) ;
dump_stack ( ) ;
add_taint ( TAINT_WARN , LOCKDEP_STILL_OK ) ;
}
EXPORT_SYMBOL_GPL ( _ _ cant_migrate ) ;
# endif / * CONFIG_SMP * /
# endif / * CONFIG_DEBUG_ATOMIC_SLEEP * /
# ifdef CONFIG_MAGIC_SYSRQ
void normalize_rt_tasks ( void )
{
struct task_struct * g , * p ;
struct sched_attr attr = {
. sched_policy = SCHED_NORMAL ,
} ;
read_lock ( & tasklist_lock ) ;
for_each_process_thread ( g , p ) {
/ *
* Only normalize user tasks :
* /
if ( p - > flags & PF_KTHREAD )
continue ;
p - > se . exec_start = 0 ;
schedstat_set ( p - > stats . wait_start , 0 ) ;
schedstat_set ( p - > stats . sleep_start , 0 ) ;
schedstat_set ( p - > stats . block_start , 0 ) ;
if ( ! rt_or_dl_task ( p ) ) {
/ *
* Renice negative nice level userspace
* tasks back to 0 :
* /
if ( task_nice ( p ) < 0 )
set_user_nice ( p , 0 ) ;
continue ;
}
_ _ sched_setscheduler ( p , & attr , false , false ) ;
}
read_unlock ( & tasklist_lock ) ;
}
# endif / * CONFIG_MAGIC_SYSRQ * /
# ifdef CONFIG_KGDB_KDB
/ *
* These functions are only useful for KDB .
*
* They can only be called when the whole system has been
* stopped - every CPU needs to be quiescent , and no scheduling
* activity can take place . Using them for anything else would
* be a serious bug , and as a result , they aren ' t even visible
* under any other configuration .
* /
/ * *
* curr_task - return the current task for a given CPU .
* @ cpu : the processor in question .
*
* ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED !
*
* Return : The current task for @ cpu .
* /
struct task_struct * curr_task ( int cpu )
{
return cpu_curr ( cpu ) ;
}
# endif / * CONFIG_KGDB_KDB * /
# ifdef CONFIG_CGROUP_SCHED
/ * task_group_lock serializes the addition / removal of task groups * /
static DEFINE_SPINLOCK ( task_group_lock ) ;
static inline void alloc_uclamp_sched_group ( struct task_group * tg ,
struct task_group * parent )
{
# ifdef CONFIG_UCLAMP_TASK_GROUP
enum uclamp_id clamp_id ;
for_each_clamp_id ( clamp_id ) {
uclamp_se_set ( & tg - > uclamp_req [ clamp_id ] ,
uclamp_none ( clamp_id ) , false ) ;
tg - > uclamp [ clamp_id ] = parent - > uclamp [ clamp_id ] ;
}
# endif
}
static void sched_free_group ( struct task_group * tg )
{
free_fair_sched_group ( tg ) ;
free_rt_sched_group ( tg ) ;
autogroup_free ( tg ) ;
kmem_cache_free ( task_group_cache , tg ) ;
}
static void sched_free_group_rcu ( struct rcu_head * rcu )
{
sched_free_group ( container_of ( rcu , struct task_group , rcu ) ) ;
}
static void sched_unregister_group ( struct task_group * tg )
{
unregister_fair_sched_group ( tg ) ;
unregister_rt_sched_group ( tg ) ;
/ *
* We have to wait for yet another RCU grace period to expire , as
* print_cfs_stats ( ) might run concurrently .
* /
call_rcu ( & tg - > rcu , sched_free_group_rcu ) ;
}
/ * allocate runqueue etc for a new task group * /
struct task_group * sched_create_group ( struct task_group * parent )
{
struct task_group * tg ;
tg = kmem_cache_alloc ( task_group_cache , GFP_KERNEL | _ _ GFP_ZERO ) ;
if ( ! tg )
return ERR_PTR ( - ENOMEM ) ;
if ( ! alloc_fair_sched_group ( tg , parent ) )
goto err ;
if ( ! alloc_rt_sched_group ( tg , parent ) )
goto err ;
scx_tg_init ( tg ) ;
alloc_uclamp_sched_group ( tg , parent ) ;
return tg ;
err :
sched_free_group ( tg ) ;
return ERR_PTR ( - ENOMEM ) ;
}
void sched_online_group ( struct task_group * tg , struct task_group * parent )
{
unsigned long flags ;
spin_lock_irqsave ( & task_group_lock , flags ) ;
list_add_tail_rcu ( & tg - > list , & task_groups ) ;
/ * Root should already exist : * /
WARN_ON ( ! parent ) ;
tg - > parent = parent ;
INIT_LIST_HEAD ( & tg - > children ) ;
list_add_rcu ( & tg - > siblings , & parent - > children ) ;
spin_unlock_irqrestore ( & task_group_lock , flags ) ;
online_fair_sched_group ( tg ) ;
}
/ * RCU callback to free various structures associated with a task group * /
static void sched_unregister_group_rcu ( struct rcu_head * rhp )
{
/ * Now it should be safe to free those cfs_rqs : * /
sched_unregister_group ( container_of ( rhp , struct task_group , rcu ) ) ;
}
void sched_destroy_group ( struct task_group * tg )
{
/ * Wait for possible concurrent references to cfs_rqs complete : * /
call_rcu ( & tg - > rcu , sched_unregister_group_rcu ) ;
}
void sched_release_group ( struct task_group * tg )
{
unsigned long flags ;
/ *
* Unlink first , to avoid walk_tg_tree_from ( ) from finding us ( via
* sched_cfs_period_timer ( ) ) .
*
* For this to be effective , we have to wait for all pending users of
* this task group to leave their RCU critical section to ensure no new
* user will see our dying task group any more . Specifically ensure
* that tg_unthrottle_up ( ) won ' t add decayed cfs_rq ' s to it .
*
* We therefore defer calling unregister_fair_sched_group ( ) to
* sched_unregister_group ( ) which is guarantied to get called only after the
* current RCU grace period has expired .
* /
spin_lock_irqsave ( & task_group_lock , flags ) ;
list_del_rcu ( & tg - > list ) ;
list_del_rcu ( & tg - > siblings ) ;
spin_unlock_irqrestore ( & task_group_lock , flags ) ;
}
static void sched_change_group ( struct task_struct * tsk )
{
struct task_group * tg ;
/ *
* All callers are synchronized by task_rq_lock ( ) ; we do not use RCU
* which is pointless here . Thus , we pass " true " to task_css_check ( )
* to prevent lockdep warnings .
* /
tg = container_of ( task_css_check ( tsk , cpu_cgrp_id , true ) ,
struct task_group , css ) ;
tg = autogroup_task_group ( tsk , tg ) ;
tsk - > sched_task_group = tg ;
# ifdef CONFIG_FAIR_GROUP_SCHED
if ( tsk - > sched_class - > task_change_group )
tsk - > sched_class - > task_change_group ( tsk ) ;
else
# endif
set_task_rq ( tsk , task_cpu ( tsk ) ) ;
}
/ *
* Change task ' s runqueue when it moves between groups .
*
* The caller of this function should have put the task in its new group by
* now . This function just updates tsk - > se . cfs_rq and tsk - > se . parent to reflect
* its new group .
* /
void sched_move_task ( struct task_struct * tsk , bool for_autogroup )
{
int queued , running , queue_flags =
DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK ;
struct rq * rq ;
CLASS ( task_rq_lock , rq_guard ) ( tsk ) ;
rq = rq_guard . rq ;
update_rq_clock ( rq ) ;
running = task_current_donor ( rq , tsk ) ;
queued = task_on_rq_queued ( tsk ) ;
if ( queued )
dequeue_task ( rq , tsk , queue_flags ) ;
if ( running )
put_prev_task ( rq , tsk ) ;
sched_change_group ( tsk ) ;
if ( ! for_autogroup )
scx_cgroup_move_task ( tsk ) ;
if ( queued )
enqueue_task ( rq , tsk , queue_flags ) ;
if ( running ) {
set_next_task ( rq , tsk ) ;
/ *
* After changing group , the running task may have joined a
* throttled one but it ' s still the running task . Trigger a
* resched to make sure that task can still run .
* /
resched_curr ( rq ) ;
}
}
static struct cgroup_subsys_state *
cpu_cgroup_css_alloc ( struct cgroup_subsys_state * parent_css )
{
struct task_group * parent = css_tg ( parent_css ) ;
struct task_group * tg ;
if ( ! parent ) {
/ * This is early initialization for the top cgroup * /
return & root_task_group . css ;
}
tg = sched_create_group ( parent ) ;
if ( IS_ERR ( tg ) )
return ERR_PTR ( - ENOMEM ) ;
return & tg - > css ;
}
/ * Expose task group only after completing cgroup initialization * /
static int cpu_cgroup_css_online ( struct cgroup_subsys_state * css )
{
struct task_group * tg = css_tg ( css ) ;
struct task_group * parent = css_tg ( css - > parent ) ;
int ret ;
ret = scx_tg_online ( tg ) ;
if ( ret )
return ret ;
if ( parent )
sched_online_group ( tg , parent ) ;
# ifdef CONFIG_UCLAMP_TASK_GROUP
/ * Propagate the effective uclamp value for the new group * /
guard ( mutex ) ( & uclamp_mutex ) ;
guard ( rcu ) ( ) ;
cpu_util_update_eff ( css ) ;
# endif
return 0 ;
}
static void cpu_cgroup_css_offline ( struct cgroup_subsys_state * css )
{
struct task_group * tg = css_tg ( css ) ;
scx_tg_offline ( tg ) ;
}
static void cpu_cgroup_css_released ( struct cgroup_subsys_state * css )
{
struct task_group * tg = css_tg ( css ) ;
sched_release_group ( tg ) ;
}
static void cpu_cgroup_css_free ( struct cgroup_subsys_state * css )
{
struct task_group * tg = css_tg ( css ) ;
/ *
* Relies on the RCU grace period between css_released ( ) and this .
* /
sched_unregister_group ( tg ) ;
}
static int cpu_cgroup_can_attach ( struct cgroup_taskset * tset )
{
# ifdef CONFIG_RT_GROUP_SCHED
struct task_struct * task ;
struct cgroup_subsys_state * css ;
if ( ! rt_group_sched_enabled ( ) )
goto scx_check ;
cgroup_taskset_for_each ( task , css , tset ) {
if ( ! sched_rt_can_attach ( css_tg ( css ) , task ) )
return - EINVAL ;
}
scx_check :
# endif / * CONFIG_RT_GROUP_SCHED * /
return scx_cgroup_can_attach ( tset ) ;
}
static void cpu_cgroup_attach ( struct cgroup_taskset * tset )
{
struct task_struct * task ;
struct cgroup_subsys_state * css ;
cgroup_taskset_for_each ( task , css , tset )
sched_move_task ( task , false ) ;
scx_cgroup_finish_attach ( ) ;
}
static void cpu_cgroup_cancel_attach ( struct cgroup_taskset * tset )
{
scx_cgroup_cancel_attach ( tset ) ;
}
# ifdef CONFIG_UCLAMP_TASK_GROUP
static void cpu_util_update_eff ( struct cgroup_subsys_state * css )
{
struct cgroup_subsys_state * top_css = css ;
struct uclamp_se * uc_parent = NULL ;
struct uclamp_se * uc_se = NULL ;
unsigned int eff [ UCLAMP_CNT ] ;
enum uclamp_id clamp_id ;
unsigned int clamps ;
lockdep_assert_held ( & uclamp_mutex ) ;
WARN_ON_ONCE ( ! rcu_read_lock_held ( ) ) ;
css_for_each_descendant_pre ( css , top_css ) {
uc_parent = css_tg ( css ) - > parent
? css_tg ( css ) - > parent - > uclamp : NULL ;
for_each_clamp_id ( clamp_id ) {
/ * Assume effective clamps matches requested clamps * /
eff [ clamp_id ] = css_tg ( css ) - > uclamp_req [ clamp_id ] . value ;
/ * Cap effective clamps with parent ' s effective clamps * /
if ( uc_parent & &
eff [ clamp_id ] > uc_parent [ clamp_id ] . value ) {
eff [ clamp_id ] = uc_parent [ clamp_id ] . value ;
}
}
/ * Ensure protection is always capped by limit * /
eff [ UCLAMP_MIN ] = min ( eff [ UCLAMP_MIN ] , eff [ UCLAMP_MAX ] ) ;
/ * Propagate most restrictive effective clamps * /
clamps = 0 x0 ;
uc_se = css_tg ( css ) - > uclamp ;
for_each_clamp_id ( clamp_id ) {
if ( eff [ clamp_id ] = = uc_se [ clamp_id ] . value )
continue ;
uc_se [ clamp_id ] . value = eff [ clamp_id ] ;
uc_se [ clamp_id ] . bucket_id = uclamp_bucket_id ( eff [ clamp_id ] ) ;
clamps | = ( 0 x1 < < clamp_id ) ;
}
if ( ! clamps ) {
css = css_rightmost_descendant ( css ) ;
continue ;
}
/ * Immediately update descendants RUNNABLE tasks * /
uclamp_update_active_tasks ( css ) ;
}
}
/ *
* Integer 10 ^ N with a given N exponent by casting to integer the literal " 1 eN "
* C expression . Since there is no way to convert a macro argument ( N ) into a
* character constant , use two levels of macros .
* /
# define _ POW10 ( exp ) ( ( unsigned int ) 1 e # # exp )
# define POW10 ( exp ) _ POW10 ( exp )
struct uclamp_request {
# define UCLAMP_PERCENT_SHIFT 2
# define UCLAMP_PERCENT_SCALE ( 100 * POW10 ( UCLAMP_PERCENT_SHIFT ) )
s64 percent ;
u64 util ;
int ret ;
} ;
static inline struct uclamp_request
capacity_from_percent ( char * buf )
{
struct uclamp_request req = {
. percent = UCLAMP_PERCENT_SCALE ,
. util = SCHED_CAPACITY_SCALE ,
. ret = 0 ,
} ;
buf = strim ( buf ) ;
if ( strcmp ( buf , " max " ) ) {
req . ret = cgroup_parse_float ( buf , UCLAMP_PERCENT_SHIFT ,
& req . percent ) ;
if ( req . ret )
return req ;
if ( ( u64 ) req . percent > UCLAMP_PERCENT_SCALE ) {
req . ret = - ERANGE ;
return req ;
}
req . util = req . percent < < SCHED_CAPACITY_SHIFT ;
req . util = DIV_ROUND_CLOSEST_ULL ( req . util , UCLAMP_PERCENT_SCALE ) ;
}
return req ;
}
static ssize_t cpu_uclamp_write ( struct kernfs_open_file * of , char * buf ,
size_t nbytes , loff_t off ,
enum uclamp_id clamp_id )
{
struct uclamp_request req ;
struct task_group * tg ;
req = capacity_from_percent ( buf ) ;
if ( req . ret )
return req . ret ;
sched_uclamp_enable ( ) ;
guard ( mutex ) ( & uclamp_mutex ) ;
guard ( rcu ) ( ) ;
tg = css_tg ( of_css ( of ) ) ;
if ( tg - > uclamp_req [ clamp_id ] . value ! = req . util )
uclamp_se_set ( & tg - > uclamp_req [ clamp_id ] , req . util , false ) ;
/ *
* Because of not recoverable conversion rounding we keep track of the
* exact requested value
* /
tg - > uclamp_pct [ clamp_id ] = req . percent ;
/ * Update effective clamps to track the most restrictive value * /
cpu_util_update_eff ( of_css ( of ) ) ;
return nbytes ;
}
static ssize_t cpu_uclamp_min_write ( struct kernfs_open_file * of ,
char * buf , size_t nbytes ,
loff_t off )
{
return cpu_uclamp_write ( of , buf , nbytes , off , UCLAMP_MIN ) ;
}
static ssize_t cpu_uclamp_max_write ( struct kernfs_open_file * of ,
char * buf , size_t nbytes ,
loff_t off )
{
return cpu_uclamp_write ( of , buf , nbytes , off , UCLAMP_MAX ) ;
}
static inline void cpu_uclamp_print ( struct seq_file * sf ,
enum uclamp_id clamp_id )
{
struct task_group * tg ;
u64 util_clamp ;
u64 percent ;
u32 rem ;
scoped_guard ( rcu ) {
tg = css_tg ( seq_css ( sf ) ) ;
util_clamp = tg - > uclamp_req [ clamp_id ] . value ;
}
if ( util_clamp = = SCHED_CAPACITY_SCALE ) {
seq_puts ( sf , " max \ n " ) ;
return ;
}
percent = tg - > uclamp_pct [ clamp_id ] ;
percent = div_u64_rem ( percent , POW10 ( UCLAMP_PERCENT_SHIFT ) , & rem ) ;
seq_printf ( sf , " % llu . % 0 * u \ n " , percent , UCLAMP_PERCENT_SHIFT , rem ) ;
}
static int cpu_uclamp_min_show ( struct seq_file * sf , void * v )
{
cpu_uclamp_print ( sf , UCLAMP_MIN ) ;
return 0 ;
}
static int cpu_uclamp_max_show ( struct seq_file * sf , void * v )
{
cpu_uclamp_print ( sf , UCLAMP_MAX ) ;
return 0 ;
}
# endif / * CONFIG_UCLAMP_TASK_GROUP * /
# ifdef CONFIG_GROUP_SCHED_WEIGHT
static unsigned long tg_weight ( struct task_group * tg )
{
# ifdef CONFIG_FAIR_GROUP_SCHED
return scale_load_down ( tg - > shares ) ;
# else
return sched_weight_from_cgroup ( tg - > scx . weight ) ;
# endif
}
static int cpu_shares_write_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cftype , u64 shareval )
{
int ret ;
if ( shareval > scale_load_down ( ULONG_MAX ) )
shareval = MAX_SHARES ;
ret = sched_group_set_shares ( css_tg ( css ) , scale_load ( shareval ) ) ;
if ( ! ret )
scx_group_set_weight ( css_tg ( css ) ,
sched_weight_to_cgroup ( shareval ) ) ;
return ret ;
}
static u64 cpu_shares_read_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
return tg_weight ( css_tg ( css ) ) ;
}
# endif / * CONFIG_GROUP_SCHED_WEIGHT * /
# ifdef CONFIG_CFS_BANDWIDTH
static DEFINE_MUTEX ( cfs_constraints_mutex ) ;
static int _ _ cfs_schedulable ( struct task_group * tg , u64 period , u64 runtime ) ;
static int tg_set_cfs_bandwidth ( struct task_group * tg ,
u64 period_us , u64 quota_us , u64 burst_us )
{
int i , ret = 0 , runtime_enabled , runtime_was_enabled ;
struct cfs_bandwidth * cfs_b = & tg - > cfs_bandwidth ;
u64 period , quota , burst ;
period = ( u64 ) period_us * NSEC_PER_USEC ;
if ( quota_us = = RUNTIME_INF )
quota = RUNTIME_INF ;
else
quota = ( u64 ) quota_us * NSEC_PER_USEC ;
burst = ( u64 ) burst_us * NSEC_PER_USEC ;
/ *
* Prevent race between setting of cfs_rq - > runtime_enabled and
* unthrottle_offline_cfs_rqs ( ) .
* /
guard ( cpus_read_lock ) ( ) ;
guard ( mutex ) ( & cfs_constraints_mutex ) ;
ret = _ _ cfs_schedulable ( tg , period , quota ) ;
if ( ret )
return ret ;
runtime_enabled = quota ! = RUNTIME_INF ;
runtime_was_enabled = cfs_b - > quota ! = RUNTIME_INF ;
/ *
* If we need to toggle cfs_bandwidth_used , off - > on must occur
* before making related changes , and on - > off must occur afterwards
* /
if ( runtime_enabled & & ! runtime_was_enabled )
cfs_bandwidth_usage_inc ( ) ;
scoped_guard ( raw_spinlock_irq , & cfs_b - > lock ) {
cfs_b - > period = ns_to_ktime ( period ) ;
cfs_b - > quota = quota ;
cfs_b - > burst = burst ;
_ _ refill_cfs_bandwidth_runtime ( cfs_b ) ;
/ *
* Restart the period timer ( if active ) to handle new
* period expiry :
* /
if ( runtime_enabled )
start_cfs_bandwidth ( cfs_b ) ;
}
for_each_online_cpu ( i ) {
struct cfs_rq * cfs_rq = tg - > cfs_rq [ i ] ;
struct rq * rq = cfs_rq - > rq ;
guard ( rq_lock_irq ) ( rq ) ;
cfs_rq - > runtime_enabled = runtime_enabled ;
cfs_rq - > runtime_remaining = 0 ;
if ( cfs_rq - > throttled )
unthrottle_cfs_rq ( cfs_rq ) ;
}
if ( runtime_was_enabled & & ! runtime_enabled )
cfs_bandwidth_usage_dec ( ) ;
return 0 ;
}
static u64 tg_get_cfs_period ( struct task_group * tg )
{
u64 cfs_period_us ;
cfs_period_us = ktime_to_ns ( tg - > cfs_bandwidth . period ) ;
do_div ( cfs_period_us , NSEC_PER_USEC ) ;
return cfs_period_us ;
}
static u64 tg_get_cfs_quota ( struct task_group * tg )
{
u64 quota_us ;
if ( tg - > cfs_bandwidth . quota = = RUNTIME_INF )
return RUNTIME_INF ;
quota_us = tg - > cfs_bandwidth . quota ;
do_div ( quota_us , NSEC_PER_USEC ) ;
return quota_us ;
}
static u64 tg_get_cfs_burst ( struct task_group * tg )
{
u64 burst_us ;
burst_us = tg - > cfs_bandwidth . burst ;
do_div ( burst_us , NSEC_PER_USEC ) ;
return burst_us ;
}
struct cfs_schedulable_data {
struct task_group * tg ;
u64 period , quota ;
} ;
/ *
* normalize group quota / period to be quota / max_period
* note : units are usecs
* /
static u64 normalize_cfs_quota ( struct task_group * tg ,
struct cfs_schedulable_data * d )
{
u64 quota , period ;
if ( tg = = d - > tg ) {
period = d - > period ;
quota = d - > quota ;
} else {
period = tg_get_cfs_period ( tg ) ;
quota = tg_get_cfs_quota ( tg ) ;
}
/ * note : these should typically be equivalent * /
if ( quota = = RUNTIME_INF | | quota = = - 1 )
return RUNTIME_INF ;
return to_ratio ( period , quota ) ;
}
static int tg_cfs_schedulable_down ( struct task_group * tg , void * data )
{
struct cfs_schedulable_data * d = data ;
struct cfs_bandwidth * cfs_b = & tg - > cfs_bandwidth ;
s64 quota = 0 , parent_quota = - 1 ;
if ( ! tg - > parent ) {
quota = RUNTIME_INF ;
} else {
struct cfs_bandwidth * parent_b = & tg - > parent - > cfs_bandwidth ;
quota = normalize_cfs_quota ( tg , d ) ;
parent_quota = parent_b - > hierarchical_quota ;
/ *
* Ensure max ( child_quota ) < = parent_quota . On cgroup2 ,
* always take the non - RUNTIME_INF min . On cgroup1 , only
* inherit when no limit is set . In both cases this is used
* by the scheduler to determine if a given CFS task has a
* bandwidth constraint at some higher level .
* /
if ( cgroup_subsys_on_dfl ( cpu_cgrp_subsys ) ) {
if ( quota = = RUNTIME_INF )
quota = parent_quota ;
else if ( parent_quota ! = RUNTIME_INF )
quota = min ( quota , parent_quota ) ;
} else {
if ( quota = = RUNTIME_INF )
quota = parent_quota ;
else if ( parent_quota ! = RUNTIME_INF & & quota > parent_quota )
return - EINVAL ;
}
}
cfs_b - > hierarchical_quota = quota ;
return 0 ;
}
static int _ _ cfs_schedulable ( struct task_group * tg , u64 period , u64 quota )
{
struct cfs_schedulable_data data = {
. tg = tg ,
. period = period ,
. quota = quota ,
} ;
if ( quota ! = RUNTIME_INF ) {
do_div ( data . period , NSEC_PER_USEC ) ;
do_div ( data . quota , NSEC_PER_USEC ) ;
}
guard ( rcu ) ( ) ;
return walk_tg_tree ( tg_cfs_schedulable_down , tg_nop , & data ) ;
}
static int cpu_cfs_stat_show ( struct seq_file * sf , void * v )
{
struct task_group * tg = css_tg ( seq_css ( sf ) ) ;
struct cfs_bandwidth * cfs_b = & tg - > cfs_bandwidth ;
seq_printf ( sf , " nr_periods % d \ n " , cfs_b - > nr_periods ) ;
seq_printf ( sf , " nr_throttled % d \ n " , cfs_b - > nr_throttled ) ;
seq_printf ( sf , " throttled_time % llu \ n " , cfs_b - > throttled_time ) ;
if ( schedstat_enabled ( ) & & tg ! = & root_task_group ) {
struct sched_statistics * stats ;
u64 ws = 0 ;
int i ;
for_each_possible_cpu ( i ) {
stats = _ _ schedstats_from_se ( tg - > se [ i ] ) ;
ws + = schedstat_val ( stats - > wait_sum ) ;
}
seq_printf ( sf , " wait_sum % llu \ n " , ws ) ;
}
seq_printf ( sf , " nr_bursts % d \ n " , cfs_b - > nr_burst ) ;
seq_printf ( sf , " burst_time % llu \ n " , cfs_b - > burst_time ) ;
return 0 ;
}
static u64 throttled_time_self ( struct task_group * tg )
{
int i ;
u64 total = 0 ;
for_each_possible_cpu ( i ) {
total + = READ_ONCE ( tg - > cfs_rq [ i ] - > throttled_clock_self_time ) ;
}
return total ;
}
static int cpu_cfs_local_stat_show ( struct seq_file * sf , void * v )
{
struct task_group * tg = css_tg ( seq_css ( sf ) ) ;
seq_printf ( sf , " throttled_time % llu \ n " , throttled_time_self ( tg ) ) ;
return 0 ;
}
# endif / * CONFIG_CFS_BANDWIDTH * /
# ifdef CONFIG_GROUP_SCHED_BANDWIDTH
const u64 max_bw_quota_period_us = 1 * USEC_PER_SEC ; / * 1 s * /
static const u64 min_bw_quota_period_us = 1 * USEC_PER_MSEC ; / * 1 ms * /
/ * More than 203 days if BW_SHIFT equals 20 . * /
static const u64 max_bw_runtime_us = MAX_BW ;
static void tg_bandwidth ( struct task_group * tg ,
u64 * period_us_p , u64 * quota_us_p , u64 * burst_us_p )
{
# ifdef CONFIG_CFS_BANDWIDTH
if ( period_us_p )
* period_us_p = tg_get_cfs_period ( tg ) ;
if ( quota_us_p )
* quota_us_p = tg_get_cfs_quota ( tg ) ;
if ( burst_us_p )
* burst_us_p = tg_get_cfs_burst ( tg ) ;
# else / * ! CONFIG_CFS_BANDWIDTH * /
if ( period_us_p )
* period_us_p = tg - > scx . bw_period_us ;
if ( quota_us_p )
* quota_us_p = tg - > scx . bw_quota_us ;
if ( burst_us_p )
* burst_us_p = tg - > scx . bw_burst_us ;
# endif / * CONFIG_CFS_BANDWIDTH * /
}
static u64 cpu_period_read_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
u64 period_us ;
tg_bandwidth ( css_tg ( css ) , & period_us , NULL , NULL ) ;
return period_us ;
}
static int tg_set_bandwidth ( struct task_group * tg ,
u64 period_us , u64 quota_us , u64 burst_us )
{
const u64 max_usec = U64_MAX / NSEC_PER_USEC ;
int ret = 0 ;
if ( tg = = & root_task_group )
return - EINVAL ;
/ * Values should survive translation to nsec * /
if ( period_us > max_usec | |
( quota_us ! = RUNTIME_INF & & quota_us > max_usec ) | |
burst_us > max_usec )
return - EINVAL ;
/ *
* Ensure we have some amount of bandwidth every period . This is to
* prevent reaching a state of large arrears when throttled via
* entity_tick ( ) resulting in prolonged exit starvation .
* /
if ( quota_us < min_bw_quota_period_us | |
period_us < min_bw_quota_period_us )
return - EINVAL ;
/ *
* Likewise , bound things on the other side by preventing insane quota
* periods . This also allows us to normalize in computing quota
* feasibility .
* /
if ( period_us > max_bw_quota_period_us )
return - EINVAL ;
/ *
* Bound quota to defend quota against overflow during bandwidth shift .
* /
if ( quota_us ! = RUNTIME_INF & & quota_us > max_bw_runtime_us )
return - EINVAL ;
if ( quota_us ! = RUNTIME_INF & & ( burst_us > quota_us | |
burst_us + quota_us > max_bw_runtime_us ) )
return - EINVAL ;
# ifdef CONFIG_CFS_BANDWIDTH
ret = tg_set_cfs_bandwidth ( tg , period_us , quota_us , burst_us ) ;
# endif / * CONFIG_CFS_BANDWIDTH * /
if ( ! ret )
scx_group_set_bandwidth ( tg , period_us , quota_us , burst_us ) ;
return ret ;
}
static s64 cpu_quota_read_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
u64 quota_us ;
tg_bandwidth ( css_tg ( css ) , NULL , & quota_us , NULL ) ;
return quota_us ; / * ( s64 ) RUNTIME_INF becomes - 1 * /
}
static u64 cpu_burst_read_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
u64 burst_us ;
tg_bandwidth ( css_tg ( css ) , NULL , NULL , & burst_us ) ;
return burst_us ;
}
static int cpu_period_write_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cftype , u64 period_us )
{
struct task_group * tg = css_tg ( css ) ;
u64 quota_us , burst_us ;
tg_bandwidth ( tg , NULL , & quota_us , & burst_us ) ;
return tg_set_bandwidth ( tg , period_us , quota_us , burst_us ) ;
}
static int cpu_quota_write_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cftype , s64 quota_us )
{
struct task_group * tg = css_tg ( css ) ;
u64 period_us , burst_us ;
if ( quota_us < 0 )
quota_us = RUNTIME_INF ;
tg_bandwidth ( tg , & period_us , NULL , & burst_us ) ;
return tg_set_bandwidth ( tg , period_us , quota_us , burst_us ) ;
}
static int cpu_burst_write_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cftype , u64 burst_us )
{
struct task_group * tg = css_tg ( css ) ;
u64 period_us , quota_us ;
tg_bandwidth ( tg , & period_us , & quota_us , NULL ) ;
return tg_set_bandwidth ( tg , period_us , quota_us , burst_us ) ;
}
# endif / * CONFIG_GROUP_SCHED_BANDWIDTH * /
# ifdef CONFIG_RT_GROUP_SCHED
static int cpu_rt_runtime_write ( struct cgroup_subsys_state * css ,
struct cftype * cft , s64 val )
{
return sched_group_set_rt_runtime ( css_tg ( css ) , val ) ;
}
static s64 cpu_rt_runtime_read ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
return sched_group_rt_runtime ( css_tg ( css ) ) ;
}
static int cpu_rt_period_write_uint ( struct cgroup_subsys_state * css ,
struct cftype * cftype , u64 rt_period_us )
{
return sched_group_set_rt_period ( css_tg ( css ) , rt_period_us ) ;
}
static u64 cpu_rt_period_read_uint ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
return sched_group_rt_period ( css_tg ( css ) ) ;
}
# endif / * CONFIG_RT_GROUP_SCHED * /
# ifdef CONFIG_GROUP_SCHED_WEIGHT
static s64 cpu_idle_read_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
return css_tg ( css ) - > idle ;
}
static int cpu_idle_write_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cft , s64 idle )
{
int ret ;
ret = sched_group_set_idle ( css_tg ( css ) , idle ) ;
if ( ! ret )
scx_group_set_idle ( css_tg ( css ) , idle ) ;
return ret ;
}
# endif / * CONFIG_GROUP_SCHED_WEIGHT * /
static struct cftype cpu_legacy_files [ ] = {
# ifdef CONFIG_GROUP_SCHED_WEIGHT
{
. name = " shares " ,
. read_u64 = cpu_shares_read_u64 ,
. write_u64 = cpu_shares_write_u64 ,
} ,
{
. name = " idle " ,
. read_s64 = cpu_idle_read_s64 ,
. write_s64 = cpu_idle_write_s64 ,
} ,
# endif
# ifdef CONFIG_GROUP_SCHED_BANDWIDTH
{
. name = " cfs_period_us " ,
. read_u64 = cpu_period_read_u64 ,
. write_u64 = cpu_period_write_u64 ,
} ,
{
. name = " cfs_quota_us " ,
. read_s64 = cpu_quota_read_s64 ,
. write_s64 = cpu_quota_write_s64 ,
} ,
{
. name = " cfs_burst_us " ,
. read_u64 = cpu_burst_read_u64 ,
. write_u64 = cpu_burst_write_u64 ,
} ,
# endif
# ifdef CONFIG_CFS_BANDWIDTH
{
. name = " stat " ,
. seq_show = cpu_cfs_stat_show ,
} ,
{
. name = " stat . local " ,
. seq_show = cpu_cfs_local_stat_show ,
} ,
# endif
# ifdef CONFIG_UCLAMP_TASK_GROUP
{
. name = " uclamp . min " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. seq_show = cpu_uclamp_min_show ,
. write = cpu_uclamp_min_write ,
} ,
{
. name = " uclamp . max " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. seq_show = cpu_uclamp_max_show ,
. write = cpu_uclamp_max_write ,
} ,
# endif
{ } / * Terminate * /
} ;
# ifdef CONFIG_RT_GROUP_SCHED
static struct cftype rt_group_files [ ] = {
{
. name = " rt_runtime_us " ,
. read_s64 = cpu_rt_runtime_read ,
. write_s64 = cpu_rt_runtime_write ,
} ,
{
. name = " rt_period_us " ,
. read_u64 = cpu_rt_period_read_uint ,
. write_u64 = cpu_rt_period_write_uint ,
} ,
{ } / * Terminate * /
} ;
# ifdef CONFIG_RT_GROUP_SCHED_DEFAULT_DISABLED
DEFINE_STATIC_KEY_FALSE ( rt_group_sched ) ;
# else
DEFINE_STATIC_KEY_TRUE ( rt_group_sched ) ;
# endif
static int _ _ init setup_rt_group_sched ( char * str )
{
long val ;
if ( kstrtol ( str , 0 , & val ) | | val < 0 | | val > 1 ) {
pr_warn ( " Unable to set rt_group_sched \ n " ) ;
return 1 ;
}
if ( val )
static_branch_enable ( & rt_group_sched ) ;
else
static_branch_disable ( & rt_group_sched ) ;
return 1 ;
}
_ _ setup ( " rt_group_sched = " , setup_rt_group_sched ) ;
static int _ _ init cpu_rt_group_init ( void )
{
if ( ! rt_group_sched_enabled ( ) )
return 0 ;
WARN_ON ( cgroup_add_legacy_cftypes ( & cpu_cgrp_subsys , rt_group_files ) ) ;
return 0 ;
}
subsys_initcall ( cpu_rt_group_init ) ;
# endif / * CONFIG_RT_GROUP_SCHED * /
static int cpu_extra_stat_show ( struct seq_file * sf ,
struct cgroup_subsys_state * css )
{
# ifdef CONFIG_CFS_BANDWIDTH
{
struct task_group * tg = css_tg ( css ) ;
struct cfs_bandwidth * cfs_b = & tg - > cfs_bandwidth ;
u64 throttled_usec , burst_usec ;
throttled_usec = cfs_b - > throttled_time ;
do_div ( throttled_usec , NSEC_PER_USEC ) ;
burst_usec = cfs_b - > burst_time ;
do_div ( burst_usec , NSEC_PER_USEC ) ;
seq_printf ( sf , " nr_periods % d \ n "
" nr_throttled % d \ n "
" throttled_usec % llu \ n "
" nr_bursts % d \ n "
" burst_usec % llu \ n " ,
cfs_b - > nr_periods , cfs_b - > nr_throttled ,
throttled_usec , cfs_b - > nr_burst , burst_usec ) ;
}
# endif / * CONFIG_CFS_BANDWIDTH * /
return 0 ;
}
static int cpu_local_stat_show ( struct seq_file * sf ,
struct cgroup_subsys_state * css )
{
# ifdef CONFIG_CFS_BANDWIDTH
{
struct task_group * tg = css_tg ( css ) ;
u64 throttled_self_usec ;
throttled_self_usec = throttled_time_self ( tg ) ;
do_div ( throttled_self_usec , NSEC_PER_USEC ) ;
seq_printf ( sf , " throttled_usec % llu \ n " ,
throttled_self_usec ) ;
}
# endif
return 0 ;
}
# ifdef CONFIG_GROUP_SCHED_WEIGHT
static u64 cpu_weight_read_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
return sched_weight_to_cgroup ( tg_weight ( css_tg ( css ) ) ) ;
}
static int cpu_weight_write_u64 ( struct cgroup_subsys_state * css ,
struct cftype * cft , u64 cgrp_weight )
{
unsigned long weight ;
int ret ;
if ( cgrp_weight < CGROUP_WEIGHT_MIN | | cgrp_weight > CGROUP_WEIGHT_MAX )
return - ERANGE ;
weight = sched_weight_from_cgroup ( cgrp_weight ) ;
ret = sched_group_set_shares ( css_tg ( css ) , scale_load ( weight ) ) ;
if ( ! ret )
scx_group_set_weight ( css_tg ( css ) , cgrp_weight ) ;
return ret ;
}
static s64 cpu_weight_nice_read_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cft )
{
unsigned long weight = tg_weight ( css_tg ( css ) ) ;
int last_delta = INT_MAX ;
int prio , delta ;
/ * find the closest nice value to the current weight * /
for ( prio = 0 ; prio < ARRAY_SIZE ( sched_prio_to_weight ) ; prio + + ) {
delta = abs ( sched_prio_to_weight [ prio ] - weight ) ;
if ( delta > = last_delta )
break ;
last_delta = delta ;
}
return PRIO_TO_NICE ( prio - 1 + MAX_RT_PRIO ) ;
}
static int cpu_weight_nice_write_s64 ( struct cgroup_subsys_state * css ,
struct cftype * cft , s64 nice )
{
unsigned long weight ;
int idx , ret ;
if ( nice < MIN_NICE | | nice > MAX_NICE )
return - ERANGE ;
idx = NICE_TO_PRIO ( nice ) - MAX_RT_PRIO ;
idx = array_index_nospec ( idx , 40 ) ;
weight = sched_prio_to_weight [ idx ] ;
ret = sched_group_set_shares ( css_tg ( css ) , scale_load ( weight ) ) ;
if ( ! ret )
scx_group_set_weight ( css_tg ( css ) ,
sched_weight_to_cgroup ( weight ) ) ;
return ret ;
}
# endif / * CONFIG_GROUP_SCHED_WEIGHT * /
static void _ _ maybe_unused cpu_period_quota_print ( struct seq_file * sf ,
long period , long quota )
{
if ( quota < 0 )
seq_puts ( sf , " max " ) ;
else
seq_printf ( sf , " % ld " , quota ) ;
seq_printf ( sf , " % ld \ n " , period ) ;
}
/ * caller should put the current value in * @ periodp before calling * /
static int _ _ maybe_unused cpu_period_quota_parse ( char * buf , u64 * period_us_p ,
u64 * quota_us_p )
{
char tok [ 21 ] ; / * U64_MAX * /
if ( sscanf ( buf , " % 20 s % llu " , tok , period_us_p ) < 1 )
return - EINVAL ;
if ( sscanf ( tok , " % llu " , quota_us_p ) < 1 ) {
if ( ! strcmp ( tok , " max " ) )
* quota_us_p = RUNTIME_INF ;
else
return - EINVAL ;
}
return 0 ;
}
# ifdef CONFIG_GROUP_SCHED_BANDWIDTH
static int cpu_max_show ( struct seq_file * sf , void * v )
{
struct task_group * tg = css_tg ( seq_css ( sf ) ) ;
u64 period_us , quota_us ;
tg_bandwidth ( tg , & period_us , & quota_us , NULL ) ;
cpu_period_quota_print ( sf , period_us , quota_us ) ;
return 0 ;
}
static ssize_t cpu_max_write ( struct kernfs_open_file * of ,
char * buf , size_t nbytes , loff_t off )
{
struct task_group * tg = css_tg ( of_css ( of ) ) ;
u64 period_us , quota_us , burst_us ;
int ret ;
tg_bandwidth ( tg , & period_us , NULL , & burst_us ) ;
ret = cpu_period_quota_parse ( buf , & period_us , & quota_us ) ;
if ( ! ret )
ret = tg_set_bandwidth ( tg , period_us , quota_us , burst_us ) ;
return ret ? : nbytes ;
}
# endif / * CONFIG_CFS_BANDWIDTH * /
static struct cftype cpu_files [ ] = {
# ifdef CONFIG_GROUP_SCHED_WEIGHT
{
. name = " weight " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. read_u64 = cpu_weight_read_u64 ,
. write_u64 = cpu_weight_write_u64 ,
} ,
{
. name = " weight . nice " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. read_s64 = cpu_weight_nice_read_s64 ,
. write_s64 = cpu_weight_nice_write_s64 ,
} ,
{
. name = " idle " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. read_s64 = cpu_idle_read_s64 ,
. write_s64 = cpu_idle_write_s64 ,
} ,
# endif
# ifdef CONFIG_GROUP_SCHED_BANDWIDTH
{
. name = " max " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. seq_show = cpu_max_show ,
. write = cpu_max_write ,
} ,
{
. name = " max . burst " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. read_u64 = cpu_burst_read_u64 ,
. write_u64 = cpu_burst_write_u64 ,
} ,
# endif / * CONFIG_CFS_BANDWIDTH * /
# ifdef CONFIG_UCLAMP_TASK_GROUP
{
. name = " uclamp . min " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. seq_show = cpu_uclamp_min_show ,
. write = cpu_uclamp_min_write ,
} ,
{
. name = " uclamp . max " ,
. flags = CFTYPE_NOT_ON_ROOT ,
. seq_show = cpu_uclamp_max_show ,
. write = cpu_uclamp_max_write ,
} ,
# endif / * CONFIG_UCLAMP_TASK_GROUP * /
{ } / * terminate * /
} ;
struct cgroup_subsys cpu_cgrp_subsys = {
. css_alloc = cpu_cgroup_css_alloc ,
. css_online = cpu_cgroup_css_online ,
. css_offline = cpu_cgroup_css_offline ,
. css_released = cpu_cgroup_css_released ,
. css_free = cpu_cgroup_css_free ,
. css_extra_stat_show = cpu_extra_stat_show ,
. css_local_stat_show = cpu_local_stat_show ,
. can_attach = cpu_cgroup_can_attach ,
. attach = cpu_cgroup_attach ,
. cancel_attach = cpu_cgroup_cancel_attach ,
. legacy_cftypes = cpu_legacy_files ,
. dfl_cftypes = cpu_files ,
. early_init = true ,
. threaded = true ,
} ;
# endif / * CONFIG_CGROUP_SCHED * /
void dump_cpu_task ( int cpu )
{
if ( in_hardirq ( ) & & cpu = = smp_processor_id ( ) ) {
struct pt_regs * regs ;
regs = get_irq_regs ( ) ;
if ( regs ) {
show_regs ( regs ) ;
return ;
}
}
if ( trigger_single_cpu_backtrace ( cpu ) )
return ;
pr_info ( " Task dump for CPU % d : \ n " , cpu ) ;
sched_show_task ( cpu_curr ( cpu ) ) ;
}
/ *
* Nice levels are multiplicative , with a gentle 10 % change for every
* nice level changed . I . e . when a CPU - bound task goes from nice 0 to
* nice 1 , it will get ~ 10 % less CPU time than another CPU - bound task
* that remained on nice 0 .
*
* The " 10 % effect " is relative and cumulative : from _ any_ nice level ,
* if you go up 1 level , it ' s - 10 % CPU usage , if you go down 1 level
* it ' s + 10 % CPU usage . ( to achieve that we use a multiplier of 1 . 25 .
* If a task goes up by ~ 10 % and another task goes down by ~ 10 % then
* the relative distance between them is ~ 25 % . )
* /
const int sched_prio_to_weight [ 40 ] = {
/ * - 20 * / 88761 , 71755 , 56483 , 46273 , 36291 ,
/ * - 15 * / 29154 , 23254 , 18705 , 14949 , 11916 ,
/ * - 10 * / 9548 , 7620 , 6100 , 4904 , 3906 ,
/ * - 5 * / 3121 , 2501 , 1991 , 1586 , 1277 ,
/ * 0 * / 1024 , 820 , 655 , 526 , 423 ,
/ * 5 * / 335 , 272 , 215 , 172 , 137 ,
/ * 10 * / 110 , 87 , 70 , 56 , 45 ,
/ * 15 * / 36 , 29 , 23 , 18 , 15 ,
} ;
/ *
* Inverse ( 2 ^ 32 / x ) values of the sched_prio_to_weight [ ] array , pre - calculated .
*
* In cases where the weight does not change often , we can use the
* pre - calculated inverse to speed up arithmetics by turning divisions
* into multiplications :
* /
const u32 sched_prio_to_wmult [ 40 ] = {
/ * - 20 * / 48388 , 59856 , 76040 , 92818 , 118348 ,
/ * - 15 * / 147320 , 184698 , 229616 , 287308 , 360437 ,
/ * - 10 * / 449829 , 563644 , 704093 , 875809 , 1099582 ,
/ * - 5 * / 1376151 , 1717300 , 2157191 , 2708050 , 3363326 ,
/ * 0 * / 4194304 , 5237765 , 6557202 , 8165337 , 10153587 ,
/ * 5 * / 12820798 , 15790321 , 19976592 , 24970740 , 31350126 ,
/ * 10 * / 39045157 , 49367440 , 61356676 , 76695844 , 95443717 ,
/ * 15 * / 119304647 , 148102320 , 186737708 , 238609294 , 286331153 ,
} ;
void call_trace_sched_update_nr_running ( struct rq * rq , int count )
{
trace_sched_update_nr_running_tp ( rq , count ) ;
}
# ifdef CONFIG_SCHED_MM_CID
/ *
* @ cid_lock : Guarantee forward - progress of cid allocation .
*
* Concurrency ID allocation within a bitmap is mostly lock - free . The cid_lock
* is only used when contention is detected by the lock - free allocation so
* forward progress can be guaranteed .
* /
DEFINE_RAW_SPINLOCK ( cid_lock ) ;
/ *
* @ use_cid_lock : Select cid allocation behavior : lock - free vs spinlock .
*
* When @ use_cid_lock is 0 , the cid allocation is lock - free . When contention is
* detected , it is set to 1 to ensure that all newly coming allocations are
* serialized by @ cid_lock until the allocation which detected contention
* completes and sets @ use_cid_lock back to 0 . This guarantees forward progress
* of a cid allocation .
* /
int use_cid_lock ;
/ *
* mm_cid remote - clear implements a lock - free algorithm to clear per - mm / cpu cid
* concurrently with respect to the execution of the source runqueue context
* switch .
*
* There is one basic properties we want to guarantee here :
*
* ( 1 ) Remote - clear should _ never_ mark a per - cpu cid UNSET when it is actively
* used by a task . That would lead to concurrent allocation of the cid and
* userspace corruption .
*
* Provide this guarantee by introducing a Dekker memory ordering to guarantee
* that a pair of loads observe at least one of a pair of stores , which can be
* shown as :
*
* X = Y = 0
*
* w [ X ] = 1 w [ Y ] = 1
* MB MB
* r [ Y ] = y r [ X ] = x
*
* Which guarantees that x = = 0 & & y = = 0 is impossible . But rather than using
* values 0 and 1 , this algorithm cares about specific state transitions of the
* runqueue current task ( as updated by the scheduler context switch ) , and the
* per - mm / cpu cid value .
*
* Let ' s introduce task ( Y ) which has task - > mm = = mm and task ( N ) which has
* task - > mm ! = mm for the rest of the discussion . There are two scheduler state
* transitions on context switch we care about :
*
* ( TSA ) Store to rq - > curr with transition from ( N ) to ( Y )
*
* ( TSB ) Store to rq - > curr with transition from ( Y ) to ( N )
*
* On the remote - clear side , there is one transition we care about :
*
* ( TMA ) cmpxchg to * pcpu_cid to set the LAZY flag
*
* There is also a transition to UNSET state which can be performed from all
* sides ( scheduler , remote - clear ) . It is always performed with a cmpxchg which
* guarantees that only a single thread will succeed :
*
* ( TMB ) cmpxchg to * pcpu_cid to mark UNSET
*
* Just to be clear , what we do _ not_ want to happen is a transition to UNSET
* when a thread is actively using the cid ( property ( 1 ) ) .
*
* Let ' s looks at the relevant combinations of TSA / TSB , and TMA transitions .
*
* Scenario A ) ( TSA ) + ( TMA ) ( from next task perspective )
*
* CPU0 CPU1
*
* Context switch CS - 1 Remote - clear
* - store to rq - > curr : ( N ) - > ( Y ) ( TSA ) - cmpxchg to * pcpu_id to LAZY ( TMA )
* ( implied barrier after cmpxchg )
* - switch_mm_cid ( )
* - memory barrier ( see switch_mm_cid ( )
* comment explaining how this barrier
* is combined with other scheduler
* barriers )
* - mm_cid_get ( next )
* - READ_ONCE ( * pcpu_cid ) - rcu_dereference ( src_rq - > curr )
*
* This Dekker ensures that either task ( Y ) is observed by the
* rcu_dereference ( ) or the LAZY flag is observed by READ_ONCE ( ) , or both are
* observed .
*
* If task ( Y ) store is observed by rcu_dereference ( ) , it means that there is
* still an active task on the cpu . Remote - clear will therefore not transition
* to UNSET , which fulfills property ( 1 ) .
*
* If task ( Y ) is not observed , but the lazy flag is observed by READ_ONCE ( ) ,
* it will move its state to UNSET , which clears the percpu cid perhaps
* uselessly ( which is not an issue for correctness ) . Because task ( Y ) is not
* observed , CPU1 can move ahead to set the state to UNSET . Because moving
* state to UNSET is done with a cmpxchg expecting that the old state has the
* LAZY flag set , only one thread will successfully UNSET .
*
* If both states ( LAZY flag and task ( Y ) ) are observed , the thread on CPU0
* will observe the LAZY flag and transition to UNSET ( perhaps uselessly ) , and
* CPU1 will observe task ( Y ) and do nothing more , which is fine .
*
* What we are effectively preventing with this Dekker is a scenario where
* neither LAZY flag nor store ( Y ) are observed , which would fail property ( 1 )
* because this would UNSET a cid which is actively used .
* /
void sched_mm_cid_migrate_from ( struct task_struct * t )
{
t - > migrate_from_cpu = task_cpu ( t ) ;
}
static
int _ _ sched_mm_cid_migrate_from_fetch_cid ( struct rq * src_rq ,
struct task_struct * t ,
struct mm_cid * src_pcpu_cid )
{
struct mm_struct * mm = t - > mm ;
struct task_struct * src_task ;
int src_cid , last_mm_cid ;
if ( ! mm )
return - 1 ;
last_mm_cid = t - > last_mm_cid ;
/ *
* If the migrated task has no last cid , or if the current
* task on src rq uses the cid , it means the source cid does not need
* to be moved to the destination cpu .
* /
if ( last_mm_cid = = - 1 )
return - 1 ;
src_cid = READ_ONCE ( src_pcpu_cid - > cid ) ;
if ( ! mm_cid_is_valid ( src_cid ) | | last_mm_cid ! = src_cid )
return - 1 ;
/ *
* If we observe an active task using the mm on this rq , it means we
* are not the last task to be migrated from this cpu for this mm , so
* there is no need to move src_cid to the destination cpu .
* /
guard ( rcu ) ( ) ;
src_task = rcu_dereference ( src_rq - > curr ) ;
if ( READ_ONCE ( src_task - > mm_cid_active ) & & src_task - > mm = = mm ) {
t - > last_mm_cid = - 1 ;
return - 1 ;
}
return src_cid ;
}
static
int _ _ sched_mm_cid_migrate_from_try_steal_cid ( struct rq * src_rq ,
struct task_struct * t ,
struct mm_cid * src_pcpu_cid ,
int src_cid )
{
struct task_struct * src_task ;
struct mm_struct * mm = t - > mm ;
int lazy_cid ;
if ( src_cid = = - 1 )
return - 1 ;
/ *
* Attempt to clear the source cpu cid to move it to the destination
* cpu .
* /
lazy_cid = mm_cid_set_lazy_put ( src_cid ) ;
if ( ! try_cmpxchg ( & src_pcpu_cid - > cid , & src_cid , lazy_cid ) )
return - 1 ;
/ *
* The implicit barrier after cmpxchg per - mm / cpu cid before loading
* rq - > curr - > mm matches the scheduler barrier in context_switch ( )
* between store to rq - > curr and load of prev and next task ' s
* per - mm / cpu cid .
*
* The implicit barrier after cmpxchg per - mm / cpu cid before loading
* rq - > curr - > mm_cid_active matches the barrier in
* sched_mm_cid_exit_signals ( ) , sched_mm_cid_before_execve ( ) , and
* sched_mm_cid_after_execve ( ) between store to t - > mm_cid_active and
* load of per - mm / cpu cid .
* /
/ *
* If we observe an active task using the mm on this rq after setting
* the lazy - put flag , this task will be responsible for transitioning
* from lazy - put flag set to MM_CID_UNSET .
* /
scoped_guard ( rcu ) {
src_task = rcu_dereference ( src_rq - > curr ) ;
if ( READ_ONCE ( src_task - > mm_cid_active ) & & src_task - > mm = = mm ) {
/ *
* We observed an active task for this mm , there is therefore
* no point in moving this cid to the destination cpu .
* /
t - > last_mm_cid = - 1 ;
return - 1 ;
}
}
/ *
* The src_cid is unused , so it can be unset .
* /
if ( ! try_cmpxchg ( & src_pcpu_cid - > cid , & lazy_cid , MM_CID_UNSET ) )
return - 1 ;
WRITE_ONCE ( src_pcpu_cid - > recent_cid , MM_CID_UNSET ) ;
return src_cid ;
}
/ *
* Migration to dst cpu . Called with dst_rq lock held .
* Interrupts are disabled , which keeps the window of cid ownership without the
* source rq lock held small .
* /
void sched_mm_cid_migrate_to ( struct rq * dst_rq , struct task_struct * t )
{
struct mm_cid * src_pcpu_cid , * dst_pcpu_cid ;
struct mm_struct * mm = t - > mm ;
int src_cid , src_cpu ;
bool dst_cid_is_set ;
struct rq * src_rq ;
lockdep_assert_rq_held ( dst_rq ) ;
if ( ! mm )
return ;
src_cpu = t - > migrate_from_cpu ;
if ( src_cpu = = - 1 ) {
t - > last_mm_cid = - 1 ;
return ;
}
/ *
* Move the src cid if the dst cid is unset . This keeps id
* allocation closest to 0 in cases where few threads migrate around
* many CPUs .
*
* If destination cid or recent cid is already set , we may have
* to just clear the src cid to ensure compactness in frequent
* migrations scenarios .
*
* It is not useful to clear the src cid when the number of threads is
* greater or equal to the number of allowed CPUs , because user - space
* can expect that the number of allowed cids can reach the number of
* allowed CPUs .
* /
dst_pcpu_cid = per_cpu_ptr ( mm - > pcpu_cid , cpu_of ( dst_rq ) ) ;
dst_cid_is_set = ! mm_cid_is_unset ( READ_ONCE ( dst_pcpu_cid - > cid ) ) | |
! mm_cid_is_unset ( READ_ONCE ( dst_pcpu_cid - > recent_cid ) ) ;
if ( dst_cid_is_set & & atomic_read ( & mm - > mm_users ) > = READ_ONCE ( mm - > nr_cpus_allowed ) )
return ;
src_pcpu_cid = per_cpu_ptr ( mm - > pcpu_cid , src_cpu ) ;
src_rq = cpu_rq ( src_cpu ) ;
src_cid = _ _ sched_mm_cid_migrate_from_fetch_cid ( src_rq , t , src_pcpu_cid ) ;
if ( src_cid = = - 1 )
return ;
src_cid = _ _ sched_mm_cid_migrate_from_try_steal_cid ( src_rq , t , src_pcpu_cid ,
src_cid ) ;
if ( src_cid = = - 1 )
return ;
if ( dst_cid_is_set ) {
_ _ mm_cid_put ( mm , src_cid ) ;
return ;
}
/ * Move src_cid to dst cpu . * /
mm_cid_snapshot_time ( dst_rq , mm ) ;
WRITE_ONCE ( dst_pcpu_cid - > cid , src_cid ) ;
WRITE_ONCE ( dst_pcpu_cid - > recent_cid , src_cid ) ;
}
static void sched_mm_cid_remote_clear ( struct mm_struct * mm , struct mm_cid * pcpu_cid ,
int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct task_struct * t ;
int cid , lazy_cid ;
cid = READ_ONCE ( pcpu_cid - > cid ) ;
if ( ! mm_cid_is_valid ( cid ) )
return ;
/ *
* Clear the cpu cid if it is set to keep cid allocation compact . If
* there happens to be other tasks left on the source cpu using this
* mm , the next task using this mm will reallocate its cid on context
* switch .
* /
lazy_cid = mm_cid_set_lazy_put ( cid ) ;
if ( ! try_cmpxchg ( & pcpu_cid - > cid , & cid , lazy_cid ) )
return ;
/ *
* The implicit barrier after cmpxchg per - mm / cpu cid before loading
* rq - > curr - > mm matches the scheduler barrier in context_switch ( )
* between store to rq - > curr and load of prev and next task ' s
* per - mm / cpu cid .
*
* The implicit barrier after cmpxchg per - mm / cpu cid before loading
* rq - > curr - > mm_cid_active matches the barrier in
* sched_mm_cid_exit_signals ( ) , sched_mm_cid_before_execve ( ) , and
* sched_mm_cid_after_execve ( ) between store to t - > mm_cid_active and
* load of per - mm / cpu cid .
* /
/ *
* If we observe an active task using the mm on this rq after setting
* the lazy - put flag , that task will be responsible for transitioning
* from lazy - put flag set to MM_CID_UNSET .
* /
scoped_guard ( rcu ) {
t = rcu_dereference ( rq - > curr ) ;
if ( READ_ONCE ( t - > mm_cid_active ) & & t - > mm = = mm )
return ;
}
/ *
* The cid is unused , so it can be unset .
* Disable interrupts to keep the window of cid ownership without rq
* lock small .
* /
scoped_guard ( irqsave ) {
if ( try_cmpxchg ( & pcpu_cid - > cid , & lazy_cid , MM_CID_UNSET ) )
_ _ mm_cid_put ( mm , cid ) ;
}
}
static void sched_mm_cid_remote_clear_old ( struct mm_struct * mm , int cpu )
{
struct rq * rq = cpu_rq ( cpu ) ;
struct mm_cid * pcpu_cid ;
struct task_struct * curr ;
u64 rq_clock ;
/ *
* rq - > clock load is racy on 32 - bit but one spurious clear once in a
* while is irrelevant .
* /
rq_clock = READ_ONCE ( rq - > clock ) ;
pcpu_cid = per_cpu_ptr ( mm - > pcpu_cid , cpu ) ;
/ *
* In order to take care of infrequently scheduled tasks , bump the time
* snapshot associated with this cid if an active task using the mm is
* observed on this rq .
* /
scoped_guard ( rcu ) {
curr = rcu_dereference ( rq - > curr ) ;
if ( READ_ONCE ( curr - > mm_cid_active ) & & curr - > mm = = mm ) {
WRITE_ONCE ( pcpu_cid - > time , rq_clock ) ;
return ;
}
}
if ( rq_clock < pcpu_cid - > time + SCHED_MM_CID_PERIOD_NS )
return ;
sched_mm_cid_remote_clear ( mm , pcpu_cid , cpu ) ;
}
static void sched_mm_cid_remote_clear_weight ( struct mm_struct * mm , int cpu ,
int weight )
{
struct mm_cid * pcpu_cid ;
int cid ;
pcpu_cid = per_cpu_ptr ( mm - > pcpu_cid , cpu ) ;
cid = READ_ONCE ( pcpu_cid - > cid ) ;
if ( ! mm_cid_is_valid ( cid ) | | cid < weight )
return ;
sched_mm_cid_remote_clear ( mm , pcpu_cid , cpu ) ;
}
static void task_mm_cid_work ( struct callback_head * work )
{
unsigned long now = jiffies , old_scan , next_scan ;
struct task_struct * t = current ;
struct cpumask * cidmask ;
struct mm_struct * mm ;
int weight , cpu ;
WARN_ON_ONCE ( t ! = container_of ( work , struct task_struct , cid_work ) ) ;
work - > next = work ; / * Prevent double - add * /
if ( t - > flags & PF_EXITING )
return ;
mm = t - > mm ;
if ( ! mm )
return ;
old_scan = READ_ONCE ( mm - > mm_cid_next_scan ) ;
next_scan = now + msecs_to_jiffies ( MM_CID_SCAN_DELAY ) ;
if ( ! old_scan ) {
unsigned long res ;
res = cmpxchg ( & mm - > mm_cid_next_scan , old_scan , next_scan ) ;
if ( res ! = old_scan )
old_scan = res ;
else
old_scan = next_scan ;
}
if ( time_before ( now , old_scan ) )
return ;
if ( ! try_cmpxchg ( & mm - > mm_cid_next_scan , & old_scan , next_scan ) )
return ;
cidmask = mm_cidmask ( mm ) ;
/ * Clear cids that were not recently used . * /
for_each_possible_cpu ( cpu )
sched_mm_cid_remote_clear_old ( mm , cpu ) ;
weight = cpumask_weight ( cidmask ) ;
/ *
* Clear cids that are greater or equal to the cidmask weight to
* recompact it .
* /
for_each_possible_cpu ( cpu )
sched_mm_cid_remote_clear_weight ( mm , cpu , weight ) ;
}
void init_sched_mm_cid ( struct task_struct * t )
{
struct mm_struct * mm = t - > mm ;
int mm_users = 0 ;
if ( mm ) {
mm_users = atomic_read ( & mm - > mm_users ) ;
if ( mm_users = = 1 )
mm - > mm_cid_next_scan = jiffies + msecs_to_jiffies ( MM_CID_SCAN_DELAY ) ;
}
t - > cid_work . next = & t - > cid_work ; / * Protect against double add * /
init_task_work ( & t - > cid_work , task_mm_cid_work ) ;
}
void task_tick_mm_cid ( struct rq * rq , struct task_struct * curr )
{
struct callback_head * work = & curr - > cid_work ;
unsigned long now = jiffies ;
if ( ! curr - > mm | | ( curr - > flags & ( PF_EXITING | PF_KTHREAD ) ) | |
work - > next ! = work )
return ;
if ( time_before ( now , READ_ONCE ( curr - > mm - > mm_cid_next_scan ) ) )
return ;
/ * No page allocation under rq lock * /
task_work_add ( curr , work , TWA_RESUME ) ;
}
void sched_mm_cid_exit_signals ( struct task_struct * t )
{
struct mm_struct * mm = t - > mm ;
struct rq * rq ;
if ( ! mm )
return ;
preempt_disable ( ) ;
rq = this_rq ( ) ;
guard ( rq_lock_irqsave ) ( rq ) ;
preempt_enable_no_resched ( ) ; / * holding spinlock * /
WRITE_ONCE ( t - > mm_cid_active , 0 ) ;
/ *
* Store t - > mm_cid_active before loading per - mm / cpu cid .
* Matches barrier in sched_mm_cid_remote_clear_old ( ) .
* /
smp_mb ( ) ;
mm_cid_put ( mm ) ;
t - > last_mm_cid = t - > mm_cid = - 1 ;
}
void sched_mm_cid_before_execve ( struct task_struct * t )
{
struct mm_struct * mm = t - > mm ;
struct rq * rq ;
if ( ! mm )
return ;
preempt_disable ( ) ;
rq = this_rq ( ) ;
guard ( rq_lock_irqsave ) ( rq ) ;
preempt_enable_no_resched ( ) ; / * holding spinlock * /
WRITE_ONCE ( t - > mm_cid_active , 0 ) ;
/ *
* Store t - > mm_cid_active before loading per - mm / cpu cid .
* Matches barrier in sched_mm_cid_remote_clear_old ( ) .
* /
smp_mb ( ) ;
mm_cid_put ( mm ) ;
t - > last_mm_cid = t - > mm_cid = - 1 ;
}
void sched_mm_cid_after_execve ( struct task_struct * t )
{
struct mm_struct * mm = t - > mm ;
struct rq * rq ;
if ( ! mm )
return ;
preempt_disable ( ) ;
rq = this_rq ( ) ;
scoped_guard ( rq_lock_irqsave , rq ) {
preempt_enable_no_resched ( ) ; / * holding spinlock * /
WRITE_ONCE ( t - > mm_cid_active , 1 ) ;
/ *
* Store t - > mm_cid_active before loading per - mm / cpu cid .
* Matches barrier in sched_mm_cid_remote_clear_old ( ) .
* /
smp_mb ( ) ;
t - > last_mm_cid = t - > mm_cid = mm_cid_get ( rq , t , mm ) ;
}
}
void sched_mm_cid_fork ( struct task_struct * t )
{
WARN_ON_ONCE ( ! t - > mm | | t - > mm_cid ! = - 1 ) ;
t - > mm_cid_active = 1 ;
}
# endif / * CONFIG_SCHED_MM_CID * /
# ifdef CONFIG_SCHED_CLASS_EXT
void sched_deq_and_put_task ( struct task_struct * p , int queue_flags ,
struct sched_enq_and_set_ctx * ctx )
{
struct rq * rq = task_rq ( p ) ;
lockdep_assert_rq_held ( rq ) ;
* ctx = ( struct sched_enq_and_set_ctx ) {
. p = p ,
. queue_flags = queue_flags ,
. queued = task_on_rq_queued ( p ) ,
. running = task_current ( rq , p ) ,
} ;
update_rq_clock ( rq ) ;
if ( ctx - > queued )
dequeue_task ( rq , p , queue_flags | DEQUEUE_NOCLOCK ) ;
if ( ctx - > running )
put_prev_task ( rq , p ) ;
}
void sched_enq_and_set_task ( struct sched_enq_and_set_ctx * ctx )
{
struct rq * rq = task_rq ( ctx - > p ) ;
lockdep_assert_rq_held ( rq ) ;
if ( ctx - > queued )
enqueue_task ( rq , ctx - > p , ctx - > queue_flags | ENQUEUE_NOCLOCK ) ;
if ( ctx - > running )
set_next_task ( rq , ctx - > p ) ;
}
# endif / * CONFIG_SCHED_CLASS_EXT * /
Messung V0.5 in Prozent C=95 H=94 G=94
¤ Dauer der Verarbeitung: 5.880 Sekunden
¤
*© Formatika GbR, Deutschland
2026-10-11
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1127926
#Domains=2039723