[CRIU] [PATCH 2/6] criu: pagemap: introduce advance() helper for pagemap iteration

Mike Rapoport rppt at linux.vnet.ibm.com
Thu Sep 8 00:39:08 PDT 2016


Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/pagemap.c | 72 +++++++++++++++++++++++++---------------------------------
 criu/uffd.c    |  3 +++
 2 files changed, 34 insertions(+), 41 deletions(-)

diff --git a/criu/pagemap.c b/criu/pagemap.c
index d8fe5b0..47c6788 100644
--- a/criu/pagemap.c
+++ b/criu/pagemap.c
@@ -121,31 +121,34 @@ int dedup_one_iovec(struct page_read *pr, struct iovec *iov)
 	return 0;
 }
 
-static int get_pagemap(struct page_read *pr, struct iovec *iov)
+static int advance(struct page_read *pr)
 {
-	PagemapEntry *pe;
+	pr->curr_pme++;
+	if (pr->curr_pme >= pr->nr_pmes)
+		return 0;
 
-	for (;;) {
-		pr->curr_pme++;
-		if (pr->curr_pme >= pr->nr_pmes)
-			return 0;
+	pr->pe = pr->pmes[pr->curr_pme];
+	pr->cvaddr = pr->pe->vaddr;
 
-		pe = pr->pmes[pr->curr_pme];
+	return 1;
+}
 
-		if (!pe->zero)
+static int get_pagemap(struct page_read *pr, struct iovec *iov)
+{
+	for (;;) {
+		if (!advance(pr))
+			return 0;
+		if (!pr->pe->zero)
 			break;
 	}
 
-	pagemap2iovec(pe, iov);
-
-	pr->pe = pe;
-	pr->cvaddr = (unsigned long)iov->iov_base;
-
-	if (pe->in_parent && !pr->parent) {
+	if (pr->pe->in_parent && !pr->parent) {
 		pr_err("No parent for snapshot pagemap\n");
 		return -1;
 	}
 
+	pagemap2iovec(pr->pe, iov);
+
 	return 1;
 }
 
@@ -163,38 +166,25 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len)
 static int seek_pagemap_page(struct page_read *pr, unsigned long vaddr,
 			     bool warn)
 {
-	int ret;
-	struct iovec iov;
-
-	if (pr->pe)
-		pagemap2iovec(pr->pe, &iov);
-	else
-		goto new_pagemap;
+	pr->reset(pr);
 
-	while (1) {
-		unsigned long iov_end;
+	while (advance(pr)) {
+		unsigned long start = pr->pe->vaddr;
+		unsigned long len = pr->pe->nr_pages * PAGE_SIZE;
+		unsigned long end = start + len;
 
-		if (vaddr < pr->cvaddr) {
-			if (warn)
-				pr_err("Missing %lx in parent pagemap, current iov: base=%lx,len=%zu\n",
-					vaddr, (unsigned long)iov.iov_base, iov.iov_len);
-			return 0;
+		if (vaddr >= start && vaddr < end) {
+			skip_pagemap_pages(pr, vaddr - pr->cvaddr);
+			return 1;
 		}
-		iov_end = (unsigned long)iov.iov_base + iov.iov_len;
 
-		if (iov_end <= vaddr) {
-			skip_pagemap_pages(pr, iov_end - pr->cvaddr);
-new_pagemap:
-			ret = get_pagemap(pr, &iov);
-			if (ret <= 0)
-				return ret;
-
-			continue;
-		}
-
-		skip_pagemap_pages(pr, vaddr - pr->cvaddr);
-		return 1;
+		if (end <= vaddr)
+			skip_pagemap_pages(pr, end - pr->cvaddr);
 	}
+
+	if (warn)
+		pr_err("Missing %lx in parent pagemap\n", vaddr);
+	return 0;
 }
 
 static inline void pagemap_bound_check(PagemapEntry *pe, unsigned long vaddr, int nr)
diff --git a/criu/uffd.c b/criu/uffd.c
index 97cacea..ebb0e8e 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -372,6 +372,9 @@ static int get_page(struct lazy_pages_info *lpi, unsigned long addr, void *dest)
 	if (ret <= 0)
 		return ret;
 
+	if (lpi->pr.pe->zero)
+		return 0;
+
 	ret = lpi->pr.read_pages(&lpi->pr, addr, 1, buf);
 	pr_debug("read_pages ret %d\n", ret);
 	if (ret <= 0)
-- 
1.9.1



More information about the CRIU mailing list