Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit a6c11c0

Browse files
Dongli ZhangKAGA-KOKO
authored andcommitted
genirq/cpuhotplug, x86/vector: Prevent vector leak during CPU offline
The absence of IRQD_MOVE_PCNTXT prevents immediate effectiveness of interrupt affinity reconfiguration via procfs. Instead, the change is deferred until the next instance of the interrupt being triggered on the original CPU. When the interrupt next triggers on the original CPU, the new affinity is enforced within __irq_move_irq(). A vector is allocated from the new CPU, but the old vector on the original CPU remains and is not immediately reclaimed. Instead, apicd->move_in_progress is flagged, and the reclaiming process is delayed until the next trigger of the interrupt on the new CPU. Upon the subsequent triggering of the interrupt on the new CPU, irq_complete_move() adds a task to the old CPU's vector_cleanup list if it remains online. Subsequently, the timer on the old CPU iterates over its vector_cleanup list, reclaiming old vectors. However, a rare scenario arises if the old CPU is outgoing before the interrupt triggers again on the new CPU. In that case irq_force_complete_move() is not invoked on the outgoing CPU to reclaim the old apicd->prev_vector because the interrupt isn't currently affine to the outgoing CPU, and irq_needs_fixup() returns false. Even though __vector_schedule_cleanup() is later called on the new CPU, it doesn't reclaim apicd->prev_vector; instead, it simply resets both apicd->move_in_progress and apicd->prev_vector to 0. As a result, the vector remains unreclaimed in vector_matrix, leading to a CPU vector leak. To address this issue, move the invocation of irq_force_complete_move() before the irq_needs_fixup() call to reclaim apicd->prev_vector, if the interrupt is currently or used to be affine to the outgoing CPU. Additionally, reclaim the vector in __vector_schedule_cleanup() as well, following a warning message, although theoretically it should never see apicd->move_in_progress with apicd->prev_cpu pointing to an offline CPU. Fixes: f0383c2 ("genirq/cpuhotplug: Add support for cleaning up move in progress") Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240522220218.162423-1-dongli.zhang@oracle.com
1 parent 88d68bb commit a6c11c0

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed

arch/x86/kernel/apic/vector.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,8 @@ static void __vector_schedule_cleanup(struct apic_chip_data *apicd)
10351035
add_timer_on(&cl->timer, cpu);
10361036
}
10371037
} else {
1038-
apicd->prev_vector = 0;
1038+
pr_warn("IRQ %u schedule cleanup for offline CPU %u\n", apicd->irq, cpu);
1039+
free_moved_vector(apicd);
10391040
}
10401041
raw_spin_unlock(&vector_lock);
10411042
}
@@ -1072,6 +1073,7 @@ void irq_complete_move(struct irq_cfg *cfg)
10721073
*/
10731074
void irq_force_complete_move(struct irq_desc *desc)
10741075
{
1076+
unsigned int cpu = smp_processor_id();
10751077
struct apic_chip_data *apicd;
10761078
struct irq_data *irqd;
10771079
unsigned int vector;
@@ -1096,10 +1098,11 @@ void irq_force_complete_move(struct irq_desc *desc)
10961098
goto unlock;
10971099

10981100
/*
1099-
* If prev_vector is empty, no action required.
1101+
* If prev_vector is empty or the descriptor is neither currently
1102+
* nor previously on the outgoing CPU no action required.
11001103
*/
11011104
vector = apicd->prev_vector;
1102-
if (!vector)
1105+
if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu))
11031106
goto unlock;
11041107

11051108
/*

kernel/irq/cpuhotplug.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ static bool migrate_one_irq(struct irq_desc *desc)
6969
return false;
7070
}
7171

72+
/*
73+
* Complete an eventually pending irq move cleanup. If this
74+
* interrupt was moved in hard irq context, then the vectors need
75+
* to be cleaned up. It can't wait until this interrupt actually
76+
* happens and this CPU was involved.
77+
*/
78+
irq_force_complete_move(desc);
79+
7280
/*
7381
* No move required, if:
7482
* - Interrupt is per cpu
@@ -87,14 +95,6 @@ static bool migrate_one_irq(struct irq_desc *desc)
8795
return false;
8896
}
8997

90-
/*
91-
* Complete an eventually pending irq move cleanup. If this
92-
* interrupt was moved in hard irq context, then the vectors need
93-
* to be cleaned up. It can't wait until this interrupt actually
94-
* happens and this CPU was involved.
95-
*/
96-
irq_force_complete_move(desc);
97-
9898
/*
9999
* If there is a setaffinity pending, then try to reuse the pending
100100
* mask, so the last change of the affinity does not get lost. If

0 commit comments

Comments
 (0)