Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: mvpp2: Fix affinity hint allocation

The mvpp2 driver has the curious behaviour of passing a stack variable
to irq_set_affinity_hint(), which results in the kernel exploding
the first time anyone accesses this information. News flash: userspace
does, and irqbalance will happily take the machine down. Great stuff.

An easy fix is to track the mask within the queue_vector structure,
and to make sure it has the same lifetime as the interrupt itself.

Fixes: e531f76757eb ("net: mvpp2: handle cases where more CPUs are available than s/w threads")
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Marc Zyngier and committed by
David S. Miller
a6b3a3fa 3aa8029e

+15 -4
+1
drivers/net/ethernet/marvell/mvpp2/mvpp2.h
··· 796 796 int nrxqs; 797 797 u32 pending_cause_rx; 798 798 struct mvpp2_port *port; 799 + struct cpumask *mask; 799 800 }; 800 801 801 802 struct mvpp2_port {
+14 -4
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
··· 3298 3298 for (i = 0; i < port->nqvecs; i++) { 3299 3299 struct mvpp2_queue_vector *qv = port->qvecs + i; 3300 3300 3301 - if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) 3301 + if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) { 3302 + qv->mask = kzalloc(cpumask_size(), GFP_KERNEL); 3303 + if (!qv->mask) { 3304 + err = -ENOMEM; 3305 + goto err; 3306 + } 3307 + 3302 3308 irq_set_status_flags(qv->irq, IRQ_NO_BALANCING); 3309 + } 3303 3310 3304 3311 err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv); 3305 3312 if (err) 3306 3313 goto err; 3307 3314 3308 3315 if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) { 3309 - unsigned long mask = 0; 3310 3316 unsigned int cpu; 3311 3317 3312 3318 for_each_present_cpu(cpu) { 3313 3319 if (mvpp2_cpu_to_thread(port->priv, cpu) == 3314 3320 qv->sw_thread_id) 3315 - mask |= BIT(cpu); 3321 + cpumask_set_cpu(cpu, qv->mask); 3316 3322 } 3317 3323 3318 - irq_set_affinity_hint(qv->irq, to_cpumask(&mask)); 3324 + irq_set_affinity_hint(qv->irq, qv->mask); 3319 3325 } 3320 3326 } 3321 3327 ··· 3331 3325 struct mvpp2_queue_vector *qv = port->qvecs + i; 3332 3326 3333 3327 irq_set_affinity_hint(qv->irq, NULL); 3328 + kfree(qv->mask); 3329 + qv->mask = NULL; 3334 3330 free_irq(qv->irq, qv); 3335 3331 } 3336 3332 ··· 3347 3339 struct mvpp2_queue_vector *qv = port->qvecs + i; 3348 3340 3349 3341 irq_set_affinity_hint(qv->irq, NULL); 3342 + kfree(qv->mask); 3343 + qv->mask = NULL; 3350 3344 irq_clear_status_flags(qv->irq, IRQ_NO_BALANCING); 3351 3345 free_irq(qv->irq, qv); 3352 3346 }