Skip to content

Commit

Permalink
ptr_ring: support resizing multiple queues
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jason Wang <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
mstsirkin authored and davem330 committed Jul 1, 2016
1 parent fd68ade commit 59e6ae5
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
71 changes: 62 additions & 9 deletions include/linux/ptr_ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -375,13 +369,72 @@ 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);

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;
Expand Down
5 changes: 5 additions & 0 deletions tools/virtio/ringtest/ptr_ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 59e6ae5

Please sign in to comment.