[CRIU] [RFC PATCH 04/16] criu: lazy-pages: handle remaining pages based on IOVs rather than pages

Mike Rapoport rppt at linux.vnet.ibm.com
Tue Sep 27 06:42:05 PDT 2016


Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/uffd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 70 insertions(+), 14 deletions(-)

diff --git a/criu/uffd.c b/criu/uffd.c
index 063ce4f..3f25b86 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -325,6 +325,56 @@ out:
 
 static int find_vmas(struct lazy_pages_info *lpi);
 
+static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr,
+			       int len)
+{
+	struct lazy_iovec *lazy_iov, *n;
+
+	list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) {
+		unsigned long start = (unsigned long)lazy_iov->iov.iov_base;
+		unsigned long end = start + lazy_iov->iov.iov_len;
+
+		if (len <= 0)
+			break;
+
+		if (addr < start || addr >= end)
+			continue;
+
+		if (addr + len < end) {
+			if (addr == start) {
+				lazy_iov->iov.iov_base += len;
+				lazy_iov->iov.iov_len -= len;
+			} else {
+				struct lazy_iovec *new;
+
+				lazy_iov->iov.iov_len -= (end - addr);
+
+				new = xzalloc(sizeof(*new));
+				if (!new)
+					return -1;
+
+				new->iov.iov_base = (void *)(addr + len);
+				new->iov.iov_len = end - (addr + len);
+
+				list_add(&new->l, &lazy_iov->l);
+			}
+			break;
+		}
+
+		if (addr == start) {
+			list_del(&lazy_iov->l);
+			xfree(lazy_iov);
+		} else {
+			lazy_iov->iov.iov_len -= (end - addr);
+		}
+
+		len -= (end - addr);
+		addr = end;
+	}
+
+	return 0;
+}
+
 static int collect_lazy_iovecs(struct lazy_pages_info *lpi)
 {
 	struct page_read *pr = &lpi->pr;
@@ -585,28 +635,30 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
 
 static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest)
 {
-	struct uffd_pages_struct *uffd_pages;
-	int rc;
+	struct lazy_iovec *lazy_iov;
+	int nr_pages, i, err;
+	unsigned long base, addr;
 
-	list_for_each_entry(uffd_pages, &lpi->pages, list) {
-		pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n",
-			 uffd_pages->addr, uffd_pages->flags);
-		if (uffd_pages->flags & UFFD_FLAG_SENT)
-			continue;
+	lpi->pr.reset(&lpi->pr);
 
-		rc = uffd_handle_page(lpi, uffd_pages->addr, dest);
-		if (rc < 0) {
-			pr_err("Error during UFFD copy\n");
-			return -1;
-		}
+	list_for_each_entry(lazy_iov, &lpi->iovs, l) {
+		nr_pages = lazy_iov->iov.iov_len / PAGE_SIZE;
+		base = (unsigned long)lazy_iov->iov.iov_base;
 
-		uffd_pages->flags |= UFFD_FLAG_SENT;
+		for (i = 0; i < nr_pages; i++) {
+			addr = base + i * PAGE_SIZE;
+
+			err = uffd_handle_page(lpi, addr, dest);
+			if (err < 0) {
+				pr_err("Error during UFFD copy\n");
+				return -1;
+			}
+		}
 	}
 
 	return 0;
 }
 
-
 static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
 				__u64 address)
 {
@@ -628,6 +680,10 @@ static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
 			uffd_pages->flags |= UFFD_FLAG_SENT;
 	}
 
+	rc = update_lazy_iovecs(lpi, address, PAGE_SIZE);
+	if (rc < 0)
+		return -1;
+
 	return 0;
 }
 
-- 
1.9.1



More information about the CRIU mailing list