[CRIU] [PATCH] page-pipe: (yet another) fix for split page-pipe buffers
Mike Rapoport
rppt at linux.vnet.ibm.com
Tue Nov 22 09:37:56 PST 2016
Splitting of the trailing part of page-pipe buffer worked by coincidence
for single page requests. Request longer than a single page were not
handled correctly.
The proper point for splitting the trailing part of the page-pipe buffer is
the IOV following the IOV containing the desired page(s).
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
criu/page-pipe.c | 55 ++++++++++++++++++++++---------------------------------
1 file changed, 22 insertions(+), 33 deletions(-)
diff --git a/criu/page-pipe.c b/criu/page-pipe.c
index 1981ff1..20f5132 100644
--- a/criu/page-pipe.c
+++ b/criu/page-pipe.c
@@ -393,10 +393,9 @@ static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb,
}
static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb,
- struct iovec *iov, unsigned long len)
+ struct iovec *iov, unsigned long len,
+ bool popup_new)
{
- struct page_pipe_buf *ppb_tmp;
- struct iovec *iov_tmp = iov;
struct page_pipe_buf *ppb_new;
int ret;
@@ -414,36 +413,10 @@ static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb,
ppb->nr_segs -= ppb_new->nr_segs;
ppb->pages_in -= len / PAGE_SIZE;
+ if (popup_new)
+ ppb = ppb_new;
list_move(&ppb->l, &pp->bufs);
- /*
- * Only the leading iov's are split from the page_pipe_buffer.
- * The complete page_pipe_buffer at the start of the page_pipe
- * list will be deleted and therefore it is necessary to also
- * move unrelated iov's to their own page_pipe_buffers.
- */
-
- if (ppb->nr_segs <= len / PAGE_SIZE)
- return 0;
-
- /* Move to the iov after the current request */
- iov += len / PAGE_SIZE;
- ret = page_pipe_split_ppb(pp, ppb, iov, len);
- if (ret)
- return -1;
-
- /*
- * Rotate until correct head pointer. The function transmitting
- * the page data expects that the head points to the right
- * page_pipe_buffer. The complete first page_pipe_buffer is
- * deleted even it contains additional elements.
- */
- ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l);
- while (ppb_tmp->iov != iov_tmp) {
- list_rotate_left(&pp->bufs);
- ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l);
- }
-
return 0;
}
@@ -471,14 +444,30 @@ int page_pipe_split(struct page_pipe *pp, unsigned long addr,
return 0;
}
- /* split origingal ppb on boundary of iov that contains addr */
+ /*
+ * Split origingal ppb on boundary of iov that contains
+ * addr. The ppb containing the address will remain at the
+ * pp->buf list head.
+ */
if (iov != ppb->iov) {
len -= (addr - (unsigned long)iov->iov_base);
- ret = page_pipe_split_ppb(pp, ppb, iov, len);
+ ret = page_pipe_split_ppb(pp, ppb, iov, len, false);
if (ret)
return -1;
}
+ /*
+ * Split the tail of the ppb. We presume that requests do not
+ * cross IOV (that is pagemap entry) boundaries.
+ * The newly created ppb will contain the desired IOV and will
+ * be poped to the head of the pp->buf list
+ */
+ if (ppb->nr_segs > 1) {
+ len = iov->iov_len;
+ ret = page_pipe_split_ppb(pp, ppb, iov + 1, len, true);
+ if (ret)
+ return -1;
+ }
/*
* if address does not match iov base, split the iov and
--
1.9.1
More information about the CRIU
mailing list