aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2017-02-19 00:17:17 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-26 05:10:51 -0500
commit7c56012e92b51030b13c4652a9494d422562d5d5 (patch)
tree10d63b04970e0864293c6a3aebcb56d6be1dc476
parentc2219da51664451149350e47321aa0fcf72a8b8f (diff)
ptr_ring: fix race conditions when resizing
[ Upstream commit e71695307114335be1ed912f4a347396c2ed0e69 ] Resizing currently drops consumer lock. This can cause entries to be reordered, which isn't good in itself. More importantly, consumer can detect a false ring empty condition and block forever. Further, nesting of consumer within producer lock is problematic for tun, since it produces entries in a BH, which causes a lock order reversal: CPU0 CPU1 ---- ---- consume: lock(&(&r->consumer_lock)->rlock); resize: local_irq_disable(); lock(&(&r->producer_lock)->rlock); lock(&(&r->consumer_lock)->rlock); <Interrupt> produce: lock(&(&r->producer_lock)->rlock); To fix, nest producer lock within consumer lock during resize, and keep consumer lock during the whole swap operation. Reported-by: Dmitry Vyukov <dvyukov@google.com> Cc: stable@vger.kernel.org Cc: "David S. Miller" <davem@davemloft.net> Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/linux/ptr_ring.h36
1 files changed, 31 insertions, 5 deletions
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index 2052011bf9fb..6c70444da3b9 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -111,6 +111,11 @@ static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr)
111 return 0; 111 return 0;
112} 112}
113 113
114/*
115 * Note: resize (below) nests producer lock within consumer lock, so if you
116 * consume in interrupt or BH context, you must disable interrupts/BH when
117 * calling this.
118 */
114static inline int ptr_ring_produce(struct ptr_ring *r, void *ptr) 119static inline int ptr_ring_produce(struct ptr_ring *r, void *ptr)
115{ 120{
116 int ret; 121 int ret;
@@ -242,6 +247,11 @@ static inline void *__ptr_ring_consume(struct ptr_ring *r)
242 return ptr; 247 return ptr;
243} 248}
244 249
250/*
251 * Note: resize (below) nests producer lock within consumer lock, so if you
252 * call this in interrupt or BH context, you must disable interrupts/BH when
253 * producing.
254 */
245static inline void *ptr_ring_consume(struct ptr_ring *r) 255static inline void *ptr_ring_consume(struct ptr_ring *r)
246{ 256{
247 void *ptr; 257 void *ptr;
@@ -357,7 +367,7 @@ static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
357 void **old; 367 void **old;
358 void *ptr; 368 void *ptr;
359 369
360 while ((ptr = ptr_ring_consume(r))) 370 while ((ptr = __ptr_ring_consume(r)))
361 if (producer < size) 371 if (producer < size)
362 queue[producer++] = ptr; 372 queue[producer++] = ptr;
363 else if (destroy) 373 else if (destroy)
@@ -372,6 +382,12 @@ static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
372 return old; 382 return old;
373} 383}
374 384
385/*
386 * Note: producer lock is nested within consumer lock, so if you
387 * resize you must make sure all uses nest correctly.
388 * In particular if you consume ring in interrupt or BH context, you must
389 * disable interrupts/BH when doing so.
390 */
375static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, 391static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
376 void (*destroy)(void *)) 392 void (*destroy)(void *))
377{ 393{
@@ -382,17 +398,25 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
382 if (!queue) 398 if (!queue)
383 return -ENOMEM; 399 return -ENOMEM;
384 400
385 spin_lock_irqsave(&(r)->producer_lock, flags); 401 spin_lock_irqsave(&(r)->consumer_lock, flags);
402 spin_lock(&(r)->producer_lock);
386 403
387 old = __ptr_ring_swap_queue(r, queue, size, gfp, destroy); 404 old = __ptr_ring_swap_queue(r, queue, size, gfp, destroy);
388 405
389 spin_unlock_irqrestore(&(r)->producer_lock, flags); 406 spin_unlock(&(r)->producer_lock);
407 spin_unlock_irqrestore(&(r)->consumer_lock, flags);
390 408
391 kfree(old); 409 kfree(old);
392 410
393 return 0; 411 return 0;
394} 412}
395 413
414/*
415 * Note: producer lock is nested within consumer lock, so if you
416 * resize you must make sure all uses nest correctly.
417 * In particular if you consume ring in interrupt or BH context, you must
418 * disable interrupts/BH when doing so.
419 */
396static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings, 420static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
397 int size, 421 int size,
398 gfp_t gfp, void (*destroy)(void *)) 422 gfp_t gfp, void (*destroy)(void *))
@@ -412,10 +436,12 @@ static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
412 } 436 }
413 437
414 for (i = 0; i < nrings; ++i) { 438 for (i = 0; i < nrings; ++i) {
415 spin_lock_irqsave(&(rings[i])->producer_lock, flags); 439 spin_lock_irqsave(&(rings[i])->consumer_lock, flags);
440 spin_lock(&(rings[i])->producer_lock);
416 queues[i] = __ptr_ring_swap_queue(rings[i], queues[i], 441 queues[i] = __ptr_ring_swap_queue(rings[i], queues[i],
417 size, gfp, destroy); 442 size, gfp, destroy);
418 spin_unlock_irqrestore(&(rings[i])->producer_lock, flags); 443 spin_unlock(&(rings[i])->producer_lock);
444 spin_unlock_irqrestore(&(rings[i])->consumer_lock, flags);
419 } 445 }
420 446
421 for (i = 0; i < nrings; ++i) 447 for (i = 0; i < nrings; ++i)