aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDavid Decotigny <decot@googlers.com>2013-01-11 17:31:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-11 17:54:54 -0500
commit896f97ea95c1d29c0520ee0766b66b7f64cb967c (patch)
tree9898ba669c2348294452fcfd5b7b81fe04cb072f /lib
parent254adaa465c40151df11fc1f88f93e6e86eb61d4 (diff)
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/cpu_rmap.c54
1 files changed, 49 insertions, 5 deletions
diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c
index 145dec5267c9..5fbed5caba6e 100644
--- a/lib/cpu_rmap.c
+++ b/lib/cpu_rmap.c
@@ -45,6 +45,7 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
45 if (!rmap) 45 if (!rmap)
46 return NULL; 46 return NULL;
47 47
48 kref_init(&rmap->refcount);
48 rmap->obj = (void **)((char *)rmap + obj_offset); 49 rmap->obj = (void **)((char *)rmap + obj_offset);
49 50
50 /* Initially assign CPUs to objects on a rota, since we have 51 /* 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)
63} 64}
64EXPORT_SYMBOL(alloc_cpu_rmap); 65EXPORT_SYMBOL(alloc_cpu_rmap);
65 66
67/**
68 * cpu_rmap_release - internal reclaiming helper called from kref_put
69 * @ref: kref to struct cpu_rmap
70 */
71static 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 */
81static 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 */
90int cpu_rmap_put(struct cpu_rmap *rmap)
91{
92 return kref_put(&rmap->refcount, cpu_rmap_release);
93}
94EXPORT_SYMBOL(cpu_rmap_put);
95
66/* Reevaluate nearest object for given CPU, comparing with the given 96/* Reevaluate nearest object for given CPU, comparing with the given
67 * neighbours at the given distance. 97 * neighbours at the given distance.
68 */ 98 */
@@ -197,8 +227,7 @@ struct irq_glue {
197 * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs 227 * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs
198 * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL 228 * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL
199 * 229 *
200 * Must be called in process context, before freeing the IRQs, and 230 * Must be called in process context, before freeing the IRQs.
201 * without holding any locks required by global workqueue items.
202 */ 231 */
203void free_irq_cpu_rmap(struct cpu_rmap *rmap) 232void free_irq_cpu_rmap(struct cpu_rmap *rmap)
204{ 233{
@@ -212,12 +241,18 @@ void free_irq_cpu_rmap(struct cpu_rmap *rmap)
212 glue = rmap->obj[index]; 241 glue = rmap->obj[index];
213 irq_set_affinity_notifier(glue->notify.irq, NULL); 242 irq_set_affinity_notifier(glue->notify.irq, NULL);
214 } 243 }
215 irq_run_affinity_notifiers();
216 244
217 kfree(rmap); 245 cpu_rmap_put(rmap);
218} 246}
219EXPORT_SYMBOL(free_irq_cpu_rmap); 247EXPORT_SYMBOL(free_irq_cpu_rmap);
220 248
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 */
221static void 256static void
222irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask) 257irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
223{ 258{
@@ -230,10 +265,16 @@ irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
230 pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc); 265 pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc);
231} 266}
232 267
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 */
233static void irq_cpu_rmap_release(struct kref *ref) 272static void irq_cpu_rmap_release(struct kref *ref)
234{ 273{
235 struct irq_glue *glue = 274 struct irq_glue *glue =
236 container_of(ref, struct irq_glue, notify.kref); 275 container_of(ref, struct irq_glue, notify.kref);
276
277 cpu_rmap_put(glue->rmap);
237 kfree(glue); 278 kfree(glue);
238} 279}
239 280
@@ -258,10 +299,13 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
258 glue->notify.notify = irq_cpu_rmap_notify; 299 glue->notify.notify = irq_cpu_rmap_notify;
259 glue->notify.release = irq_cpu_rmap_release; 300 glue->notify.release = irq_cpu_rmap_release;
260 glue->rmap = rmap; 301 glue->rmap = rmap;
302 cpu_rmap_get(rmap);
261 glue->index = cpu_rmap_add(rmap, glue); 303 glue->index = cpu_rmap_add(rmap, glue);
262 rc = irq_set_affinity_notifier(irq, &glue->notify); 304 rc = irq_set_affinity_notifier(irq, &glue->notify);
263 if (rc) 305 if (rc) {
306 cpu_rmap_put(glue->rmap);
264 kfree(glue); 307 kfree(glue);
308 }
265 return rc; 309 return rc;
266} 310}
267EXPORT_SYMBOL(irq_cpu_rmap_add); 311EXPORT_SYMBOL(irq_cpu_rmap_add);