diff options
| author | Tim Chen <tim.c.chen@linux.intel.com> | 2026-09-21 17:37:22 -0700 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2026-09-22 10:49:53 +0200 |
| commit | 0d6526f82c3cdefcca47f73f5fc08dc6f335eac6 (patch) | |
| tree | 176dc2d685debcfb082c151ee94f2425ac96b364 /scripts/atomic/fallbacks | |
| download | linux-stable-0d6526f82c3cdefcca47f73f5fc08dc6f335eac6.tar.gz linux-stable-0d6526f82c3cdefcca47f73f5fc08dc6f335eac6.zip | |
sched/cache: Keep nr_pref_llc_running in the runnable domain, to fix LLC mis-scheduling buggrafted
alb_break_llc() decides whether to break LLC preference during active
load balance. It does so by testing that every runnable fair task on the
source rq prefers its LLC:
env->src_rq->nr_pref_llc_running == env->src_rq->cfs.h_nr_runnable
But the two counters cover different sets. nr_pref_llc_running is updated
in account_llc_enqueue()/account_llc_dequeue(), next to cfs_rq->nr_queued,
so it follows queued tasks. h_nr_runnable is updated in set_delayed()/
clear_delayed() and drops delay-dequeued tasks.
So under DELAY_DEQUEUE, a preferring task that goes to sleep stays counted
in nr_pref_llc_running while h_nr_runnable falls. The equality then breaks,
alb_break_llc() returns false, and active balance is free to pull a task
off its preferred LLC. Active balance only moves runnable tasks, and this
is the only LLC check it consults: once the stopper runs, LBF_ACTIVE_LB
skips the per-task test in can_migrate_task(). The runnable set is the one
we want.
Fix it on the counter side. A task should be counted in
nr_pref_llc_running exactly while it is both queued on its preferred LLC
(pref_llc_queued) and runnable (!sched_delayed). Define that membership
once in task_pref_llc_runnable(), and adjust the counter only through
pref_llc_running_inc()/pref_llc_running_dec() from the four sites that
change either input: account_llc_enqueue(), account_llc_dequeue(),
set_delayed() and clear_delayed(). Gating every update on the same
predicate keeps the delay, wake and dequeue paths from double-counting
or underflowing; see the comments at those sites for the ordering.
nr_llc_running and sd->llc_counts are not touched and stay on queued
semantics.
Fixes: 714059f79ff0 ("sched/cache: Handle moving single tasks to/from their preferred LLC")
Closes: https://lore.kernel.org/lkml/20260827135000.735138-1-zhanxusheng@xiaomi.com/
Reported-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Suggested-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kayra Cizmeci <kayracizmeci@gmail.com>
Cc: <stable@kernel.org> # v7.2.x
Link: https://patch.msgid.link/06af61afedac32e6477f57feb4d658f6c411c3af.1790035273.git.tim.c.chen@linux.intel.com
Diffstat (limited to 'scripts/atomic/fallbacks')
| -rwxr-xr-x | scripts/atomic/fallbacks/acquire | 5 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/add_negative | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/add_unless | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/andnot | 3 | ||||
| -rw-r--r-- | scripts/atomic/fallbacks/cmpxchg | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/dec | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/dec_and_test | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/dec_if_positive | 11 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/dec_unless_positive | 10 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/fence | 7 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/fetch_add_unless | 10 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/inc | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/inc_and_test | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/inc_not_zero | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/inc_unless_negative | 10 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/read_acquire | 12 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/release | 4 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/set_release | 8 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/sub_and_test | 3 | ||||
| -rwxr-xr-x | scripts/atomic/fallbacks/try_cmpxchg | 7 | ||||
| -rw-r--r-- | scripts/atomic/fallbacks/xchg | 3 |
21 files changed, 117 insertions, 0 deletions
diff --git a/scripts/atomic/fallbacks/acquire b/scripts/atomic/fallbacks/acquire new file mode 100755 index 000000000..4da0cab36 --- /dev/null +++ b/scripts/atomic/fallbacks/acquire @@ -0,0 +1,5 @@ +cat <<EOF + ${ret} ret = arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args}); + __atomic_acquire_fence(); + return ret; +EOF diff --git a/scripts/atomic/fallbacks/add_negative b/scripts/atomic/fallbacks/add_negative new file mode 100755 index 000000000..1d3d4ab3a --- /dev/null +++ b/scripts/atomic/fallbacks/add_negative @@ -0,0 +1,3 @@ +cat <<EOF + return raw_${atomic}_add_return${order}(i, v) < 0; +EOF diff --git a/scripts/atomic/fallbacks/add_unless b/scripts/atomic/fallbacks/add_unless new file mode 100755 index 000000000..95ecb2b74 --- /dev/null +++ b/scripts/atomic/fallbacks/add_unless @@ -0,0 +1,3 @@ +cat << EOF + return raw_${atomic}_fetch_add_unless(v, a, u) != u; +EOF diff --git a/scripts/atomic/fallbacks/andnot b/scripts/atomic/fallbacks/andnot new file mode 100755 index 000000000..66760457e --- /dev/null +++ b/scripts/atomic/fallbacks/andnot @@ -0,0 +1,3 @@ +cat <<EOF + ${retstmt}raw_${atomic}_${pfx}and${sfx}${order}(~i, v); +EOF diff --git a/scripts/atomic/fallbacks/cmpxchg b/scripts/atomic/fallbacks/cmpxchg new file mode 100644 index 000000000..1c8507f62 --- /dev/null +++ b/scripts/atomic/fallbacks/cmpxchg @@ -0,0 +1,3 @@ +cat <<EOF + return raw_cmpxchg${order}(&v->counter, old, new); +EOF diff --git a/scripts/atomic/fallbacks/dec b/scripts/atomic/fallbacks/dec new file mode 100755 index 000000000..60d286d40 --- /dev/null +++ b/scripts/atomic/fallbacks/dec @@ -0,0 +1,3 @@ +cat <<EOF + ${retstmt}raw_${atomic}_${pfx}sub${sfx}${order}(1, v); +EOF diff --git a/scripts/atomic/fallbacks/dec_and_test b/scripts/atomic/fallbacks/dec_and_test new file mode 100755 index 000000000..3a0278e0d --- /dev/null +++ b/scripts/atomic/fallbacks/dec_and_test @@ -0,0 +1,3 @@ +cat <<EOF + return raw_${atomic}_dec_return(v) == 0; +EOF diff --git a/scripts/atomic/fallbacks/dec_if_positive b/scripts/atomic/fallbacks/dec_if_positive new file mode 100755 index 000000000..f65c11b4b --- /dev/null +++ b/scripts/atomic/fallbacks/dec_if_positive @@ -0,0 +1,11 @@ +cat <<EOF + ${int} dec, c = raw_${atomic}_read(v); + + do { + dec = c - 1; + if (unlikely(dec < 0)) + break; + } while (!raw_${atomic}_try_cmpxchg(v, &c, dec)); + + return dec; +EOF diff --git a/scripts/atomic/fallbacks/dec_unless_positive b/scripts/atomic/fallbacks/dec_unless_positive new file mode 100755 index 000000000..d025361d7 --- /dev/null +++ b/scripts/atomic/fallbacks/dec_unless_positive @@ -0,0 +1,10 @@ +cat <<EOF + ${int} c = raw_${atomic}_read(v); + + do { + if (unlikely(c > 0)) + return false; + } while (!raw_${atomic}_try_cmpxchg(v, &c, c - 1)); + + return true; +EOF diff --git a/scripts/atomic/fallbacks/fence b/scripts/atomic/fallbacks/fence new file mode 100755 index 000000000..40d5b3976 --- /dev/null +++ b/scripts/atomic/fallbacks/fence @@ -0,0 +1,7 @@ +cat <<EOF + ${ret} ret; + __atomic_pre_full_fence(); + ret = arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args}); + __atomic_post_full_fence(); + return ret; +EOF diff --git a/scripts/atomic/fallbacks/fetch_add_unless b/scripts/atomic/fallbacks/fetch_add_unless new file mode 100755 index 000000000..8db7e9e17 --- /dev/null +++ b/scripts/atomic/fallbacks/fetch_add_unless @@ -0,0 +1,10 @@ +cat << EOF + ${int} c = raw_${atomic}_read(v); + + do { + if (unlikely(c == u)) + break; + } while (!raw_${atomic}_try_cmpxchg(v, &c, c + a)); + + return c; +EOF diff --git a/scripts/atomic/fallbacks/inc b/scripts/atomic/fallbacks/inc new file mode 100755 index 000000000..56c770f59 --- /dev/null +++ b/scripts/atomic/fallbacks/inc @@ -0,0 +1,3 @@ +cat <<EOF + ${retstmt}raw_${atomic}_${pfx}add${sfx}${order}(1, v); +EOF diff --git a/scripts/atomic/fallbacks/inc_and_test b/scripts/atomic/fallbacks/inc_and_test new file mode 100755 index 000000000..7d16a10f2 --- /dev/null +++ b/scripts/atomic/fallbacks/inc_and_test @@ -0,0 +1,3 @@ +cat <<EOF + return raw_${atomic}_inc_return(v) == 0; +EOF diff --git a/scripts/atomic/fallbacks/inc_not_zero b/scripts/atomic/fallbacks/inc_not_zero new file mode 100755 index 000000000..1fcef1e55 --- /dev/null +++ b/scripts/atomic/fallbacks/inc_not_zero @@ -0,0 +1,3 @@ +cat <<EOF + return raw_${atomic}_add_unless(v, 1, 0); +EOF diff --git a/scripts/atomic/fallbacks/inc_unless_negative b/scripts/atomic/fallbacks/inc_unless_negative new file mode 100755 index 000000000..7b4b09868 --- /dev/null +++ b/scripts/atomic/fallbacks/inc_unless_negative @@ -0,0 +1,10 @@ +cat <<EOF + ${int} c = raw_${atomic}_read(v); + + do { + if (unlikely(c < 0)) + return false; + } while (!raw_${atomic}_try_cmpxchg(v, &c, c + 1)); + + return true; +EOF diff --git a/scripts/atomic/fallbacks/read_acquire b/scripts/atomic/fallbacks/read_acquire new file mode 100755 index 000000000..e319862d2 --- /dev/null +++ b/scripts/atomic/fallbacks/read_acquire @@ -0,0 +1,12 @@ +cat <<EOF + ${int} ret; + + if (__native_word(${atomic}_t)) { + ret = smp_load_acquire(&(v)->counter); + } else { + ret = raw_${atomic}_read(v); + __atomic_acquire_fence(); + } + + return ret; +EOF diff --git a/scripts/atomic/fallbacks/release b/scripts/atomic/fallbacks/release new file mode 100755 index 000000000..1e6daf57b --- /dev/null +++ b/scripts/atomic/fallbacks/release @@ -0,0 +1,4 @@ +cat <<EOF + __atomic_release_fence(); + ${retstmt}arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args}); +EOF diff --git a/scripts/atomic/fallbacks/set_release b/scripts/atomic/fallbacks/set_release new file mode 100755 index 000000000..16a374ae6 --- /dev/null +++ b/scripts/atomic/fallbacks/set_release @@ -0,0 +1,8 @@ +cat <<EOF + if (__native_word(${atomic}_t)) { + smp_store_release(&(v)->counter, i); + } else { + __atomic_release_fence(); + raw_${atomic}_set(v, i); + } +EOF diff --git a/scripts/atomic/fallbacks/sub_and_test b/scripts/atomic/fallbacks/sub_and_test new file mode 100755 index 000000000..d1f746fe0 --- /dev/null +++ b/scripts/atomic/fallbacks/sub_and_test @@ -0,0 +1,3 @@ +cat <<EOF + return raw_${atomic}_sub_return(i, v) == 0; +EOF diff --git a/scripts/atomic/fallbacks/try_cmpxchg b/scripts/atomic/fallbacks/try_cmpxchg new file mode 100755 index 000000000..d4da82092 --- /dev/null +++ b/scripts/atomic/fallbacks/try_cmpxchg @@ -0,0 +1,7 @@ +cat <<EOF + ${int} r, o = *old; + r = raw_${atomic}_cmpxchg${order}(v, o, new); + if (unlikely(r != o)) + *old = r; + return likely(r == o); +EOF diff --git a/scripts/atomic/fallbacks/xchg b/scripts/atomic/fallbacks/xchg new file mode 100644 index 000000000..e4def1e0d --- /dev/null +++ b/scripts/atomic/fallbacks/xchg @@ -0,0 +1,3 @@ +cat <<EOF + return raw_xchg${order}(&v->counter, new); +EOF |
