summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-20 12:35:35 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-20 12:35:35 -1000
commitcb95904b470d2d347012d5e360303cf478ca5362 (patch)
tree4060494f11c5d52e7554e10af7ff3e2f619011af /include
parent4a8bdffce502d70405391a7ac38bac6dcef94749 (diff)
parentb99b7f60c5b473d374c68b53753153b4aa9e0702 (diff)
Merge tag 'sched-core-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler updates from Ingo Molnar: "Kconfig updates: - Simplify PREEMPT_DYNAMIC (Mark Rutland) Fair scheduler updates: - Remove redundant RUN_TO_PARITY check (Elif Topuz) - Declare augmented callbacks per field, fix rb_add_augmented_cached() descent (Yiwei Lin, Peter Zijlstra) - Restart fair hrtick after same-task repicks (Shubhang Kaushik) - Improve the scheduling latency of short slice tasks (Vincent Guittot) Deadline/RT scheduler updates: - Check start_dl_timer expiry with ktime_before() (Liang Hao) - irq_work: CPU-hotplug improvements on PREEMPT_RT (Sebastian Andrzej Siewior) Energy-aware scheduling updates: - Implement the steal_governor, introduce preferred CPUs and steal-driven vCPU backoff (Shrikanth Hegde) Multi-processor load-balancing updates: - Enable preferred SMT siblings on NVIDIA Olympus (Andrea Righi) - Randomize equally shallow idle CPU picks (Christian Loehle) - Remove redundant core_sched_seq (Hui Su) Cache-aware scheduling updates: - Avoid publishing partial LLC utilization (Jemmy Wong) NUMA-balancing updates: - Reset NUMA fault locality after scan period update (Eric Kim) Proxy execution updates: - Ongoing work to implement sleeping owner handling for proxy execution (John Stultz, Vasily Gorbik) - Preparatory steps to make sched_ext compatible with proxy execution (Andrea Righi) Scheduler infrastructure updates & fixes: - Remove the RCU wait from PSI trigger destruction (Shakeel Butt) - Avoid modifying wait-entry on failed priority registration (Hui Su) - Use the new static key API for sched_feat (Hongyan Xia) - Convert paravirt_steal to new static key APIs (Hongyan Xia) - cputime: Don't account idle time twice after dyntick-idle (Stian Halseth) Scheduler debugging updates: - Set TIF_NEED_RESCHED before calling __trace_set_need_resched() (Sechang Lim) - Fix context analysis errors in non-preferred CPU push (Shrikanth Hegde) Misc cleanups and fixes by Christian Loehle, Shubhang Kaushik, Thomas Huth and Vladimir Zapolskiy" * tag 'sched-core-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (64 commits) sched: Replace nr_iowait_cpu() with a bool accessor Revert "sched/fair: Remove dead code on enqueue_task_fair()" sched/cache: Avoid publishing partial LLC utilization sched/cputime: Don't account idle time twice after dyntick-idle sched/psi: Remove the RCU wait from trigger destruction sched/eevdf: Remove redundant RUN_TO_PARITY check sched/wait: Avoid modifying entry on failed priority registration rbtree_test: Use rb_add_augmented_cached() for the cached augmented test rbtree: Update augmented data on the way down in rb_add_augmented_cached() rbtree: Declare augmented callbacks per field with RB_AUG() rbtree_test: Use rb_add() and rb_add_cached() for the basic tests smpboot: Don't park the thread if work is pending irq_work: Flush lazy work CPU down on PREEMPT_RT irq_work: Update a comment regarding CPU hotplug invocation sched/topology: Add asymmetric SMT packing override sched/fair: Honor asymmetric SMT priority in idle selection sched: Set TIF_NEED_RESCHED before calling __trace_set_need_resched() sched/core: Fix context analysis errors in non-preferred CPU push virt/steal_governor: Enable the driver virt/steal_governor: Implement steal_governor policy loop ...
Diffstat (limited to 'include')
-rw-r--r--include/asm-generic/preempt.h10
-rw-r--r--include/linux/bitmap.h14
-rw-r--r--include/linux/cpumask.h42
-rw-r--r--include/linux/irq-entry-common.h17
-rw-r--r--include/linux/irq_work.h2
-rw-r--r--include/linux/kernel.h20
-rw-r--r--include/linux/kernel_stat.h18
-rw-r--r--include/linux/preempt.h20
-rw-r--r--include/linux/rbtree_augmented.h201
-rw-r--r--include/linux/sched.h37
-rw-r--r--include/linux/sched/cputime.h6
-rw-r--r--include/linux/sched/stat.h2
-rw-r--r--include/uapi/linux/sched.h2
13 files changed, 239 insertions, 152 deletions
diff --git a/include/asm-generic/preempt.h b/include/asm-generic/preempt.h
index c8683c046615..1adddeab8545 100644
--- a/include/asm-generic/preempt.h
+++ b/include/asm-generic/preempt.h
@@ -96,19 +96,9 @@ static __always_inline bool should_resched(int preempt_offset)
extern asmlinkage void preempt_schedule(void);
extern asmlinkage void preempt_schedule_notrace(void);
-#if defined(CONFIG_PREEMPT_DYNAMIC) && defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
-
-void dynamic_preempt_schedule(void);
-void dynamic_preempt_schedule_notrace(void);
-#define __preempt_schedule() dynamic_preempt_schedule()
-#define __preempt_schedule_notrace() dynamic_preempt_schedule_notrace()
-
-#else /* !CONFIG_PREEMPT_DYNAMIC || !CONFIG_HAVE_PREEMPT_DYNAMIC_KEY*/
-
#define __preempt_schedule() preempt_schedule()
#define __preempt_schedule_notrace() preempt_schedule_notrace()
-#endif /* CONFIG_PREEMPT_DYNAMIC && CONFIG_HAVE_PREEMPT_DYNAMIC_KEY*/
#endif /* CONFIG_PREEMPTION */
#endif /* __ASM_PREEMPT_H */
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 7df1573a409c..adafbcf2016b 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -52,6 +52,7 @@ struct device;
* bitmap_complement(dst, src, nbits) *dst = ~(*src)
* bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal?
* bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap?
+ * bitmap_intersects_and(src1, src2, src3, nbits) Do *src1, *src2 and *src3 overlap?
* bitmap_subset(src1, src2, nbits) Is *src1 a subset of *src2?
* bitmap_empty(src, nbits) Are all bits zero in *src?
* bitmap_full(src, nbits) Are all bits set in *src?
@@ -181,6 +182,9 @@ void __bitmap_replace(unsigned long *dst,
const unsigned long *mask, unsigned int nbits);
bool __bitmap_intersects(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits);
+bool __bitmap_intersects_and(const unsigned long *bitmap1,
+ const unsigned long *bitmap2,
+ const unsigned long *bitmap3, unsigned int nbits);
bool __bitmap_subset(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits);
unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
@@ -446,6 +450,16 @@ bool bitmap_intersects(const unsigned long *src1, const unsigned long *src2, uns
}
static __always_inline
+bool bitmap_intersects_and(const unsigned long *src1, const unsigned long *src2,
+ const unsigned long *src3, unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return ((*src1 & *src2 & *src3) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+ else
+ return __bitmap_intersects_and(src1, src2, src3, nbits);
+}
+
+static __always_inline
bool bitmap_subset(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
{
if (small_const_nbits(nbits))
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 4c8bb6953107..bf89bb3f30f6 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -121,12 +121,20 @@ extern struct cpumask __cpu_enabled_mask;
extern struct cpumask __cpu_present_mask;
extern struct cpumask __cpu_active_mask;
extern struct cpumask __cpu_dying_mask;
+
+#ifdef CONFIG_PREFERRED_CPU
+extern struct cpumask __cpu_preferred_mask;
+#else
+#define __cpu_preferred_mask __cpu_active_mask
+#endif
+
#define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask)
#define cpu_online_mask ((const struct cpumask *)&__cpu_online_mask)
#define cpu_enabled_mask ((const struct cpumask *)&__cpu_enabled_mask)
#define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask)
#define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask)
#define cpu_dying_mask ((const struct cpumask *)&__cpu_dying_mask)
+#define cpu_preferred_mask ((const struct cpumask *)&__cpu_preferred_mask)
extern atomic_t __num_online_cpus;
extern unsigned int __num_possible_cpus;
@@ -825,6 +833,24 @@ bool cpumask_intersects(const struct cpumask *src1p, const struct cpumask *src2p
}
/**
+ * cpumask_intersects_and - (*src1p & *src2p & *src3p) != 0
+ * @src1p: the first input
+ * @src2p: the second input
+ * @src3p: the third input
+ *
+ * Return: true if AND of the three cpumasks is non-empty,
+ * otherwise false
+ */
+static __always_inline
+bool cpumask_intersects_and(const struct cpumask *src1p,
+ const struct cpumask *src2p,
+ const struct cpumask *src3p)
+{
+ return bitmap_intersects_and(cpumask_bits(src1p), cpumask_bits(src2p),
+ cpumask_bits(src3p), small_cpumask_bits);
+}
+
+/**
* cpumask_subset - (*src1p & ~*src2p) == 0
* @src1p: the first input
* @src2p: the second input
@@ -1163,6 +1189,12 @@ void init_cpu_possible(const struct cpumask *src);
#define set_cpu_active(cpu, active) assign_cpu((cpu), &__cpu_active_mask, (active))
#define set_cpu_dying(cpu, dying) assign_cpu((cpu), &__cpu_dying_mask, (dying))
+#ifdef CONFIG_PREFERRED_CPU
+#define set_cpu_preferred(cpu, preferred) assign_cpu((cpu), &__cpu_preferred_mask, (preferred))
+#else
+#define set_cpu_preferred(cpu, preferred) do { } while (0)
+#endif
+
void set_cpu_online(unsigned int cpu, bool online);
void set_cpu_possible(unsigned int cpu, bool possible);
@@ -1257,6 +1289,11 @@ static __always_inline bool cpu_dying(unsigned int cpu)
return cpumask_test_cpu(cpu, cpu_dying_mask);
}
+static __always_inline bool cpu_preferred(unsigned int cpu)
+{
+ return cpumask_test_cpu(cpu, cpu_preferred_mask);
+}
+
#else
#define num_online_cpus() 1U
@@ -1295,6 +1332,11 @@ static __always_inline bool cpu_dying(unsigned int cpu)
return false;
}
+static __always_inline bool cpu_preferred(unsigned int cpu)
+{
+ return cpu == 0;
+}
+
#endif /* NR_CPUS > 1 */
#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
diff --git a/include/linux/irq-entry-common.h b/include/linux/irq-entry-common.h
index c74b5c87e10f..d5a66f54d70b 100644
--- a/include/linux/irq-entry-common.h
+++ b/include/linux/irq-entry-common.h
@@ -346,22 +346,7 @@ typedef struct irqentry_state {
*
* Conditional reschedule with additional sanity checks.
*/
-void raw_irqentry_exit_cond_resched(void);
-
-#ifdef CONFIG_PREEMPT_DYNAMIC
-#if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL)
-#define irqentry_exit_cond_resched_dynamic_enabled raw_irqentry_exit_cond_resched
-#define irqentry_exit_cond_resched_dynamic_disabled NULL
-DECLARE_STATIC_CALL(irqentry_exit_cond_resched, raw_irqentry_exit_cond_resched);
-#define irqentry_exit_cond_resched() static_call(irqentry_exit_cond_resched)()
-#elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
-DECLARE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched);
-void dynamic_irqentry_exit_cond_resched(void);
-#define irqentry_exit_cond_resched() dynamic_irqentry_exit_cond_resched()
-#endif
-#else /* CONFIG_PREEMPT_DYNAMIC */
-#define irqentry_exit_cond_resched() raw_irqentry_exit_cond_resched()
-#endif /* CONFIG_PREEMPT_DYNAMIC */
+void irqentry_exit_cond_resched(void);
/**
* irqentry_enter_from_kernel_mode - Establish state before invoking the irq handler
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
index c5afd053ae32..7184e1273965 100644
--- a/include/linux/irq_work.h
+++ b/include/linux/irq_work.h
@@ -59,6 +59,7 @@ void irq_work_sync(struct irq_work *work);
#include <asm/irq_work.h>
void irq_work_run(void);
+void irq_work_run_cpu(unsigned int cpu);
bool irq_work_needs_cpu(void);
void irq_work_single(void *arg);
@@ -67,6 +68,7 @@ void arch_irq_work_raise(void);
#else
static inline bool irq_work_needs_cpu(void) { return false; }
static inline void irq_work_run(void) { }
+static inline void irq_work_run_cpu(unsigned int cpu) { }
static inline void irq_work_single(void *arg) { }
#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 24414c79e59a..4b11d1dc0a67 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -43,30 +43,10 @@ struct completion;
struct user;
#ifdef CONFIG_PREEMPT_VOLUNTARY_BUILD
-
extern int __cond_resched(void);
# define might_resched() __cond_resched()
-
-#elif defined(CONFIG_PREEMPT_DYNAMIC) && defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL)
-
-extern int __cond_resched(void);
-
-DECLARE_STATIC_CALL(might_resched, __cond_resched);
-
-static __always_inline void might_resched(void)
-{
- static_call_mod(might_resched)();
-}
-
-#elif defined(CONFIG_PREEMPT_DYNAMIC) && defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
-
-extern int dynamic_might_resched(void);
-# define might_resched() dynamic_might_resched()
-
#else
-
# define might_resched() do { } while (0)
-
#endif /* CONFIG_PREEMPT_* */
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 9ca6c2259dfe..9f0f91dc8d7d 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -40,6 +40,9 @@ struct kernel_cpustat {
seqcount_t idle_sleeptime_seq;
u64 idle_entrytime;
u64 idle_stealtime[2];
+ u64 idle_dyntick_entry;
+ u64 idle_tick_period;
+ u64 idle_tick_overlap;
#endif
u64 cpustat[NR_STATS];
};
@@ -111,7 +114,7 @@ static inline unsigned long kstat_cpu_irqs_sum(unsigned int cpu)
#ifdef CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE
static inline void kcpustat_dyntick_start(u64 now) { }
-static inline void kcpustat_dyntick_stop(u64 now) { }
+static inline void kcpustat_dyntick_stop(u64 now, u64 tick_start) { }
static inline void kcpustat_irq_enter(u64 now) { }
static inline void kcpustat_irq_exit(u64 now) { }
static inline bool kcpustat_idle_dyntick(void) { return false; }
@@ -132,7 +135,7 @@ static inline u64 kcpustat_field_iowait(int cpu)
#else /* !CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE */
extern void kcpustat_dyntick_start(u64 now);
-extern void kcpustat_dyntick_stop(u64 now);
+extern void kcpustat_dyntick_stop(u64 now, u64 tick_start);
extern void kcpustat_irq_enter(u64 now);
extern void kcpustat_irq_exit(u64 now);
extern u64 kcpustat_field_idle(int cpu);
@@ -196,6 +199,17 @@ static inline void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
}
#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN */
+static inline u64 kcpustat_field_total(enum cpu_usage_stat usage, const struct cpumask *cpus)
+{
+ u64 total = 0;
+ int cpu;
+
+ for_each_cpu(cpu, cpus)
+ total += kcpustat_field(usage, cpu);
+
+ return total;
+}
+
extern void account_user_time(struct task_struct *, u64);
extern void account_guest_time(struct task_struct *, u64);
extern void account_system_time(struct task_struct *, int, u64);
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 2e689de7b29a..06ff44a4b8b6 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -498,21 +498,11 @@ DEFINE_LOCK_GUARD_0(preempt_notrace, preempt_disable_notrace(), preempt_enable_n
#ifdef CONFIG_PREEMPT_DYNAMIC
-extern bool preempt_model_none(void);
-extern bool preempt_model_voluntary(void);
extern bool preempt_model_full(void);
extern bool preempt_model_lazy(void);
#else
-static inline bool preempt_model_none(void)
-{
- return IS_ENABLED(CONFIG_PREEMPT_NONE);
-}
-static inline bool preempt_model_voluntary(void)
-{
- return IS_ENABLED(CONFIG_PREEMPT_VOLUNTARY);
-}
static inline bool preempt_model_full(void)
{
return IS_ENABLED(CONFIG_PREEMPT);
@@ -525,6 +515,16 @@ static inline bool preempt_model_lazy(void)
#endif
+static inline bool preempt_model_none(void)
+{
+ return IS_ENABLED(CONFIG_PREEMPT_NONE);
+}
+
+static inline bool preempt_model_voluntary(void)
+{
+ return IS_ENABLED(CONFIG_PREEMPT_VOLUNTARY);
+}
+
static inline bool preempt_model_rt(void)
{
return IS_ENABLED(CONFIG_PREEMPT_RT);
diff --git a/include/linux/rbtree_augmented.h b/include/linux/rbtree_augmented.h
index d2fa1c41bfd2..b9fc1be86ae3 100644
--- a/include/linux/rbtree_augmented.h
+++ b/include/linux/rbtree_augmented.h
@@ -15,6 +15,8 @@
#include <linux/compiler.h>
#include <linux/rbtree.h>
#include <linux/rcupdate.h>
+#include <linux/args.h>
+#include <linux/minmax.h>
/*
* Please note - only struct rb_augment_callbacks and the prototypes for
@@ -28,6 +30,7 @@ struct rb_augment_callbacks {
void (*propagate)(struct rb_node *node, struct rb_node *stop);
void (*copy)(struct rb_node *old, struct rb_node *new);
void (*rotate)(struct rb_node *old, struct rb_node *new);
+ void (*merge)(struct rb_node *node, struct rb_node *new);
};
extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
@@ -60,6 +63,12 @@ rb_insert_augmented_cached(struct rb_node *node,
rb_insert_augmented(node, &root->rb_root, augment);
}
+/*
+ * Insert @node into the leftmost cached augmented tree @tree.
+ *
+ * The augmented data of @node must already describe @node alone; it is
+ * merged into every ancestor on the way down through augment->merge().
+ */
static __always_inline struct rb_node *
rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree,
bool (*less)(struct rb_node *, const struct rb_node *),
@@ -71,6 +80,7 @@ rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree,
while (*link) {
parent = *link;
+ augment->merge(parent, node);
if (less(node, parent)) {
link = &parent->rb_left;
} else {
@@ -80,12 +90,108 @@ rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree,
}
rb_link_node(node, parent, link);
- augment->propagate(parent, NULL); /* suboptimal */
rb_insert_augmented_cached(node, tree, leftmost, augment);
return leftmost ? node : NULL;
}
+#define RB_FOR_EACH_1(what, RBNAME, RBSTRUCT, RBFIELD, x) \
+ what(1, RBNAME, RBSTRUCT, RBFIELD, x)
+
+#define RB_FOR_EACH_2(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(2, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_1(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_3(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(3, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_2(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_4(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(4, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_3(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_5(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(5, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_4(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_6(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(6, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_5(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_7(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(7, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_6(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH_8(what, RBNAME, RBSTRUCT, RBFIELD, x, ...) \
+ what(8, RBNAME, RBSTRUCT, RBFIELD, x) \
+ RB_FOR_EACH_7(what, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+#define RB_FOR_EACH(action, RBNAME, RBSTRUCT, RBFIELD, ...) \
+ CONCATENATE(RB_FOR_EACH_, COUNT_ARGS(__VA_ARGS__)) \
+ (action, RBNAME, RBSTRUCT, RBFIELD, __VA_ARGS__)
+
+/*
+ * One augmented field: @val is the node's own contribution (a member for
+ * RB_AUG(), a function of the node for RB_AUG_FUNC()), @aug the member
+ * holding the aggregate over the subtree, and @fold(a, b) combines two
+ * aggregates: min, max, a sum, ... It must be commutative and associative.
+ */
+#define RB_AUG_FUNC(val, aug, fold) (val(s), aug, fold)
+#define RB_AUG(val, aug, fold) (s->val, aug, fold)
+#define RB_UNPACK(...) __VA_ARGS__
+
+#define __RB_INST(n, RBNAME, RBSTRUCT, RBFIELD, val, aug, fold) \
+static inline void \
+RBNAME ## _copy_ ## n(RBSTRUCT *old, RBSTRUCT *new) \
+{ \
+ new->aug = old->aug; \
+} \
+static inline bool \
+RBNAME ## _compute_ ## n(RBSTRUCT *s, bool exit) \
+{ \
+ TYPEOF_UNQUAL(s->aug) _old_aug = s->aug; \
+ TYPEOF_UNQUAL(s->aug) _val = val; \
+ struct rb_node *_node = &s->RBFIELD; \
+ if (_node->rb_right) { \
+ RBSTRUCT *_c = container_of(_node->rb_right, typeof(*s), RBFIELD); \
+ _val = fold(_val, _c->aug); \
+ } \
+ if (_node->rb_left) { \
+ RBSTRUCT *_c = container_of(_node->rb_left, typeof(*s), RBFIELD); \
+ _val = fold(_val, _c->aug); \
+ } \
+ if (exit && _old_aug == _val) \
+ return true; \
+ s->aug = _val; \
+ return false; \
+}
+#define _RB_INST(n, RBNAME, RBSTRUCT, RBFIELD, args) \
+ __RB_INST(n, RBNAME, RBSTRUCT, RBFIELD, args)
+#define RB_INST(n, RBNAME, RBSTRUCT, RBFIELD, x) \
+ _RB_INST(n, RBNAME, RBSTRUCT, RBFIELD, RB_UNPACK x)
+
+#define __RB_COPY(n, RBNAME, RBSTRUCT, RBFIELD, val, aug, fold) \
+ RBNAME ## _copy_ ## n(old, new);
+#define _RB_COPY(n, RBNAME, RBSTRUCT, RBFIELD, args) \
+ __RB_COPY(n, RBNAME, RBSTRUCT, RBFIELD, args)
+#define RB_COPY(n, RBNAME, RBSTRUCT, RBFIELD, x) \
+ _RB_COPY(n, RBNAME, RBSTRUCT, RBFIELD, RB_UNPACK x)
+
+#define __RB_COMPUTE(n, RBNAME, RBSTRUCT, RBFIELD, val, aug, fold) \
+ ret &= RBNAME ## _compute_ ## n(node, exit);
+#define _RB_COMPUTE(n, RBNAME, RBSTRUCT, RBFIELD, args) \
+ __RB_COMPUTE(n, RBNAME, RBSTRUCT, RBFIELD, args)
+#define RB_COMPUTE(n, RBNAME, RBSTRUCT, RBFIELD, x) \
+ _RB_COMPUTE(n, RBNAME, RBSTRUCT, RBFIELD, RB_UNPACK x)
+
+/* fold @new, about to become a descendant of @node, into @node */
+#define __RB_MERGE(n, RBNAME, RBSTRUCT, RBFIELD, val, aug, fold) \
+ node->aug = fold(node->aug, new->aug);
+#define _RB_MERGE(n, RBNAME, RBSTRUCT, RBFIELD, args) \
+ __RB_MERGE(n, RBNAME, RBSTRUCT, RBFIELD, args)
+#define RB_MERGE(n, RBNAME, RBSTRUCT, RBFIELD, x) \
+ _RB_MERGE(n, RBNAME, RBSTRUCT, RBFIELD, RB_UNPACK x)
+
/*
* Template for declaring augmented rbtree callbacks (generic multi fields)
*
@@ -93,18 +199,29 @@ rb_add_augmented_cached(struct rb_node *node, struct rb_root_cached *tree,
* RBNAME: name of the rb_augment_callbacks structure
* RBSTRUCT: struct type of the tree nodes
* RBFIELD: name of struct rb_node field within RBSTRUCT
- * RBCOPY: name of function that copies the RBAUGMENTED datas
- * RBCOMPUTE: name of function that recomputes the RBAUGMENTED datas
+ * RBAUG...: list of RB_AUG() describing the augmented data
*/
-
-#define RB_DECLARE_CALLBACKS_MULTI(RBSTATIC, RBNAME, \
- RBSTRUCT, RBFIELD, RBCOPY, RBCOMPUTE) \
+#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
+ RBSTRUCT, RBFIELD, RBAUG...) \
+RB_FOR_EACH(RB_INST, RBNAME, RBSTRUCT, RBFIELD, RBAUG) \
+static inline void \
+RBNAME ## __copy(RBSTRUCT *old, RBSTRUCT *new) \
+{ \
+ RB_FOR_EACH(RB_COPY, RBNAME, RBSTRUCT, RBFIELD, RBAUG); \
+} \
+static inline bool \
+RBNAME ## __compute(RBSTRUCT *node, bool exit) \
+{ \
+ bool ret = true; \
+ RB_FOR_EACH(RB_COMPUTE, RBNAME, RBSTRUCT, RBFIELD, RBAUG); \
+ return ret; \
+} \
static inline void \
RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop) \
{ \
while (rb != stop) { \
RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD); \
- if (RBCOMPUTE(node, true)) \
+ if (RBNAME ## __compute(node, true)) \
break; \
rb = rb_parent(&node->RBFIELD); \
} \
@@ -114,44 +231,31 @@ RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \
{ \
RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
- RBCOPY(new, old); \
+ RBNAME ## __copy(old, new); \
} \
static void \
RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \
{ \
RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
- RBCOPY(new, old); \
- RBCOMPUTE(old, false); \
+ RBNAME ## __copy(old, new); \
+ RBNAME ## __compute(old, false); \
+} \
+static inline void \
+RBNAME ## _merge(struct rb_node *rb, struct rb_node *rb_new) \
+{ \
+ RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD); \
+ RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
+ RB_FOR_EACH(RB_MERGE, RBNAME, RBSTRUCT, RBFIELD, RBAUG); \
} \
RBSTATIC const struct rb_augment_callbacks RBNAME = { \
.propagate = RBNAME ## _propagate, \
.copy = RBNAME ## _copy, \
- .rotate = RBNAME ## _rotate \
+ .rotate = RBNAME ## _rotate, \
+ .merge = RBNAME ## _merge \
};
/*
- * Template for declaring augmented rbtree callbacks (generic single field)
- *
- * RBSTATIC: 'static' or empty
- * RBNAME: name of the rb_augment_callbacks structure
- * RBSTRUCT: struct type of the tree nodes
- * RBFIELD: name of struct rb_node field within RBSTRUCT
- * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree
- * RBCOMPUTE: name of function that recomputes the RBAUGMENTED data
- */
-
-#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
- RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE) \
-static inline void \
-RBNAME ## _copy_single(RBSTRUCT *new, RBSTRUCT *old) \
-{ \
- new->RBAUGMENTED = old->RBAUGMENTED; \
-} \
-RB_DECLARE_CALLBACKS_MULTI(RBSTATIC, RBNAME, \
- RBSTRUCT, RBFIELD, RBNAME ## _copy_single, RBCOMPUTE)
-
-/*
* Template for declaring augmented rbtree callbacks,
* computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
*
@@ -159,34 +263,15 @@ RB_DECLARE_CALLBACKS_MULTI(RBSTATIC, RBNAME, \
* RBNAME: name of the rb_augment_callbacks structure
* RBSTRUCT: struct type of the tree nodes
* RBFIELD: name of struct rb_node field within RBSTRUCT
- * RBTYPE: type of the RBAUGMENTED field
- * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
- * RBCOMPUTE: name of function that returns the per-node RBTYPE scalar
+ * RBTYPE: type of the RBAUGMENTED field -- unused, assumed typeof(RBAUGMENTED)
+ * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree
+ * RBVALUE: name of function that returns the per-node RBTYPE scalar
*/
-#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \
- RBTYPE, RBAUGMENTED, RBCOMPUTE) \
-static inline bool RBNAME ## _compute_max(RBSTRUCT *node, bool exit) \
-{ \
- RBSTRUCT *child; \
- RBTYPE max = RBCOMPUTE(node); \
- if (node->RBFIELD.rb_left) { \
- child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD); \
- if (child->RBAUGMENTED > max) \
- max = child->RBAUGMENTED; \
- } \
- if (node->RBFIELD.rb_right) { \
- child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD); \
- if (child->RBAUGMENTED > max) \
- max = child->RBAUGMENTED; \
- } \
- if (exit && node->RBAUGMENTED == max) \
- return true; \
- node->RBAUGMENTED = max; \
- return false; \
-} \
-RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
- RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME ## _compute_max)
+#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \
+ RBTYPE, RBAUGMENTED, RBVALUE) \
+RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \
+ RB_AUG_FUNC(RBVALUE, RBAUGMENTED, max))
#define RB_RED 0
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 78bfc0e32e56..93ab9b6bec3e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -554,6 +554,7 @@ struct sched_statistics {
u64 nr_failed_migrations_running;
u64 nr_failed_migrations_hot;
u64 nr_forced_migrations;
+ u64 nr_migrations_cpu_non_preferred;
u64 nr_wakeups;
u64 nr_wakeups_sync;
@@ -2105,10 +2106,9 @@ static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
static inline void set_tsk_need_resched(struct task_struct *tsk)
{
- if (tracepoint_enabled(sched_set_need_resched_tp) &&
- !test_tsk_thread_flag(tsk, TIF_NEED_RESCHED))
+ if (!test_and_set_tsk_thread_flag(tsk, TIF_NEED_RESCHED) &&
+ tracepoint_enabled(sched_set_need_resched_tp))
__trace_set_need_resched(tsk, TIF_NEED_RESCHED);
- set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
}
static inline void clear_tsk_need_resched(struct task_struct *tsk)
@@ -2135,44 +2135,19 @@ static inline void set_need_resched_current(void)
* value indicates whether a reschedule was done in fact.
* cond_resched_lock() will drop the spinlock before scheduling,
*/
-#if !defined(CONFIG_PREEMPTION) || defined(CONFIG_PREEMPT_DYNAMIC)
+#if !defined(CONFIG_PREEMPTION)
extern int __cond_resched(void);
-#if defined(CONFIG_PREEMPT_DYNAMIC) && defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL)
-
-DECLARE_STATIC_CALL(cond_resched, __cond_resched);
-
-static __always_inline int _cond_resched(void)
-{
- return static_call_mod(cond_resched)();
-}
-
-#elif defined(CONFIG_PREEMPT_DYNAMIC) && defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
-
-extern int dynamic_cond_resched(void);
-
-static __always_inline int _cond_resched(void)
-{
- return dynamic_cond_resched();
-}
-
-#else /* !CONFIG_PREEMPTION */
-
static inline int _cond_resched(void)
{
return __cond_resched();
}
-
-#endif /* PREEMPT_DYNAMIC && CONFIG_HAVE_PREEMPT_DYNAMIC_CALL */
-
-#else /* CONFIG_PREEMPTION && !CONFIG_PREEMPT_DYNAMIC */
-
+#else
static inline int _cond_resched(void)
{
return 0;
}
-
-#endif /* !CONFIG_PREEMPTION || CONFIG_PREEMPT_DYNAMIC */
+#endif
#define cond_resched() ({ \
__might_resched(__FILE__, __LINE__, 0); \
diff --git a/include/linux/sched/cputime.h b/include/linux/sched/cputime.h
index e90efaf6d26e..694126411dfe 100644
--- a/include/linux/sched/cputime.h
+++ b/include/linux/sched/cputime.h
@@ -182,9 +182,9 @@ extern unsigned long long
task_sched_runtime(struct task_struct *task);
#ifdef CONFIG_PARAVIRT
-struct static_key;
-extern struct static_key paravirt_steal_enabled;
-extern struct static_key paravirt_steal_rq_enabled;
+#include <linux/jump_label.h>
+DECLARE_STATIC_KEY_FALSE(paravirt_steal_enabled);
+DECLARE_STATIC_KEY_FALSE(paravirt_steal_rq_enabled);
#ifdef CONFIG_HAVE_PV_STEAL_CLOCK_GEN
u64 dummy_steal_clock(int cpu);
diff --git a/include/linux/sched/stat.h b/include/linux/sched/stat.h
index 0108a38bb64d..4810b14d0372 100644
--- a/include/linux/sched/stat.h
+++ b/include/linux/sched/stat.h
@@ -20,7 +20,7 @@ extern int nr_processes(void);
extern unsigned int nr_running(void);
extern bool single_task_running(void);
extern unsigned int nr_iowait(void);
-extern unsigned int nr_iowait_cpu(int cpu);
+extern bool cpu_has_iowait(int cpu);
static inline int sched_info_on(void)
{
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
index 33a4624285cd..19ffeba89428 100644
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -53,7 +53,7 @@
*/
#define UNSHARE_EMPTY_MNTNS 0x00100000 /* Unshare an empty mount namespace. */
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
/**
* struct clone_args - arguments for the clone3 syscall
* @flags: Flags for the new process as listed above.