Skip to content

Commit 896f97e

Browse files
David Decotignytorvalds
authored andcommitted
lib: cpu_rmap: avoid flushing all workqueues
In some cases, free_irq_cpu_rmap() is called while holding a lock (eg rtnl). This can lead to deadlocks, because it invokes flush_scheduled_work() which ends up waiting for whole system workqueue to flush, but some pending works might try to acquire the lock we are already holding. This commit uses reference-counting to replace irq_run_affinity_notifiers(). It also removes irq_run_affinity_notifiers() altogether. [akpm@linux-foundation.org: eliminate free_cpu_rmap, rename cpu_rmap_reclaim() to cpu_rmap_release(), propagate kref_put() retval from cpu_rmap_put()] Signed-off-by: David Decotigny <decot@googlers.com> Reviewed-by: Ben Hutchings <bhutchings@solarflare.com> Acked-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Or Gerlitz <ogerlitz@mellanox.com> Acked-by: Amir Vadai <amirv@mellanox.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 254adaa commit 896f97e

File tree

3 files changed

+53
-19
lines changed

3 files changed

+53
-19
lines changed

include/linux/cpu_rmap.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@
1313
#include <linux/cpumask.h>
1414
#include <linux/gfp.h>
1515
#include <linux/slab.h>
16+
#include <linux/kref.h>
1617

1718
/**
1819
* struct cpu_rmap - CPU affinity reverse-map
20+
* @refcount: kref for object
1921
* @size: Number of objects to be reverse-mapped
2022
* @used: Number of objects added
2123
* @obj: Pointer to array of object pointers
2224
* @near: For each CPU, the index and distance to the nearest object,
2325
* based on affinity masks
2426
*/
2527
struct cpu_rmap {
28+
struct kref refcount;
2629
u16 size, used;
2730
void **obj;
2831
struct {
@@ -33,15 +36,7 @@ struct cpu_rmap {
3336
#define CPU_RMAP_DIST_INF 0xffff
3437

3538
extern struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags);
36-
37-
/**
38-
* free_cpu_rmap - free CPU affinity reverse-map
39-
* @rmap: Reverse-map allocated with alloc_cpu_rmap(), or %NULL
40-
*/
41-
static inline void free_cpu_rmap(struct cpu_rmap *rmap)
42-
{
43-
kfree(rmap);
44-
}
39+
extern int cpu_rmap_put(struct cpu_rmap *rmap);
4540

4641
extern int cpu_rmap_add(struct cpu_rmap *rmap, void *obj);
4742
extern int cpu_rmap_update(struct cpu_rmap *rmap, u16 index,

include/linux/interrupt.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,6 @@ struct irq_affinity_notify {
268268
extern int
269269
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
270270

271-
static inline void irq_run_affinity_notifiers(void)
272-
{
273-
flush_scheduled_work();
274-
}
275-
276271
#else /* CONFIG_SMP */
277272

278273
static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)

lib/cpu_rmap.c

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
4545
if (!rmap)
4646
return NULL;
4747

48+
kref_init(&rmap->refcount);
4849
rmap->obj = (void **)((char *)rmap + obj_offset);
4950

5051
/* Initially assign CPUs to objects on a rota, since we have
@@ -63,6 +64,35 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
6364
}
6465
EXPORT_SYMBOL(alloc_cpu_rmap);
6566

67+
/**
68+
* cpu_rmap_release - internal reclaiming helper called from kref_put
69+
* @ref: kref to struct cpu_rmap
70+
*/
71+
static void cpu_rmap_release(struct kref *ref)
72+
{
73+
struct cpu_rmap *rmap = container_of(ref, struct cpu_rmap, refcount);
74+
kfree(rmap);
75+
}
76+
77+
/**
78+
* cpu_rmap_get - internal helper to get new ref on a cpu_rmap
79+
* @rmap: reverse-map allocated with alloc_cpu_rmap()
80+
*/
81+
static inline void cpu_rmap_get(struct cpu_rmap *rmap)
82+
{
83+
kref_get(&rmap->refcount);
84+
}
85+
86+
/**
87+
* cpu_rmap_put - release ref on a cpu_rmap
88+
* @rmap: reverse-map allocated with alloc_cpu_rmap()
89+
*/
90+
int cpu_rmap_put(struct cpu_rmap *rmap)
91+
{
92+
return kref_put(&rmap->refcount, cpu_rmap_release);
93+
}
94+
EXPORT_SYMBOL(cpu_rmap_put);
95+
6696
/* Reevaluate nearest object for given CPU, comparing with the given
6797
* neighbours at the given distance.
6898
*/
@@ -197,8 +227,7 @@ struct irq_glue {
197227
* free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs
198228
* @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL
199229
*
200-
* Must be called in process context, before freeing the IRQs, and
201-
* without holding any locks required by global workqueue items.
230+
* Must be called in process context, before freeing the IRQs.
202231
*/
203232
void free_irq_cpu_rmap(struct cpu_rmap *rmap)
204233
{
@@ -212,12 +241,18 @@ void free_irq_cpu_rmap(struct cpu_rmap *rmap)
212241
glue = rmap->obj[index];
213242
irq_set_affinity_notifier(glue->notify.irq, NULL);
214243
}
215-
irq_run_affinity_notifiers();
216244

217-
kfree(rmap);
245+
cpu_rmap_put(rmap);
218246
}
219247
EXPORT_SYMBOL(free_irq_cpu_rmap);
220248

249+
/**
250+
* irq_cpu_rmap_notify - callback for IRQ subsystem when IRQ affinity updated
251+
* @notify: struct irq_affinity_notify passed by irq/manage.c
252+
* @mask: cpu mask for new SMP affinity
253+
*
254+
* This is executed in workqueue context.
255+
*/
221256
static void
222257
irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
223258
{
@@ -230,10 +265,16 @@ irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
230265
pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc);
231266
}
232267

268+
/**
269+
* irq_cpu_rmap_release - reclaiming callback for IRQ subsystem
270+
* @ref: kref to struct irq_affinity_notify passed by irq/manage.c
271+
*/
233272
static void irq_cpu_rmap_release(struct kref *ref)
234273
{
235274
struct irq_glue *glue =
236275
container_of(ref, struct irq_glue, notify.kref);
276+
277+
cpu_rmap_put(glue->rmap);
237278
kfree(glue);
238279
}
239280

@@ -258,10 +299,13 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
258299
glue->notify.notify = irq_cpu_rmap_notify;
259300
glue->notify.release = irq_cpu_rmap_release;
260301
glue->rmap = rmap;
302+
cpu_rmap_get(rmap);
261303
glue->index = cpu_rmap_add(rmap, glue);
262304
rc = irq_set_affinity_notifier(irq, &glue->notify);
263-
if (rc)
305+
if (rc) {
306+
cpu_rmap_put(glue->rmap);
264307
kfree(glue);
308+
}
265309
return rc;
266310
}
267311
EXPORT_SYMBOL(irq_cpu_rmap_add);

0 commit comments

Comments
 (0)