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>
This commit is contained in:
Michael S. Tsirkin 2016-06-30 14:45:33 +08:00 committed by David S. Miller
parent fd68adec9d
commit 59e6ae5324
2 changed files with 67 additions and 9 deletions

View File

@ -349,20 +349,14 @@ static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
return 0;
}
static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
void (*destroy)(void *))
static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
int size, gfp_t gfp,
void (*destroy)(void *))
{
unsigned long flags;
int producer = 0;
void **queue = __ptr_ring_init_queue_alloc(size, gfp);
void **old;
void *ptr;
if (!queue)
return -ENOMEM;
spin_lock_irqsave(&(r)->producer_lock, flags);
while ((ptr = ptr_ring_consume(r)))
if (producer < size)
queue[producer++] = ptr;
@ -375,6 +369,23 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
old = r->queue;
r->queue = queue;
return old;
}
static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
void (*destroy)(void *))
{
unsigned long flags;
void **queue = __ptr_ring_init_queue_alloc(size, gfp);
void **old;
if (!queue)
return -ENOMEM;
spin_lock_irqsave(&(r)->producer_lock, flags);
old = __ptr_ring_swap_queue(r, queue, size, gfp, destroy);
spin_unlock_irqrestore(&(r)->producer_lock, flags);
kfree(old);
@ -382,6 +393,48 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp,
return 0;
}
static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
int size,
gfp_t gfp, void (*destroy)(void *))
{
unsigned long flags;
void ***queues;
int i;
queues = kmalloc(nrings * sizeof *queues, gfp);
if (!queues)
goto noqueues;
for (i = 0; i < nrings; ++i) {
queues[i] = __ptr_ring_init_queue_alloc(size, gfp);
if (!queues[i])
goto nomem;
}
for (i = 0; i < nrings; ++i) {
spin_lock_irqsave(&(rings[i])->producer_lock, flags);
queues[i] = __ptr_ring_swap_queue(rings[i], queues[i],
size, gfp, destroy);
spin_unlock_irqrestore(&(rings[i])->producer_lock, flags);
}
for (i = 0; i < nrings; ++i)
kfree(queues[i]);
kfree(queues);
return 0;
nomem:
while (--i >= 0)
kfree(queues[i]);
kfree(queues);
noqueues:
return -ENOMEM;
}
static inline void ptr_ring_cleanup(struct ptr_ring *r, void (*destroy)(void *))
{
void *ptr;

View File

@ -17,6 +17,11 @@
typedef pthread_spinlock_t spinlock_t;
typedef int gfp_t;
static void *kmalloc(unsigned size, gfp_t gfp)
{
return memalign(64, size);
}
static void *kzalloc(unsigned size, gfp_t gfp)
{
void *p = memalign(64, size);