diff options
author | Thomas Gleixner <[email protected]> | 2017-10-16 16:16:19 +0200 |
---|---|---|
committer | Thomas Gleixner <[email protected]> | 2017-10-17 16:45:09 +0200 |
commit | 0696d059f23c05f2dbc3b19ef50e5bdd175b782b (patch) | |
tree | e06b5344da043b2a7d1f5a0af687c83317a4d769 | |
parent | 02edee152d6ea325c88898f3a702f5db2d78de7a (diff) |
x86/vector: Use correct per cpu variable in free_moved_vector()
free_moved_vector() accesses the per cpu vector array with this_cpu_write()
to clear the vector. The function has two call sites:
1) The vector cleanup IPI
2) The force_complete_move() code path
For #1 this_cpu_write() is correct as it runs on the CPU on which the
vector needs to be freed.
For #2 this_cpu_write() is wrong because the function is called from an
outgoing CPU which is not necessarily the CPU on which the previous vector
needs to be freed. As a result it sets the vector on the outgoing CPU to
NULL, which is pointless as that CPU does not handle interrupts
anymore. What's worse is that it leaves the vector on the previous target
CPU in place which later on triggers the BUG_ON(vector) in the vector
allocation code when the vector gets reused. That's possible because the
bitmap allocator entry of that CPU is freed correctly.
Always use the CPU to which the vector was associated and clear the vector
entry on that CPU. Fixup the tracepoint as well so it tracks on which CPU
the vector gets removed.
Fixes: 69cde0004a4b ("x86/vector: Use matrix allocator for vector assignment")
Reported-by: Petri Latvala <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: Juergen Gross <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Len Brown <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Joerg Roedel <[email protected]>
Cc: "Rafael J. Wysocki" <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Rui Zhang <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Boris Ostrovsky <[email protected]>
Cc: "K. Y. Srinivasan" <[email protected]>
Cc: Arjan van de Ven <[email protected]>
Cc: Alok Kataria <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: Yu Chen <[email protected]>
Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1710161614430.1973@nanos
-rw-r--r-- | arch/x86/include/asm/trace/irq_vectors.h | 12 | ||||
-rw-r--r-- | arch/x86/kernel/apic/vector.c | 4 |
2 files changed, 10 insertions, 6 deletions
diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h index bc09c5cf6390..bfd480b827f5 100644 --- a/arch/x86/include/asm/trace/irq_vectors.h +++ b/arch/x86/include/asm/trace/irq_vectors.h @@ -360,24 +360,28 @@ TRACE_EVENT(vector_setup, TRACE_EVENT(vector_free_moved, - TP_PROTO(unsigned int irq, unsigned int vector, bool is_managed), + TP_PROTO(unsigned int irq, unsigned int cpu, unsigned int vector, + bool is_managed), - TP_ARGS(irq, vector, is_managed), + TP_ARGS(irq, cpu, vector, is_managed), TP_STRUCT__entry( __field( unsigned int, irq ) + __field( unsigned int, cpu ) __field( unsigned int, vector ) __field( bool, is_managed ) ), TP_fast_assign( __entry->irq = irq; + __entry->cpu = cpu; __entry->vector = vector; __entry->is_managed = is_managed; ), - TP_printk("irq=%u vector=%u is_managed=%d", - __entry->irq, __entry->vector, __entry->is_managed) + TP_printk("irq=%u cpu=%u vector=%u is_managed=%d", + __entry->irq, __entry->cpu, __entry->vector, + __entry->is_managed) ); diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 573538e0981e..05c85e693a5d 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -797,9 +797,9 @@ static void free_moved_vector(struct apic_chip_data *apicd) */ WARN_ON_ONCE(managed); - trace_vector_free_moved(apicd->irq, vector, managed); + trace_vector_free_moved(apicd->irq, cpu, vector, managed); irq_matrix_free(vector_matrix, cpu, vector, managed); - __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); + per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; hlist_del_init(&apicd->clist); apicd->prev_vector = 0; apicd->move_in_progress = 0; |