Jeremy Dorfman identified mutex contention when multiple threads parse /proc/stat concurrently.
Since Thomas Gleixner commit 425a5072dcd1 ("genirq: Free irq_desc with rcu"), we can easily switch kstat_irqs_usr() to rcu locking and remove this mutex contetion. show_interrupts() case will be handled in a separate patch. Signed-off-by: Eric Dumazet <eduma...@google.com> Reported-by: Jeremy Dorfman <jdorf...@google.com> Cc: Thomas Gleixner <t...@linutronix.de> Cc: Willem de Bruijn <will...@google.com> --- kernel/irq/irqdesc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index afc7f902d74a3eff5d1f8a5e407159c5d28625f7..a668b7ad8a5d5e3b191e3a1dc8f9f32293658d42 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -443,6 +443,7 @@ static void free_desc(unsigned int irq) * We free the descriptor, masks and stat fields via RCU. That * allows demultiplex interrupts to do rcu based management of * the child interrupts. + * This also allows us to use rcu in kstat_irqs_usr(). */ call_rcu(&desc->rcu, delayed_free_desc); } @@ -928,17 +929,17 @@ unsigned int kstat_irqs(unsigned int irq) * kstat_irqs_usr - Get the statistics for an interrupt * @irq: The interrupt number * - * Returns the sum of interrupt counts on all cpus since boot for - * @irq. Contrary to kstat_irqs() this can be called from any - * preemptible context. It's protected against concurrent removal of - * an interrupt descriptor when sparse irqs are enabled. + * Returns the sum of interrupt counts on all cpus since boot for @irq. + * Contrary to kstat_irqs() this can be called from any context. + * It uses rcu since a concurrent removal of an interrupt descriptor is + * observing an rcu grace period before delayed_free_desc()/irq_kobj_release(). */ unsigned int kstat_irqs_usr(unsigned int irq) { unsigned int sum; - irq_lock_sparse(); + rcu_read_lock(); sum = kstat_irqs(irq); - irq_unlock_sparse(); + rcu_read_unlock(); return sum; } -- 2.18.0.rc1.244.gcf134e6275-goog