Merge tag 'sched-core-2026-06-14' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip

Pull scheduler updates from Ingo Molnar:
 "SMP load-balancing updates:

   - A large series to introduce infrastructure for cache-aware load
     balancing, with the goal of co-locating tasks that share data
     within the same Last Level Cache (LLC) domain. By improving cache
     locality, the scheduler can reduce cache bouncing and cache misses,
     ultimately improving data access efficiency.

     Implemented by Chen Yu and Tim Chen, based on early prototype work
     by Peter Zijlstra, with fixes by Jianyong Wu, Peter Zijlstra and
     Shrikanth Hegde.

   - A series to simplify CONFIG_SCHED_SMT ifdef usage (Shrikanth Hegde)

  Fair scheduler updates:

   - A series to improve SD_ASYM_CPUCAPACITY scheduling by introducing
     SMT awareness (Andrea Righi, K Prateek Nayak)

   - A series to optimize cfs_rq and sched_entity allocation for better
     data locality (Zecheng Li)

   - A preparatory series to change fair/cgroup scheduling to a single
     runqueue, without the final change (Peter Zijlstra)

   - Auto-manage ext/fair dl_server bandwidth (Andrea Righi)

   - Fix cpu_util runnable_avg arithmetic (Hongyan Xia)

   - Optimize update_tg_load_avg()'s rate-limiting code (Rik van Riel)

   - Allow account_cfs_rq_runtime() to throttle current hierarchy
     (K Prateek Nayak)

   - Update util_est after updating util_avg during dequeue, to fix the
     util signal update logic, which reduces signal noise (Vincent
     Guittot)

  Scheduler topology updates:

   - Allow multiple domains to claim sched_domain_shared (K Prateek
     Nayak)

   - Add parameter to split LLC (Peter Zijlstra)

  Core scheduler updates:

   - Use trace_call__<tp>() to save a static branch (Gabriele Monaco)

  Scheduler statistics updates:

   - Drop now-stale mul_u64_u64_div_u64() cputime over-approximation
     guard (Nicolas Pitre)

  Deadline scheduler updates:

   - Reject debugfs dl_server writes for offline CPUs (Andrea Righi)

   - Fix replenishment logic for non-deferred servers (Yuri Andriaccio)

  RT scheduling updates:

   - Turn RT_PUSH_IPI default off for non PREEMPT_RT (Steven Rostedt)

   - Update default bandwidth for real-time tasks to 1.0 (Yuri
     Andriaccio)

  Proxy scheduling updates:

   - A series to implement Optimized Donor Migration for Proxy Execution
     (John Stultz, Peter Zijlstra)

   - Various proxy scheduling cleanups and fixes (Peter Zijlstra,
     K Prateek Nayak)

  Misc fixes, improvements and cleanups by Aaron Lu, Andrea Righi,
  Zenghui Yu, Chen Yu, Guanyou.Chen, John Stultz, Shrikanth Hegde,
  Peter Zijlstra, Liang Luo and Yiyang Chen"

* tag 'sched-core-2026-06-14' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip: (91 commits)
  sched/fair: Fix newidle vs core-sched
  sched/deadline: Use task_on_rq_migrating() helper
  sched/core: Combine separate 'else' and 'if' statements
  sched/fair: Fix cpu_util runnable_avg arithmetic
  sched/fair: Unify cfs_rq throttling via account_cfs_rq_runtime()
  sched/fair: Move the throttled tasks to a local list in tg_unthrottle_up()
  sched/fair: Call update_curr() before unthrottling the hierarchy
  sched/fair: Use throttled_csd_list for local unthrottle
  sched/fair: Convert cfs bandwidth throttling to use guards
  sched/fair: Allocate cfs_tg_state with percpu allocator
  sched/fair: Remove task_group->se pointer array
  sched/fair: Co-locate cfs_rq and sched_entity in cfs_tg_state
  sched: restore timer_slack_ns when resetting RT policy on fork
  MAINTAINERS: Fix spelling mistake in Peter's name
  sched: Simplify ttwu_runnable()
  sched/proxy: Remove superfluous clear_task_blocked_in()
  sched/proxy: Remove PROXY_WAKING
  sched/proxy: Switch proxy to use p->is_blocked
  sched/proxy: Only return migrate when needed
  sched: Be more strict about p->is_blocked
  ...
This commit is contained in:
Linus Torvalds
2026-06-15 14:50:18 +05:30
38 changed files with 3501 additions and 984 deletions
@@ -7215,6 +7215,18 @@ Kernel parameters
Not specifying this option is equivalent to
spec_store_bypass_disable=auto.
split_llc=
[X86,EARLY] Split the LLC N-ways
When set, the LLC is split this many ways by matching
'core_id % n'. This is setup before SMP bringup and
used during SMP bringup before it knows the full
topology. If your core count doesn't nicely divide by
the number given, you get to keep the pieces.
This is mostly a debug feature to emulate multiple LLCs
on hardware that only have a single LLC.
split_lock_detect=
[X86] Enable split lock detection or bus lock detection
+1 -1
View File
@@ -21350,7 +21350,7 @@ F: include/uapi/linux/pps_gen.h
PRESSURE STALL INFORMATION (PSI)
M: Johannes Weiner <hannes@cmpxchg.org>
M: Suren Baghdasaryan <surenb@google.com>
R: Peter Ziljstra <peterz@infradead.org>
R: Peter Zijlstra <peterz@infradead.org>
S: Maintained
F: include/linux/psi*
F: kernel/sched/psi.c
+7
View File
@@ -135,6 +135,13 @@ struct cpumask *cpu_coregroup_mask(int cpu);
const struct cpumask *cpu_die_mask(int cpu);
int cpu_die_id(int cpu);
/*
* Points to where the LLC is. On power9 this will point at CACHE
* domain, On others it will point to SMT domain. In all cases
* cpu_l2_cache_mask points to where LLC is
*/
#define arch_llc_mask(cpu) cpu_l2_cache_mask(cpu)
#ifdef CONFIG_PPC64
#include <asm/smp.h>
+5
View File
@@ -704,6 +704,11 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
return per_cpu(cpu_info.topo.l2c_id, cpu);
}
static inline u32 per_cpu_core_id(unsigned int cpu)
{
return per_cpu(cpu_info.topo.core_id, cpu);
}
#ifdef CONFIG_CPU_SUP_AMD
/*
* Issue a DIV 0/1 insn to clear any division data from previous DIV
+20
View File
@@ -424,6 +424,21 @@ static const struct x86_cpu_id intel_cod_cpu[] = {
{}
};
/*
* Allows splitting the LLC by matching 'core_id % split_llc'.
*
* This is mostly a debug hack to emulate systems with multiple LLCs per node
* on systems that do not naturally have this.
*/
static unsigned int split_llc = 0;
static int __init split_llc_setup(char *str)
{
get_option(&str, &split_llc);
return 0;
}
early_param("split_llc", split_llc_setup);
static bool match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
{
const struct x86_cpu_id *id = x86_match_cpu(intel_cod_cpu);
@@ -438,6 +453,11 @@ static bool match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
if (per_cpu_llc_id(cpu1) != per_cpu_llc_id(cpu2))
return false;
if (split_llc &&
(per_cpu_core_id(cpu1) % split_llc) !=
(per_cpu_core_id(cpu2) % split_llc))
return false;
/*
* Allow the SNC topology without warning. Return of false
* means 'c' does not share the LLC of 'o'. This will be
+23
View File
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/sched.h>
#include <linux/sched/topology.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/sysfs.h>
@@ -68,6 +69,24 @@ bool last_level_cache_is_valid(unsigned int cpu)
}
/*
* Get the cacheinfo of the LLC associated with @cpu.
* Derived from update_per_cpu_data_slice_size_cpu().
*/
struct cacheinfo *get_cpu_cacheinfo_llc(unsigned int cpu)
{
struct cacheinfo *llc;
if (!last_level_cache_is_valid(cpu))
return NULL;
llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1);
if (llc->type != CACHE_TYPE_DATA && llc->type != CACHE_TYPE_UNIFIED)
return NULL;
return llc;
}
bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y)
{
struct cacheinfo *llc_x, *llc_y;
@@ -1018,6 +1037,7 @@ static int cacheinfo_cpu_online(unsigned int cpu)
goto err;
if (cpu_map_shared_cache(true, cpu, &cpu_map))
update_per_cpu_data_slice_size(true, cpu, cpu_map);
sched_update_llc_bytes(cpu);
return 0;
err:
free_cache_attributes(cpu);
@@ -1036,6 +1056,9 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
free_cache_attributes(cpu);
if (nr_shared > 1)
update_per_cpu_data_slice_size(false, cpu, cpu_map);
sched_update_llc_bytes(cpu);
return 0;
}
+1
View File
@@ -89,6 +89,7 @@ int populate_cache_leaves(unsigned int cpu);
int cache_setup_acpi(unsigned int cpu);
bool last_level_cache_is_valid(unsigned int cpu);
bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y);
struct cacheinfo *get_cpu_cacheinfo_llc(unsigned int cpu);
int fetch_cache_info(unsigned int cpu);
int detect_cache_attributes(unsigned int cpu);
#ifndef CONFIG_ACPI_PPTT
+32
View File
@@ -1223,6 +1223,8 @@ struct mm_struct {
/* MM CID related storage */
struct mm_mm_cid mm_cid;
/* sched_cache related statistics */
struct sched_cache_stat sc_stat;
#ifdef CONFIG_MMU
atomic_long_t pgtables_bytes; /* size of all page tables */
#endif
@@ -1619,6 +1621,36 @@ static inline unsigned int mm_cid_size(void)
# define MM_CID_STATIC_SIZE 0
#endif /* CONFIG_SCHED_MM_CID */
#ifdef CONFIG_SCHED_CACHE
void mm_init_sched(struct mm_struct *mm,
struct sched_cache_time __percpu *pcpu_sched);
static inline int mm_alloc_sched_noprof(struct mm_struct *mm)
{
struct sched_cache_time __percpu *pcpu_sched =
alloc_percpu_noprof(struct sched_cache_time);
if (!pcpu_sched)
return -ENOMEM;
mm_init_sched(mm, pcpu_sched);
return 0;
}
#define mm_alloc_sched(...) alloc_hooks(mm_alloc_sched_noprof(__VA_ARGS__))
static inline void mm_destroy_sched(struct mm_struct *mm)
{
free_percpu(mm->sc_stat.pcpu_sched);
mm->sc_stat.pcpu_sched = NULL;
}
#else /* !CONFIG_SCHED_CACHE */
static inline int mm_alloc_sched(struct mm_struct *mm) { return 0; }
static inline void mm_destroy_sched(struct mm_struct *mm) { }
#endif /* CONFIG_SCHED_CACHE */
struct mmu_gather;
extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm);
extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm);
+51 -51
View File
@@ -161,7 +161,7 @@ struct user_event_mm;
*/
#define is_special_task_state(state) \
((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_PARKED | \
TASK_DEAD | TASK_FROZEN))
TASK_DEAD | TASK_WAKING | TASK_FROZEN))
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
# define debug_normal_state_change(state_value) \
@@ -702,6 +702,11 @@ struct sched_dl_entity {
* running, skipping the defer phase.
*
* @dl_defer_idle tracks idle state
*
* @dl_bw_attached tells if this server's bandwidth currently
* contributes to the root domain's total_bw. Only meaningful for server
* entities (@dl_server == 1). Allows toggling the reservation on/off
* without losing the configured @dl_runtime/@dl_period.
*/
unsigned int dl_throttled : 1;
unsigned int dl_yielded : 1;
@@ -713,6 +718,7 @@ struct sched_dl_entity {
unsigned int dl_defer_armed : 1;
unsigned int dl_defer_running : 1;
unsigned int dl_defer_idle : 1;
unsigned int dl_bw_attached : 1;
/*
* Bandwidth enforcement timer. Each -deadline task has its
@@ -846,7 +852,11 @@ struct task_struct {
struct alloc_tag *alloc_tag;
#endif
int on_cpu;
u8 on_cpu;
u8 on_rq;
u8 is_blocked;
u8 __pad;
struct __call_single_node wake_entry;
unsigned int wakee_flips;
unsigned long wakee_flip_decay_ts;
@@ -861,7 +871,6 @@ struct task_struct {
*/
int recent_used_cpu;
int wake_cpu;
int on_rq;
int prio;
int static_prio;
@@ -1243,6 +1252,13 @@ struct task_struct {
struct mutex *blocked_on; /* lock we're blocked on */
raw_spinlock_t blocked_lock;
/*
* The task that is boosting this task; a back link for the current
* donor stack. Set in schedule() -> find_proxy_task() and only stable
* under preempt_disable().
*/
struct task_struct *blocked_donor;
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
/*
* Encoded lock address causing task block (lower 2 bits = type from
@@ -1403,6 +1419,13 @@ struct task_struct {
unsigned long numa_pages_migrated;
#endif /* CONFIG_NUMA_BALANCING */
#ifdef CONFIG_SCHED_CACHE
struct callback_head cache_work;
int preferred_llc;
/* 1: task was enqueued to its preferred LLC, 0 otherwise */
int pref_llc_queued;
#endif
struct rseq_data rseq;
struct sched_mm_cid mm_cid;
@@ -2177,19 +2200,10 @@ extern int __cond_resched_rwlock_write(rwlock_t *lock) __must_hold(lock);
#ifndef CONFIG_PREEMPT_RT
/*
* With proxy exec, if a task has been proxy-migrated, it may be a donor
* on a cpu that it can't actually run on. Thus we need a special state
* to denote that the task is being woken, but that it needs to be
* evaluated for return-migration before it is run. So if the task is
* blocked_on PROXY_WAKING, return migrate it before running it.
*/
#define PROXY_WAKING ((struct mutex *)(-1L))
static inline struct mutex *__get_task_blocked_on(struct task_struct *p)
{
lockdep_assert_held_once(&p->blocked_lock);
return p->blocked_on == PROXY_WAKING ? NULL : p->blocked_on;
return p->blocked_on;
}
static inline void __set_task_blocked_on(struct task_struct *p, struct mutex *m)
@@ -2217,7 +2231,7 @@ static inline void __clear_task_blocked_on(struct task_struct *p, struct mutex *
* blocked_on relationships, but make sure we are not
* clearing the relationship with a different lock.
*/
WARN_ON_ONCE(m && p->blocked_on && p->blocked_on != m && p->blocked_on != PROXY_WAKING);
WARN_ON_ONCE(m && p->blocked_on && p->blocked_on != m);
p->blocked_on = NULL;
}
@@ -2226,35 +2240,6 @@ static inline void clear_task_blocked_on(struct task_struct *p, struct mutex *m)
guard(raw_spinlock_irqsave)(&p->blocked_lock);
__clear_task_blocked_on(p, m);
}
static inline void __set_task_blocked_on_waking(struct task_struct *p, struct mutex *m)
{
/* Currently we serialize blocked_on under the task::blocked_lock */
lockdep_assert_held_once(&p->blocked_lock);
if (!sched_proxy_exec()) {
__clear_task_blocked_on(p, m);
return;
}
/* Don't set PROXY_WAKING if blocked_on was already cleared */
if (!p->blocked_on)
return;
/*
* There may be cases where we set PROXY_WAKING on tasks that were
* already set to waking, but make sure we are not changing
* the relationship with a different lock.
*/
WARN_ON_ONCE(m && p->blocked_on != m && p->blocked_on != PROXY_WAKING);
p->blocked_on = PROXY_WAKING;
}
static inline void set_task_blocked_on_waking(struct task_struct *p, struct mutex *m)
{
guard(raw_spinlock_irqsave)(&p->blocked_lock);
__set_task_blocked_on_waking(p, m);
}
#else
static inline void __clear_task_blocked_on(struct task_struct *p, struct rt_mutex *m)
{
@@ -2263,14 +2248,6 @@ static inline void __clear_task_blocked_on(struct task_struct *p, struct rt_mute
static inline void clear_task_blocked_on(struct task_struct *p, struct rt_mutex *m)
{
}
static inline void __set_task_blocked_on_waking(struct task_struct *p, struct rt_mutex *m)
{
}
static inline void set_task_blocked_on_waking(struct task_struct *p, struct rt_mutex *m)
{
}
#endif /* !CONFIG_PREEMPT_RT */
static __always_inline bool need_resched(void)
@@ -2403,6 +2380,29 @@ static __always_inline int task_mm_cid(struct task_struct *t)
}
#endif
#ifdef CONFIG_SCHED_CACHE
struct sched_cache_time {
u64 runtime;
unsigned long epoch;
};
struct sched_cache_stat {
struct sched_cache_time __percpu *pcpu_sched;
raw_spinlock_t lock;
unsigned long epoch;
u64 nr_running_avg;
unsigned long next_scan;
unsigned long footprint;
int cpu;
} ____cacheline_aligned_in_smp;
#else
struct sched_cache_stat { };
#endif
#ifndef MODULE
#ifndef COMPILE_OFFSETS
+5
View File
@@ -33,6 +33,11 @@ extern u64 sched_clock_cpu(int cpu);
extern void sched_clock_init(void);
#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
static inline int sched_clock_stable(void)
{
return 1;
}
static inline void sched_clock_tick(void)
{
}
-4
View File
@@ -4,16 +4,12 @@
#include <linux/static_key.h>
#ifdef CONFIG_SCHED_SMT
extern struct static_key_false sched_smt_present;
static __always_inline bool sched_smt_active(void)
{
return static_branch_likely(&sched_smt_present);
}
#else
static __always_inline bool sched_smt_active(void) { return false; }
#endif
void arch_smt_update(void);
+31 -1
View File
@@ -67,7 +67,25 @@ struct sched_domain_shared {
atomic_t ref;
atomic_t nr_busy_cpus;
int has_idle_cores;
int nr_idle_scan;
union {
int nr_idle_scan;
/*
* Used during allocation to claim the sched_domain_shared
* object at multiple levels.
*
* Note: between build and the first periodic LB tick, which
* rewrites the union via update_idle_cpu_scan(), readers of
* nr_idle_scan may observe the transient SD_* flag value as
* the scan bound. The flag bits are small positive integers,
* so the effect is just a slightly relaxed scan bound for one
* window and self-heals on the first tick.
*/
int alloc_flags;
};
#ifdef CONFIG_SCHED_CACHE
unsigned long util_avg;
unsigned long capacity;
#endif
};
struct sched_domain {
@@ -99,6 +117,12 @@ struct sched_domain {
u64 max_newidle_lb_cost;
unsigned long last_decay_max_lb_cost;
#ifdef CONFIG_SCHED_CACHE
unsigned int llc_max;
unsigned int *llc_counts __counted_by_ptr(llc_max);
unsigned long llc_bytes;
#endif
#ifdef CONFIG_SCHEDSTATS
/* sched_balance_rq() stats */
unsigned int lb_count[CPU_MAX_IDLE_TYPES];
@@ -256,4 +280,10 @@ static inline int task_node(const struct task_struct *p)
return cpu_to_node(task_cpu(p));
}
#ifdef CONFIG_SCHED_CACHE
extern void sched_update_llc_bytes(unsigned int cpu);
#else
static inline void sched_update_llc_bytes(unsigned int cpu) { }
#endif
#endif /* _LINUX_SCHED_TOPOLOGY_H */
+14 -1
View File
@@ -230,11 +230,24 @@ static inline int cpu_to_mem(int cpu)
#define topology_drawer_cpumask(cpu) cpumask_of(cpu)
#endif
#if defined(CONFIG_SCHED_SMT) && !defined(cpu_smt_mask)
/*
* Defining cpu_smt_mask as cpumask_of that CPU helps to get
* rid of lot of ifdeffery all around the codebase in case of
* CONFIG_SCHED_SMT=n. It just means there are no other siblings, which
* is what is expected.
*/
#if defined(CONFIG_SCHED_SMT)
# if !defined(cpu_smt_mask)
static inline const struct cpumask *cpu_smt_mask(int cpu)
{
return topology_sibling_cpumask(cpu);
}
# endif
#else /* !CONFIG_SCHED_SMT */
static inline const struct cpumask *cpu_smt_mask(int cpu)
{
return cpumask_of(cpu);
}
#endif
#ifndef topology_is_primary_thread
+11
View File
@@ -1016,6 +1016,17 @@ config NUMA_BALANCING
This system will be inactive on UMA systems.
config SCHED_CACHE
bool "Cache aware load balance"
default y
depends on SMP
help
When enabled, the scheduler will attempt to aggregate tasks from
the same process onto a single Last Level Cache (LLC) domain when
possible. This improves cache locality by keeping tasks that share
resources within the same cache domain, reducing cache misses and
lowering data access latency.
config NUMA_BALANCING_DEFAULT_ENABLED
bool "Automatically enable NUMA aware memory/task placement"
default y
+5
View File
@@ -210,6 +210,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.mems_allowed_seq = SEQCNT_SPINLOCK_ZERO(init_task.mems_allowed_seq,
&init_task.alloc_lock),
#endif
.blocked_donor = NULL,
#ifdef CONFIG_RT_MUTEXES
.pi_waiters = RB_ROOT_CACHED,
.pi_top_task = NULL,
@@ -225,6 +226,10 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.numa_group = NULL,
.numa_faults = NULL,
#endif
#ifdef CONFIG_SCHED_CACHE
.preferred_llc = -1,
.pref_llc_queued = 0,
#endif
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
.kasan_depth = 1,
#endif
+29
View File
@@ -543,6 +543,32 @@ void mm_update_next_owner(struct mm_struct *mm)
}
#endif /* CONFIG_MEMCG */
#if defined(CONFIG_SCHED_CACHE) && defined(CONFIG_NUMA_BALANCING)
/*
* Subtract the memory footprint of the current task from
* mm.
*/
static void exit_mm_sched_cache(struct mm_struct *mm)
{
unsigned long fp, sub;
if (!current->total_numa_faults)
return;
/*
* No lock protection due to performance considerations.
* Make sure mm->sc_stat.footprint does not become
* negative.
*/
fp = READ_ONCE(mm->sc_stat.footprint);
sub = min(fp, current->total_numa_faults);
WRITE_ONCE(mm->sc_stat.footprint, fp - sub);
}
#else
static inline void exit_mm_sched_cache(struct mm_struct *mm)
{
}
#endif /* CONFIG_SCHED_CACHE CONFIG_NUMA_BALANCING */
/*
* Turn us into a lazy TLB process if we
* aren't already..
@@ -554,6 +580,9 @@ static void exit_mm(void)
exit_mm_release(current, mm);
if (!mm)
return;
exit_mm_sched_cache(mm);
mmap_read_lock(mm);
mmgrab_lazy_tlb(mm);
BUG_ON(mm != current->active_mm);
+7
View File
@@ -728,6 +728,7 @@ void __mmdrop(struct mm_struct *mm)
cleanup_lazy_tlbs(mm);
WARN_ON_ONCE(mm == current->active_mm);
mm_destroy_sched(mm);
mm_free_pgd(mm);
mm_free_id(mm);
destroy_context(mm);
@@ -1128,6 +1129,9 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
if (mm_alloc_cid(mm, p))
goto fail_cid;
if (mm_alloc_sched(mm))
goto fail_sched;
if (percpu_counter_init_many(mm->rss_stat, 0, GFP_KERNEL_ACCOUNT,
NR_MM_COUNTERS))
goto fail_pcpu;
@@ -1136,6 +1140,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
return mm;
fail_pcpu:
mm_destroy_sched(mm);
fail_sched:
mm_destroy_cid(mm);
fail_cid:
destroy_context(mm);
@@ -2234,6 +2240,7 @@ __latent_entropy struct task_struct *copy_process(
lockdep_init_task(p);
p->blocked_on = NULL; /* not blocked yet */
p->blocked_donor = NULL; /* nobody is boosting p yet */
#ifdef CONFIG_BCACHE
p->sequential_io = 0;
+55 -8
View File
@@ -763,6 +763,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
raw_spin_lock_irqsave(&lock->wait_lock, flags);
raw_spin_lock(&current->blocked_lock);
__set_task_blocked_on(current, lock);
set_current_state(state);
if (opt_acquired)
break;
@@ -980,15 +981,22 @@ EXPORT_SYMBOL_GPL(ww_mutex_lock_interruptible);
static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigned long ip)
__releases(lock)
{
struct task_struct *next = NULL;
struct task_struct *donor, *next = NULL;
struct mutex_waiter *waiter;
DEFINE_WAKE_Q(wake_q);
unsigned long owner;
unsigned long flags;
mutex_release(&lock->dep_map, ip);
__release(lock);
/*
* Ensures the proxy donor stack is stable across unlock and handoff.
* Specifically, it avoids the case where current->blocked_donor is
* NULL when it is inspected while doing the unlock, but a preemption
* before taking the wake_lock would make it set and a hand-off is
* missed.
*/
guard(preempt)();
/*
* Release the lock before (potentially) taking the spinlock such that
* other contenders can get on with things ASAP.
@@ -1001,6 +1009,12 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
MUTEX_WARN_ON(__owner_task(owner) != current);
MUTEX_WARN_ON(owner & MUTEX_FLAG_PICKUP);
if (sched_proxy_exec() && current->blocked_donor) {
/* force handoff if we have a blocked_donor */
owner = MUTEX_FLAG_HANDOFF;
break;
}
if (owner & MUTEX_FLAG_HANDOFF)
break;
@@ -1013,14 +1027,42 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
}
raw_spin_lock_irqsave(&lock->wait_lock, flags);
raw_spin_lock(&current->blocked_lock);
debug_mutex_unlock(lock);
waiter = lock->first_waiter;
if (waiter) {
next = waiter->task;
if (sched_proxy_exec()) {
/*
* If we have a task boosting current, and that task was boosting
* current through this lock, hand the lock to that task, as that
* is the highest waiter, as selected by the scheduling function.
*/
donor = current->blocked_donor;
if (donor) {
struct mutex *next_lock;
raw_spin_lock_nested(&donor->blocked_lock, SINGLE_DEPTH_NESTING);
next_lock = __get_task_blocked_on(donor);
if (next_lock == lock) {
next = get_task_struct(donor);
__clear_task_blocked_on(next, lock);
current->blocked_donor = NULL;
}
raw_spin_unlock(&donor->blocked_lock);
}
}
/*
* Failing that, pick first on the wait list.
*/
waiter = lock->first_waiter;
if (!next && waiter) {
next = get_task_struct(waiter->task);
raw_spin_lock_nested(&next->blocked_lock, SINGLE_DEPTH_NESTING);
debug_mutex_wake_waiter(lock, waiter);
set_task_blocked_on_waking(next, lock);
wake_q_add(&wake_q, next);
__clear_task_blocked_on(next, lock);
raw_spin_unlock(&next->blocked_lock);
}
if (trace_contended_release_enabled() && waiter)
@@ -1029,7 +1071,12 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
if (owner & MUTEX_FLAG_HANDOFF)
__mutex_handoff(lock, next);
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
raw_spin_unlock(&current->blocked_lock);
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
if (next) {
wake_up_process(next);
put_task_struct(next);
}
}
#ifndef CONFIG_DEBUG_LOCK_ALLOC
+2 -2
View File
@@ -324,7 +324,7 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,
* blocked_on to PROXY_WAKING. Otherwise we can see
* circular blocked_on relationships that can't resolve.
*/
set_task_blocked_on_waking(waiter->task, lock);
clear_task_blocked_on(waiter->task, lock);
wake_q_add(wake_q, waiter->task);
}
@@ -383,7 +383,7 @@ static bool __ww_mutex_wound(struct MUTEX *lock,
* are waking the mutex owner, who may be currently
* blocked on a different mutex.
*/
set_task_blocked_on_waking(owner, NULL);
clear_task_blocked_on(owner, NULL);
wake_q_add(wake_q, owner);
}
return true;
+234 -205
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More