aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/ptr_ring.h
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2016-06-30 02:45:33 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-01 05:32:17 -0400
commit59e6ae53248a72d83cec77dd704b6990b2394479 (patch)
tree6978c2c81e9c807a544304ea2c28ce49696d3ad4 /include/linux/ptr_ring.h
parentfd68adec9de3104c236ffbcb3bd829d3e635a444 (diff)
ptr_ring: support resizing multiple queues
Sometimes, we need support resizing multiple queues at once. This is because it was not easy to recover to recover from a partial failure of multiple queues resizing. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux/ptr_ring.h')
-rw-r--r--include/linux/ptr_ring.h71
1 files changed, 62 insertions, 9 deletions
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index d78b8b89c707..2052011bf9fb 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -349,20 +349,14 @@ static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
349 return 0; 349 return 0;
350} 350}
351 351
352static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, 352static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
353 void (*destroy)(void *)) 353 int size, gfp_t gfp,
354 void (*destroy)(void *))
354{ 355{
355 unsigned long flags;
356 int producer = 0; 356 int producer = 0;
357 void **queue = __ptr_ring_init_queue_alloc(size, gfp);
358 void **old; 357 void **old;
359 void *ptr; 358 void *ptr;
360 359
361 if (!queue)
362 return -ENOMEM;
363
364 spin_lock_irqsave(&(r)->producer_lock, flags);
365
366 while ((ptr = ptr_ring_consume(r))) 360 while ((ptr = ptr_ring_consume(r)))
367 if (producer < size) 361 if (producer < size)
368 queue[producer++] = ptr; 362 queue[producer++] = ptr;
@@ -375,6 +369,23 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
375 old = r->queue; 369 old = r->queue;
376 r->queue = queue; 370 r->queue = queue;
377 371
372 return old;
373}
374
375static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
376 void (*destroy)(void *))
377{
378 unsigned long flags;
379 void **queue = __ptr_ring_init_queue_alloc(size, gfp);
380 void **old;
381
382 if (!queue)
383 return -ENOMEM;
384
385 spin_lock_irqsave(&(r)->producer_lock, flags);
386
387 old = __ptr_ring_swap_queue(r, queue, size, gfp, destroy);
388
378 spin_unlock_irqrestore(&(r)->producer_lock, flags); 389 spin_unlock_irqrestore(&(r)->producer_lock, flags);
379 390
380 kfree(old); 391 kfree(old);
@@ -382,6 +393,48 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
382 return 0; 393 return 0;
383} 394}
384 395
396static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
397 int size,
398 gfp_t gfp, void (*destroy)(void *))
399{
400 unsigned long flags;
401 void ***queues;
402 int i;
403
404 queues = kmalloc(nrings * sizeof *queues, gfp);
405 if (!queues)
406 goto noqueues;
407
408 for (i = 0; i < nrings; ++i) {
409 queues[i] = __ptr_ring_init_queue_alloc(size, gfp);
410 if (!queues[i])
411 goto nomem;
412 }
413
414 for (i = 0; i < nrings; ++i) {
415 spin_lock_irqsave(&(rings[i])->producer_lock, flags);
416 queues[i] = __ptr_ring_swap_queue(rings[i], queues[i],
417 size, gfp, destroy);
418 spin_unlock_irqrestore(&(rings[i])->producer_lock, flags);
419 }
420
421 for (i = 0; i < nrings; ++i)
422 kfree(queues[i]);
423
424 kfree(queues);
425
426 return 0;
427
428nomem:
429 while (--i >= 0)
430 kfree(queues[i]);
431
432 kfree(queues);
433
434noqueues:
435 return -ENOMEM;
436}
437
385static inline void ptr_ring_cleanup(struct ptr_ring *r, void (*destroy)(void *)) 438static inline void ptr_ring_cleanup(struct ptr_ring *r, void (*destroy)(void *))
386{ 439{
387 void *ptr; 440 void *ptr;