Skip to content

Commit 9a0ef98

Browse files
Christoph HellwigKAGA-KOKO
authored andcommitted
genirq/affinity: Assign vectors to all present CPUs
Currently the irq vector spread algorithm is restricted to online CPUs, which ties the IRQ mapping to the currently online devices and doesn't deal nicely with the fact that CPUs could come and go rapidly due to e.g. power management. Instead assign vectors to all present CPUs to avoid this churn. Build a map of all possible CPUs for a given node, as the architectures only provide a map of all onlines CPUs. Do this dynamically on each call for the vector assingments, which is a bit suboptimal and could be optimized in the future by provinding a mapping from the arch code. Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: Jens Axboe <[email protected]> Cc: [email protected] Cc: Sagi Grimberg <[email protected]> Cc: Marc Zyngier <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: [email protected] Cc: Keith Busch <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected]
1 parent 3ca5722 commit 9a0ef98

File tree

1 file changed

+63
-13
lines changed

1 file changed

+63
-13
lines changed

kernel/irq/affinity.c

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
1+
/*
2+
* Copyright (C) 2016 Thomas Gleixner.
3+
* Copyright (C) 2016-2017 Christoph Hellwig.
4+
*/
25
#include <linux/interrupt.h>
36
#include <linux/kernel.h>
47
#include <linux/slab.h>
@@ -35,13 +38,54 @@ static void irq_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
3538
}
3639
}
3740

38-
static int get_nodes_in_cpumask(const struct cpumask *mask, nodemask_t *nodemsk)
41+
static cpumask_var_t *alloc_node_to_present_cpumask(void)
42+
{
43+
cpumask_var_t *masks;
44+
int node;
45+
46+
masks = kcalloc(nr_node_ids, sizeof(cpumask_var_t), GFP_KERNEL);
47+
if (!masks)
48+
return NULL;
49+
50+
for (node = 0; node < nr_node_ids; node++) {
51+
if (!zalloc_cpumask_var(&masks[node], GFP_KERNEL))
52+
goto out_unwind;
53+
}
54+
55+
return masks;
56+
57+
out_unwind:
58+
while (--node >= 0)
59+
free_cpumask_var(masks[node]);
60+
kfree(masks);
61+
return NULL;
62+
}
63+
64+
static void free_node_to_present_cpumask(cpumask_var_t *masks)
65+
{
66+
int node;
67+
68+
for (node = 0; node < nr_node_ids; node++)
69+
free_cpumask_var(masks[node]);
70+
kfree(masks);
71+
}
72+
73+
static void build_node_to_present_cpumask(cpumask_var_t *masks)
74+
{
75+
int cpu;
76+
77+
for_each_present_cpu(cpu)
78+
cpumask_set_cpu(cpu, masks[cpu_to_node(cpu)]);
79+
}
80+
81+
static int get_nodes_in_cpumask(cpumask_var_t *node_to_present_cpumask,
82+
const struct cpumask *mask, nodemask_t *nodemsk)
3983
{
4084
int n, nodes = 0;
4185

4286
/* Calculate the number of nodes in the supplied affinity mask */
43-
for_each_online_node(n) {
44-
if (cpumask_intersects(mask, cpumask_of_node(n))) {
87+
for_each_node(n) {
88+
if (cpumask_intersects(mask, node_to_present_cpumask[n])) {
4589
node_set(n, *nodemsk);
4690
nodes++;
4791
}
@@ -64,7 +108,7 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
64108
int last_affv = affv + affd->pre_vectors;
65109
nodemask_t nodemsk = NODE_MASK_NONE;
66110
struct cpumask *masks;
67-
cpumask_var_t nmsk;
111+
cpumask_var_t nmsk, *node_to_present_cpumask;
68112

69113
if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
70114
return NULL;
@@ -73,21 +117,28 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
73117
if (!masks)
74118
goto out;
75119

120+
node_to_present_cpumask = alloc_node_to_present_cpumask();
121+
if (!node_to_present_cpumask)
122+
goto out;
123+
76124
/* Fill out vectors at the beginning that don't need affinity */
77125
for (curvec = 0; curvec < affd->pre_vectors; curvec++)
78126
cpumask_copy(masks + curvec, irq_default_affinity);
79127

80128
/* Stabilize the cpumasks */
81129
get_online_cpus();
82-
nodes = get_nodes_in_cpumask(cpu_online_mask, &nodemsk);
130+
build_node_to_present_cpumask(node_to_present_cpumask);
131+
nodes = get_nodes_in_cpumask(node_to_present_cpumask, cpu_present_mask,
132+
&nodemsk);
83133

84134
/*
85135
* If the number of nodes in the mask is greater than or equal the
86136
* number of vectors we just spread the vectors across the nodes.
87137
*/
88138
if (affv <= nodes) {
89139
for_each_node_mask(n, nodemsk) {
90-
cpumask_copy(masks + curvec, cpumask_of_node(n));
140+
cpumask_copy(masks + curvec,
141+
node_to_present_cpumask[n]);
91142
if (++curvec == last_affv)
92143
break;
93144
}
@@ -101,7 +152,7 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
101152
vecs_per_node = (affv - (curvec - affd->pre_vectors)) / nodes;
102153

103154
/* Get the cpus on this node which are in the mask */
104-
cpumask_and(nmsk, cpu_online_mask, cpumask_of_node(n));
155+
cpumask_and(nmsk, cpu_present_mask, node_to_present_cpumask[n]);
105156

106157
/* Calculate the number of cpus per vector */
107158
ncpus = cpumask_weight(nmsk);
@@ -133,6 +184,7 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
133184
/* Fill out vectors at the end that don't need affinity */
134185
for (; curvec < nvecs; curvec++)
135186
cpumask_copy(masks + curvec, irq_default_affinity);
187+
free_node_to_present_cpumask(node_to_present_cpumask);
136188
out:
137189
free_cpumask_var(nmsk);
138190
return masks;
@@ -147,12 +199,10 @@ int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd)
147199
{
148200
int resv = affd->pre_vectors + affd->post_vectors;
149201
int vecs = maxvec - resv;
150-
int cpus;
202+
int ret;
151203

152-
/* Stabilize the cpumasks */
153204
get_online_cpus();
154-
cpus = cpumask_weight(cpu_online_mask);
205+
ret = min_t(int, cpumask_weight(cpu_present_mask), vecs) + resv;
155206
put_online_cpus();
156-
157-
return min(cpus, vecs) + resv;
207+
return ret;
158208
}

0 commit comments

Comments
 (0)