[CRIU] [PATCH] dedup: add dedup on unmap vma, into auto-dedup and dedup

Tikhomirov Pavel snorcht at gmail.com
Mon Mar 31 03:24:16 PDT 2014


add evaddr in page_read to identify the end of curently checked area
of pagemap entry, and then if we seek through(pass by) some part of
pagemap entry, we assume this part(piece from evaddr) as unmaped
in newer image, so we can dedup it in parent

Example:
2 --data--|---- -unmaped -----|--data--
1 ----data ----|--data--|----- data----
  cccccccc euuu euuuuuuu euuuu cccccccc
c - stands for checked page, e and u - page for deduplication on
unmap(e - evaddr)

test: this patch make all images of size 0 in:
sudo bash test/zdtm.sh --auto-dedup -P -i 10  transition/maps007

Signed-off-by: Tikhomirov Pavel <snorcht at gmail.com>
---
 cr-dedup.c          | 17 +++++++++++++++++
 include/page-read.h |  4 ++++
 page-read.c         | 29 +++++++++++++++++++++++++++++
 page-xfer.c         |  6 +++++-
 4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/cr-dedup.c b/cr-dedup.c
index 7758674..9a485b3 100644
--- a/cr-dedup.c
+++ b/cr-dedup.c
@@ -87,6 +87,18 @@ static int cr_dedup_one_pagemap(int pid)
 			ret = dedup_one_iovec(prp, &iov);
 			if (ret)
 				goto exit;
+		} else {
+			/*
+			 * If data is in parent go check it, check will use
+			 * seek_pagemap_page, it starts deduplication of
+			 * passed by unmaped areas
+			 */
+			ret = check_pagehole_in_parent(prp, &iov);
+			if (ret) {
+				pr_err("Hole %p/%zu not found in parent\n",
+				       iov.iov_base, iov.iov_len);
+				goto exit;
+			}
 		}
 
 		pr.put_pagemap(&pr);
@@ -176,6 +188,11 @@ int dedup_one_iovec(struct page_read *pr, struct iovec *iov)
 				return ret;
 		}
 
+		/*
+		 * set evaddr to the end of checked area
+		 */
+		pr->evaddr = min(piov_end, iov_end);
+
 		prp = pr->parent;
 		if (prp) {
 			/* recursively */
diff --git a/include/page-read.h b/include/page-read.h
index 7a063e9..1dc993f 100644
--- a/include/page-read.h
+++ b/include/page-read.h
@@ -62,6 +62,9 @@ struct page_read {
 					   go to this guy for page, see
 					   read_pagemap_page */
 	unsigned long cvaddr;		/* vaddr we are on */
+	unsigned long evaddr;		/* vaddr of the end of checked area
+					   need this to know what part of
+					   pagemap is unmounted */
 
 	struct iovec bunch;		/* record consequent neighbour
 					   iovecs to punch together */
@@ -75,4 +78,5 @@ extern int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool war
 
 extern int dedup_one_iovec(struct page_read *pr, struct iovec *iov);
 extern int punch_hole(struct page_read *pr, unsigned long off, unsigned long len, bool cleanup);
+extern int check_pagehole_in_parent(struct page_read *p, struct iovec *iov);
 #endif /* __CR_PAGE_READ_H__ */
diff --git a/page-read.c b/page-read.c
index 8937f33..aab9efe 100644
--- a/page-read.c
+++ b/page-read.c
@@ -62,6 +62,7 @@ static int get_pagemap(struct page_read *pr, struct iovec *iov)
 
 	pr->pe = pe;
 	pr->cvaddr = (unsigned long)iov->iov_base;
+	pr->evaddr = (unsigned long)iov->iov_base;
 
 	if (pe->in_parent && !pr->parent) {
 		pr_err("No parent for snapshot pagemap\n");
@@ -87,6 +88,7 @@ static void skip_pagemap_pages(struct page_read *pr, unsigned long len)
 	if (!pr->pe->in_parent)
 		lseek(pr->fd_pg, len, SEEK_CUR);
 	pr->cvaddr += len;
+	pr->evaddr += len;
 }
 
 int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool warn)
@@ -101,6 +103,7 @@ int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool warn)
 
 	while (1) {
 		unsigned long iov_end;
+		struct iovec tiov;
 
 		if (vaddr < pr->cvaddr) {
 			if (warn)
@@ -111,6 +114,19 @@ int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool warn)
 		iov_end = (unsigned long)iov.iov_base + iov.iov_len;
 
 		if (iov_end <= vaddr) {
+			/*
+			 * If pass by pagemap entry in parent, it was unmaped so we can dedup it
+			 * pr->evaddr is used to identify end of previously checked region
+			 */
+			if (opts.auto_dedup) {
+				tiov.iov_base = (void*)pr->evaddr;
+				tiov.iov_len = iov_end - pr->evaddr;
+				if (tiov.iov_len > 0) {
+					pr_debug("pr%d: Assume(1) unmaped vma from %lx len %lx\n", pr->id, pr->evaddr, tiov.iov_len);
+					dedup_one_iovec(pr, &tiov);
+				}
+			}
+
 			skip_pagemap_pages(pr, iov_end - pr->cvaddr);
 			put_pagemap(pr);
 new_pagemap:
@@ -120,6 +136,18 @@ new_pagemap:
 
 			continue;
 		}
+		
+		/*
+		 * If pass by part of pagemap entry in parent, it was unmaped
+		 */
+		if (opts.auto_dedup) {
+			tiov.iov_base = (void*)pr->evaddr;
+			tiov.iov_len = vaddr - pr->evaddr;
+			if (tiov.iov_len > 0) {
+				pr_debug("pr%d: Assume(2) unmaped vma from %lx len %lx\n", pr->id, pr->evaddr, tiov.iov_len);
+				dedup_one_iovec(pr, &tiov);
+			}
+		}
 
 		skip_pagemap_pages(pr, vaddr - pr->cvaddr);
 		return 1;
@@ -157,6 +185,7 @@ static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *bu
 	}
 
 	pr->cvaddr += PAGE_SIZE;
+	pr->evaddr += PAGE_SIZE;
 
 	return 1;
 }
diff --git a/page-xfer.c b/page-xfer.c
index f26be35..c63bec2 100644
--- a/page-xfer.c
+++ b/page-xfer.c
@@ -487,7 +487,7 @@ static int write_pages_loc(struct page_xfer *xfer,
 	return 0;
 }
 
-static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov)
+int check_pagehole_in_parent(struct page_read *p, struct iovec *iov)
 {
 	int ret;
 	unsigned long off, end;
@@ -521,6 +521,10 @@ static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov)
 		 */
 
 		pend = (unsigned long)piov.iov_base + piov.iov_len;
+		/*
+		 * Set evaddr to the end of checked area
+		 */
+		p->evaddr = min(pend, end);
 		if (end <= pend)
 			return 0;
 
-- 
1.8.3.2



More information about the CRIU mailing list