[CRIU] [PATCH v3 09/12] shmem: implement anon shared memory dedup on dump

Eugene Batalov eabatalov89 at gmail.com
Sun Aug 7 06:11:13 PDT 2016


From: Fyodor Bocharov <bocharovfedor at gmail.com>

Dedup works as following: when dumping anon shmem vma we are checking its
every page for dirtiness (this info stored in bitmap with each anon shmem
vma). We dump each anon shmem vma using page-xfer. page-xfer does all
magic with storing "in_parent" field in pagemap-entry.
When restoring from deduplicated image we simply read every page with
page-read and it does all magic of reading from right place in image
hierarchy.
auto-dedup on restore is already implemented by page-read so we don't need
to code it.

Signed-off-by: Fyodor Bocharov <fbocharov at yandex.ru>
Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com>
---
 criu/shmem.c | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/criu/shmem.c b/criu/shmem.c
index f59a2e6..a91e085 100644
--- a/criu/shmem.c
+++ b/criu/shmem.c
@@ -2,6 +2,7 @@
 #include <sys/mman.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <stdbool.h>
 
 #include "list.h"
 #include "pid.h"
@@ -430,7 +431,9 @@ static int restore_shmem_content(void *addr, struct shmem_info *si)
 		if (vaddr + nr_pages * PAGE_SIZE > si->size)
 			break;
 
-		pr.read_pages(&pr, vaddr, nr_pages, addr + vaddr);
+		ret = pr.read_pages(&pr, vaddr, nr_pages, addr + vaddr);
+		if (ret < 0)
+			break;
 
 		if (pr.put_pagemap)
 			pr.put_pagemap(&pr);
@@ -586,17 +589,11 @@ static int dump_one_shmem(struct shmem_info *si)
 	struct page_pipe *pp;
 	struct page_xfer xfer;
 	int err, ret = -1, fd;
-	unsigned char *map = NULL;
 	void *addr = NULL;
 	unsigned long pfn, nrpages;
 
 	pr_info("Dumping shared memory %ld\n", si->shmid);
 
-	nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
-	map = xmalloc(nrpages * sizeof(*map));
-	if (!map)
-		goto err;
-
 	fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end);
 	if (fd < 0)
 		goto err;
@@ -609,17 +606,7 @@ static int dump_one_shmem(struct shmem_info *si)
 		goto err;
 	}
 
-	/*
-	 * We can't use pagemap here, because this vma is
-	 * not mapped to us at all, but mincore reports the
-	 * pagecache status of a file, which is correct in
-	 * this case.
-	 */
-
-	err = mincore(addr, si->size, map);
-	if (err)
-		goto err_unmap;
-
+	nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
 	pp = create_page_pipe((nrpages + 1) / 2, NULL, PP_CHUNK_MODE);
 	if (!pp)
 		goto err_unmap;
@@ -629,10 +616,24 @@ static int dump_one_shmem(struct shmem_info *si)
 		goto err_pp;
 
 	for (pfn = 0; pfn < nrpages; pfn++) {
-		if (!(map[pfn] & PAGE_RSS))
+		bool used;
+		bool dirty;
+		unsigned long pgaddr;
+
+		used = test_bit(pfn, si->pused_map);
+		if (!used)
 			continue;
+
+		dirty = test_bit(pfn, si->pdirty_map);
+		pgaddr = (unsigned long)addr + pfn * PAGE_SIZE;
 again:
-		ret = page_pipe_add_page(pp, (unsigned long)addr + pfn * PAGE_SIZE, 0);
+		if (page_is_zero(pfn))
+			ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_ZERO);
+		else if (xfer.parent && page_in_parent(dirty))
+			ret = page_pipe_add_hole(pp, pgaddr, PP_HOLE_PARENT);
+		else
+			ret = page_pipe_add_page(pp, pgaddr, 0);
+
 		if (ret == -EAGAIN) {
 			ret = dump_pages(pp, &xfer, addr);
 			if (ret)
@@ -652,7 +653,6 @@ err_pp:
 err_unmap:
 	munmap(addr,  si->size);
 err:
-	xfree(map);
 	return ret;
 }
 
-- 
1.9.1



More information about the CRIU mailing list