Skip to content

Commit cddc81f

Browse files
author
CKI KWF Bot
committed
Merge: smp: Backport fix and cleanup patches for kernel/smp.c
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1590 JIRA: https://issues.redhat.com/browse/RHEL-121178 MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1590 This MR backports a number of fix and cleanup patches for kernel/smp.c in an attempt to address the soft lockup problem reported in the Jira ticket. Signed-off-by: Waiman Long <longman@redhat.com> Approved-by: Aristeu Rozanski <arozansk@redhat.com> Approved-by: Rafael Aquini <raquini@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents c98974e + 949cb79 commit cddc81f

File tree

1 file changed

+37
-45
lines changed

1 file changed

+37
-45
lines changed

kernel/smp.c

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ int smpcfd_dead_cpu(unsigned int cpu)
8686
int smpcfd_dying_cpu(unsigned int cpu)
8787
{
8888
/*
89-
* The IPIs for the smp-call-function callbacks queued by other
90-
* CPUs might arrive late, either due to hardware latencies or
91-
* because this CPU disabled interrupts (inside stop-machine)
92-
* before the IPIs were sent. So flush out any pending callbacks
93-
* explicitly (without waiting for the IPIs to arrive), to
94-
* ensure that the outgoing CPU doesn't go offline with work
95-
* still pending.
89+
* The IPIs for the smp-call-function callbacks queued by other CPUs
90+
* might arrive late, either due to hardware latencies or because this
91+
* CPU disabled interrupts (inside stop-machine) before the IPIs were
92+
* sent. So flush out any pending callbacks explicitly (without waiting
93+
* for the IPIs to arrive), to ensure that the outgoing CPU doesn't go
94+
* offline with work still pending.
95+
*
96+
* This runs with interrupts disabled inside the stopper task invoked by
97+
* stop_machine(), ensuring mutually exclusive CPU offlining and IPI flush.
9698
*/
9799
__flush_smp_call_function_queue(false);
98100
irq_work_run();
@@ -418,6 +420,10 @@ void __smp_call_single_queue(int cpu, struct llist_node *node)
418420
*/
419421
static int generic_exec_single(int cpu, call_single_data_t *csd)
420422
{
423+
/*
424+
* Preemption already disabled here so stopper cannot run on this CPU,
425+
* ensuring mutually exclusive CPU offlining and last IPI flush.
426+
*/
421427
if (cpu == smp_processor_id()) {
422428
smp_call_func_t func = csd->func;
423429
void *info = csd->info;
@@ -638,8 +644,10 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
638644
int err;
639645

640646
/*
641-
* prevent preemption and reschedule on another processor,
642-
* as well as CPU removal
647+
* Prevent preemption and reschedule on another CPU, as well as CPU
648+
* removal. This prevents stopper from running on this CPU, thus
649+
* providing mutual exclusion of the below cpu_online() check and
650+
* IPI sending ensuring IPI are not missed by CPU going offline.
643651
*/
644652
this_cpu = get_cpu();
645653

@@ -741,32 +749,19 @@ EXPORT_SYMBOL_GPL(smp_call_function_single_async);
741749
*
742750
* Selection preference:
743751
* 1) current cpu if in @mask
744-
* 2) any cpu of current node if in @mask
745-
* 3) any other online cpu in @mask
752+
* 2) nearest cpu in @mask, based on NUMA topology
746753
*/
747754
int smp_call_function_any(const struct cpumask *mask,
748755
smp_call_func_t func, void *info, int wait)
749756
{
750757
unsigned int cpu;
751-
const struct cpumask *nodemask;
752758
int ret;
753759

754760
/* Try for same CPU (cheapest) */
755761
cpu = get_cpu();
756-
if (cpumask_test_cpu(cpu, mask))
757-
goto call;
758-
759-
/* Try for same node. */
760-
nodemask = cpumask_of_node(cpu_to_node(cpu));
761-
for (cpu = cpumask_first_and(nodemask, mask); cpu < nr_cpu_ids;
762-
cpu = cpumask_next_and(cpu, nodemask, mask)) {
763-
if (cpu_online(cpu))
764-
goto call;
765-
}
762+
if (!cpumask_test_cpu(cpu, mask))
763+
cpu = sched_numa_find_nth_cpu(mask, 0, cpu_to_node(cpu));
766764

767-
/* Any online will do: smp_call_function_single handles nr_cpu_ids. */
768-
cpu = cpumask_any_and(mask, cpu_online_mask);
769-
call:
770765
ret = smp_call_function_single(cpu, func, info, wait);
771766
put_cpu();
772767
return ret;
@@ -792,7 +787,6 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
792787
bool wait = scf_flags & SCF_WAIT;
793788
int nr_cpus = 0;
794789
bool run_remote = false;
795-
bool run_local = false;
796790

797791
lockdep_assert_preemption_disabled();
798792

@@ -814,18 +808,8 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
814808
*/
815809
WARN_ON_ONCE(!in_task());
816810

817-
/* Check if we need local execution. */
818-
if ((scf_flags & SCF_RUN_LOCAL) && cpumask_test_cpu(this_cpu, mask))
819-
run_local = true;
820-
821811
/* Check if we need remote execution, i.e., any CPU excluding this one. */
822-
cpu = cpumask_first_and(mask, cpu_online_mask);
823-
if (cpu == this_cpu)
824-
cpu = cpumask_next_and(cpu, mask, cpu_online_mask);
825-
if (cpu < nr_cpu_ids)
826-
run_remote = true;
827-
828-
if (run_remote) {
812+
if (cpumask_any_and_but(mask, cpu_online_mask, this_cpu) < nr_cpu_ids) {
829813
cfd = this_cpu_ptr(&cfd_data);
830814
cpumask_and(cfd->cpumask, mask, cpu_online_mask);
831815
__cpumask_clear_cpu(this_cpu, cfd->cpumask);
@@ -839,6 +823,9 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
839823
continue;
840824
}
841825

826+
/* Work is enqueued on a remote CPU. */
827+
run_remote = true;
828+
842829
csd_lock(csd);
843830
if (wait)
844831
csd->node.u_flags |= CSD_TYPE_SYNC;
@@ -850,6 +837,10 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
850837
#endif
851838
trace_csd_queue_cpu(cpu, _RET_IP_, func, csd);
852839

840+
/*
841+
* Kick the remote CPU if this is the first work
842+
* item enqueued.
843+
*/
853844
if (llist_add(&csd->node.llist, &per_cpu(call_single_queue, cpu))) {
854845
__cpumask_set_cpu(cpu, cfd->cpumask_ipi);
855846
nr_cpus++;
@@ -868,7 +859,9 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
868859
send_call_function_ipi_mask(cfd->cpumask_ipi);
869860
}
870861

871-
if (run_local && (!cond_func || cond_func(this_cpu, info))) {
862+
/* Check if we need local execution. */
863+
if ((scf_flags & SCF_RUN_LOCAL) && cpumask_test_cpu(this_cpu, mask) &&
864+
(!cond_func || cond_func(this_cpu, info))) {
872865
unsigned long flags;
873866

874867
local_irq_save(flags);
@@ -891,16 +884,15 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
891884
* @mask: The set of cpus to run on (only runs on online subset).
892885
* @func: The function to run. This must be fast and non-blocking.
893886
* @info: An arbitrary pointer to pass to the function.
894-
* @wait: Bitmask that controls the operation. If %SCF_WAIT is set, wait
895-
* (atomically) until function has completed on other CPUs. If
896-
* %SCF_RUN_LOCAL is set, the function will also be run locally
897-
* if the local CPU is set in the @cpumask.
898-
*
899-
* If @wait is true, then returns once @func has returned.
887+
* @wait: If true, wait (atomically) until function has completed
888+
* on other CPUs.
900889
*
901890
* You must not call this function with disabled interrupts or from a
902891
* hardware interrupt handler or from a bottom half handler. Preemption
903892
* must be disabled when calling this function.
893+
*
894+
* @func is not called on the local CPU even if @mask contains it. Consider
895+
* using on_each_cpu_cond_mask() instead if this is not desirable.
904896
*/
905897
void smp_call_function_many(const struct cpumask *mask,
906898
smp_call_func_t func, void *info, bool wait)
@@ -1025,7 +1017,7 @@ void __init smp_init(void)
10251017
* @cond_func: A callback function that is passed a cpu id and
10261018
* the info parameter. The function is called
10271019
* with preemption disabled. The function should
1028-
* return a blooean value indicating whether to IPI
1020+
* return a boolean value indicating whether to IPI
10291021
* the specified CPU.
10301022
* @func: The function to run on all applicable CPUs.
10311023
* This must be fast and non-blocking.

0 commit comments

Comments
 (0)