Commit a91b2e90 authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

page-pipe: do not allow pipe sharing between different PPB types

Currently, if pipe is shared between lazy and non-lazy PPBs lazy migration
fails because data that should be transfered on demand is spliced into the
images. Preventing pipe sharing between PPBs of different type resolves
this issue.
In order to still minimize pipe fragmentation, we track the last pipe that
was used for certain PPB type and re-use it for the PPB of the same type.
Signed-off-by: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 8d98d864
...@@ -102,12 +102,23 @@ struct page_pipe_buf { ...@@ -102,12 +102,23 @@ struct page_pipe_buf {
struct list_head l; /* links into page_pipe->bufs */ struct list_head l; /* links into page_pipe->bufs */
}; };
/*
* Page pipe buffers with different flags cannot share the same pipe.
* We track the last ppb that was used for each type separately in the
* prev[] array in the struct page_pipe (below).
* Currently we have 2 types: the buffers that are always stored in
* the images and the buffers that are lazily migrated
*/
#define PP_PIPE_TYPES 2
#define PP_HOLE_PARENT (1 << 0) #define PP_HOLE_PARENT (1 << 0)
struct page_pipe { struct page_pipe {
unsigned int nr_pipes; /* how many page_pipe_bufs in there */ unsigned int nr_pipes; /* how many page_pipe_bufs in there */
struct list_head bufs; /* list of bufs */ struct list_head bufs; /* list of bufs */
struct list_head free_bufs; /* list of bufs */ struct list_head free_bufs; /* list of bufs */
struct page_pipe_buf *prev[PP_PIPE_TYPES]; /* last ppb of each type
for pipe sharing */
unsigned int nr_iovs; /* number of iovs */ unsigned int nr_iovs; /* number of iovs */
unsigned int free_iov; /* first free iov */ unsigned int free_iov; /* first free iov */
struct iovec *iovs; /* iovs. They are provided into create_page_pipe struct iovec *iovs; /* iovs. They are provided into create_page_pipe
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "page-pipe.h" #include "page-pipe.h"
#include "fcntl.h" #include "fcntl.h"
#include "stats.h" #include "stats.h"
#include "cr_options.h"
/* can existing iov accumulate the page? */ /* can existing iov accumulate the page? */
static inline bool iov_grow_page(struct iovec *iov, unsigned long addr) static inline bool iov_grow_page(struct iovec *iov, unsigned long addr)
...@@ -63,8 +64,39 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) ...@@ -63,8 +64,39 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb)
return 0; return 0;
} }
static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_buf *prev) static struct page_pipe_buf *pp_prev_ppb(struct page_pipe *pp,
unsigned int ppb_flags)
{ {
int type = 0;
/* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */
if (pp->flags & PP_CHUNK_MODE)
return NULL;
if (list_empty(&pp->bufs))
return NULL;
if (ppb_flags & PPB_LAZY && opts.lazy_pages)
type = 1;
return pp->prev[type];
}
static void pp_update_prev_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb,
unsigned int ppb_flags)
{
int type = 0;
if (ppb_flags & PPB_LAZY && opts.lazy_pages)
type = 1;
pp->prev[type] = ppb;
}
static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp,
unsigned int ppb_flags)
{
struct page_pipe_buf *prev = pp_prev_ppb(pp, ppb_flags);
struct page_pipe_buf *ppb; struct page_pipe_buf *ppb;
ppb = xmalloc(sizeof(*ppb)); ppb = xmalloc(sizeof(*ppb));
...@@ -94,6 +126,8 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_bu ...@@ -94,6 +126,8 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_bu
list_add_tail(&ppb->l, &pp->bufs); list_add_tail(&ppb->l, &pp->bufs);
pp_update_prev_ppb(pp, ppb, ppb_flags);
return ppb; return ppb;
} }
...@@ -119,7 +153,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, ...@@ -119,7 +153,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in,
static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) static int page_pipe_grow(struct page_pipe *pp, unsigned int flags)
{ {
struct page_pipe_buf *ppb, *prev = NULL; struct page_pipe_buf *ppb;
struct iovec *free_iov; struct iovec *free_iov;
pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov); pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov);
...@@ -133,10 +167,7 @@ static int page_pipe_grow(struct page_pipe *pp, unsigned int flags) ...@@ -133,10 +167,7 @@ static int page_pipe_grow(struct page_pipe *pp, unsigned int flags)
if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK)) if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK))
return -EAGAIN; return -EAGAIN;
/* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */ ppb = ppb_alloc(pp, flags);
if (!(pp->flags & PP_CHUNK_MODE) && !list_empty(&pp->bufs))
prev = list_entry(pp->bufs.prev, struct page_pipe_buf, l);
ppb = ppb_alloc(pp, prev);
if (!ppb) if (!ppb)
return -1; return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment