]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.19/genirq-avoid-summation-loops-for-proc-stat.patch
d4ff8ca695b14c6733f91ba6e29369a2da483ac2
[thirdparty/kernel/stable-queue.git] / queue-4.19 / genirq-avoid-summation-loops-for-proc-stat.patch
1 From a07167b5aa2226adf4d633069c055b9197f914fa Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Fri, 8 Feb 2019 14:48:03 +0100
4 Subject: genirq: Avoid summation loops for /proc/stat
5
6 [ Upstream commit 1136b0728969901a091f0471968b2b76ed14d9ad ]
7
8 Waiman reported that on large systems with a large amount of interrupts the
9 readout of /proc/stat takes a long time to sum up the interrupt
10 statistics. In principle this is not a problem. but for unknown reasons
11 some enterprise quality software reads /proc/stat with a high frequency.
12
13 The reason for this is that interrupt statistics are accounted per cpu. So
14 the /proc/stat logic has to sum up the interrupt stats for each interrupt.
15
16 This can be largely avoided for interrupts which are not marked as
17 'PER_CPU' interrupts by simply adding a per interrupt summation counter
18 which is incremented along with the per interrupt per cpu counter.
19
20 The PER_CPU interrupts need to avoid that and use only per cpu accounting
21 because they share the interrupt number and the interrupt descriptor and
22 concurrent updates would conflict or require unwanted synchronization.
23
24 Reported-by: Waiman Long <longman@redhat.com>
25 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
26 Reviewed-by: Waiman Long <longman@redhat.com>
27 Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
28 Reviewed-by: Davidlohr Bueso <dbueso@suse.de>
29 Cc: Matthew Wilcox <willy@infradead.org>
30 Cc: Andrew Morton <akpm@linux-foundation.org>
31 Cc: Alexey Dobriyan <adobriyan@gmail.com>
32 Cc: Kees Cook <keescook@chromium.org>
33 Cc: linux-fsdevel@vger.kernel.org
34 Cc: Davidlohr Bueso <dave@stgolabs.net>
35 Cc: Miklos Szeredi <miklos@szeredi.hu>
36 Cc: Daniel Colascione <dancol@google.com>
37 Cc: Dave Chinner <david@fromorbit.com>
38 Cc: Randy Dunlap <rdunlap@infradead.org>
39 Link: https://lkml.kernel.org/r/20190208135020.925487496@linutronix.de
40
41 8<-------------
42
43 v2: Undo the unintentional layout change of struct irq_desc.
44
45 include/linux/irqdesc.h | 1 +
46 kernel/irq/chip.c | 12 ++++++++++--
47 kernel/irq/internals.h | 8 +++++++-
48 kernel/irq/irqdesc.c | 7 ++++++-
49 4 files changed, 24 insertions(+), 4 deletions(-)
50
51 Signed-off-by: Sasha Levin <sashal@kernel.org>
52 ---
53 include/linux/irqdesc.h | 1 +
54 kernel/irq/chip.c | 12 ++++++++++--
55 kernel/irq/internals.h | 8 +++++++-
56 kernel/irq/irqdesc.c | 7 ++++++-
57 4 files changed, 24 insertions(+), 4 deletions(-)
58
59 diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
60 index dd1e40ddac7d..875c41b23f20 100644
61 --- a/include/linux/irqdesc.h
62 +++ b/include/linux/irqdesc.h
63 @@ -65,6 +65,7 @@ struct irq_desc {
64 unsigned int core_internal_state__do_not_mess_with_it;
65 unsigned int depth; /* nested irq disables */
66 unsigned int wake_depth; /* nested wake enables */
67 + unsigned int tot_count;
68 unsigned int irq_count; /* For detecting broken IRQs */
69 unsigned long last_unhandled; /* Aging timer for unhandled count */
70 unsigned int irqs_unhandled;
71 diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
72 index a2b3d9de999c..811009ebacd4 100644
73 --- a/kernel/irq/chip.c
74 +++ b/kernel/irq/chip.c
75 @@ -855,7 +855,11 @@ void handle_percpu_irq(struct irq_desc *desc)
76 {
77 struct irq_chip *chip = irq_desc_get_chip(desc);
78
79 - kstat_incr_irqs_this_cpu(desc);
80 + /*
81 + * PER CPU interrupts are not serialized. Do not touch
82 + * desc->tot_count.
83 + */
84 + __kstat_incr_irqs_this_cpu(desc);
85
86 if (chip->irq_ack)
87 chip->irq_ack(&desc->irq_data);
88 @@ -884,7 +888,11 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
89 unsigned int irq = irq_desc_get_irq(desc);
90 irqreturn_t res;
91
92 - kstat_incr_irqs_this_cpu(desc);
93 + /*
94 + * PER CPU interrupts are not serialized. Do not touch
95 + * desc->tot_count.
96 + */
97 + __kstat_incr_irqs_this_cpu(desc);
98
99 if (chip->irq_ack)
100 chip->irq_ack(&desc->irq_data);
101 diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
102 index ca6afa267070..e74e7eea76cf 100644
103 --- a/kernel/irq/internals.h
104 +++ b/kernel/irq/internals.h
105 @@ -242,12 +242,18 @@ static inline void irq_state_set_masked(struct irq_desc *desc)
106
107 #undef __irqd_to_state
108
109 -static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc)
110 +static inline void __kstat_incr_irqs_this_cpu(struct irq_desc *desc)
111 {
112 __this_cpu_inc(*desc->kstat_irqs);
113 __this_cpu_inc(kstat.irqs_sum);
114 }
115
116 +static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc)
117 +{
118 + __kstat_incr_irqs_this_cpu(desc);
119 + desc->tot_count++;
120 +}
121 +
122 static inline int irq_desc_get_node(struct irq_desc *desc)
123 {
124 return irq_common_data_get_node(&desc->irq_common_data);
125 diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
126 index 578d0e5f1b5b..ba454cba4069 100644
127 --- a/kernel/irq/irqdesc.c
128 +++ b/kernel/irq/irqdesc.c
129 @@ -119,6 +119,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
130 desc->depth = 1;
131 desc->irq_count = 0;
132 desc->irqs_unhandled = 0;
133 + desc->tot_count = 0;
134 desc->name = NULL;
135 desc->owner = owner;
136 for_each_possible_cpu(cpu)
137 @@ -915,11 +916,15 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
138 unsigned int kstat_irqs(unsigned int irq)
139 {
140 struct irq_desc *desc = irq_to_desc(irq);
141 - int cpu;
142 unsigned int sum = 0;
143 + int cpu;
144
145 if (!desc || !desc->kstat_irqs)
146 return 0;
147 + if (!irq_settings_is_per_cpu_devid(desc) &&
148 + !irq_settings_is_per_cpu(desc))
149 + return desc->tot_count;
150 +
151 for_each_possible_cpu(cpu)
152 sum += *per_cpu_ptr(desc->kstat_irqs, cpu);
153 return sum;
154 --
155 2.19.1
156