On Mon, Jun 4, 2018 at 8:33 AM, Thomas Gleixner <tglx@xxxxxxxxxxxxx> wrote: > Several people observed the WARN_ON() in irq_matrix_free() which triggers > when the caller tries to free an vector which is not in the allocation > range. Song provided the trace information which allowed to decode the root > cause. > > The rework of the vector allocation mechanism failed to preserve a sanity > check, which prevents setting a new target vector/CPU when the previous > affinity change has not fully completed. > > As a result a half finished affinity change can be overwritten, which can > cause the leak of a irq descriptor pointer on the previous target CPU and > double enqueue of the hlist head into the cleanup lists of two or more > CPUs. After one CPU cleaned up its vector the next CPU will invoke the > cleanup handler with vector 0, which triggers the out of range warning in > the matrix allocator. > > Prevent this by checking the apic_data of the interrupt whether the > move_in_progress flag is false and the hlist node is not hashed. Return > -EBUSY if not. > > This prevents the damage and restores the behaviour before the vector > allocation rework, but due to other changes in that area it also widens the > chance that user space can observe -EBUSY. In theory this should be fine, > but actually not all user space tools handle -EBUSY correctly. Addressing > that is not part of this fix, but will be addressed in follow up patches. > > Fixes: 69cde0004a4b ("x86/vector: Use matrix allocator for vector assignment") > Reported-by: Dmitry Safonov <0x7f454c46@xxxxxxxxx> > Reported-by: Tariq Toukan <tariqt@xxxxxxxxxxxx> > Reported-by: Song Liu <liu.song.a23@xxxxxxxxx> > Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx Thanks Thomas! This patch alone fixes my test: ethtool -L in a loop. I also run the same test for the full set, and it works well. Tested-by: Song Liu <songliubraving@xxxxxx> > --- > arch/x86/kernel/apic/vector.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > --- a/arch/x86/kernel/apic/vector.c > +++ b/arch/x86/kernel/apic/vector.c > @@ -235,6 +235,15 @@ static int allocate_vector(struct irq_da > if (vector && cpu_online(cpu) && cpumask_test_cpu(cpu, dest)) > return 0; > > + /* > + * Careful here. @apicd might either have move_in_progress set or > + * be enqueued for cleanup. Assigning a new vector would either > + * leave a stale vector on some CPU around or in case of a pending > + * cleanup corrupt the hlist. > + */ > + if (apicd->move_in_progress || !hlist_unhashed(&apicd->clist)) > + return -EBUSY; > + > vector = irq_matrix_alloc(vector_matrix, dest, resvd, &cpu); > if (vector > 0) > apic_update_vector(irqd, vector, cpu); > >