[CRIU] [PATCH v3 05/12] shmem: implement used and dirty pages tracking

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


From: Fyodor Bocharov <bocharovfedor at gmail.com>

To track anon shared vma pages usage we create a bitmap for it.
Each bit in this bitmap corresponds to particular page in vma. Bit with
value of 1 in this map states that page is used. Bit 0 states that the
page wasn't ever used by any dumpee process.
Page is considered used if it has at least one PME_PRESENT or PME_SWAP
bit set in any dumpee process pagemap.
Pages usage tracking allows us not to dump unused pages at all.

To track anon shared vma pages dirtiness we create a bitmap for it.
Each bit in this bitmap corresponds to particular page in vma. Bit with
value of 1 in this map states that page is dirty. Bit 0 states that the
page is clean.
Page is considered dirty if it has at least one PME_SOFT_DIRTY bit set in
any dumpee process pagemap.
Dirty pages tracking allows not to dump used pages on incremental dumps
if pages contents haven't changed.

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

diff --git a/criu/shmem.c b/criu/shmem.c
index f8a3ba3..f59a2e6 100644
--- a/criu/shmem.c
+++ b/criu/shmem.c
@@ -81,6 +81,8 @@ struct shmem_info {
 		struct { /* For dump */
 			unsigned long	start;
 			unsigned long	end;
+			unsigned long	*pdirty_map;
+			unsigned long	*pused_map;
 		};
 	};
 };
@@ -120,6 +122,52 @@ static struct shmem_info *shmem_find(unsigned long shmid)
 	return NULL;
 }
 
+#define BLOCKS_CNT(size, block_size) \
+	(((size) + (block_size) - 1) / (block_size))
+
+static int expand_shmem(struct shmem_info *si, unsigned long new_size)
+{
+	unsigned long nr_pages, nr_map_items, map_size,
+				nr_new_map_items, new_map_size;
+
+	nr_pages = BLOCKS_CNT(si->size, PAGE_SIZE);
+	nr_map_items = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map) * 8);
+	map_size = nr_map_items * sizeof(*si->pdirty_map);
+
+	nr_pages = BLOCKS_CNT(new_size, PAGE_SIZE);
+	nr_new_map_items = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map) * 8);
+	new_map_size = nr_new_map_items * sizeof(*si->pdirty_map);
+
+	BUG_ON(new_map_size < map_size);
+
+	si->pdirty_map = xrealloc(si->pdirty_map, new_map_size);
+	if (!si->pdirty_map)
+		return -1;
+	memzero(si->pdirty_map + nr_map_items, new_map_size - map_size);
+
+	si->pused_map = xrealloc(si->pused_map, new_map_size);
+	if (!si->pused_map)
+		return -1;
+	memzero(si->pused_map + nr_map_items, new_map_size - map_size);
+
+	si->size = new_size;
+	return 0;
+}
+
+static void update_shmem_pmaps(struct shmem_info *si, u64 *map,
+		unsigned long off)
+{
+	unsigned long p, pcount, poff;
+
+	pcount = BLOCKS_CNT(si->size - off, PAGE_SIZE);
+	poff = BLOCKS_CNT(off, PAGE_SIZE);
+	for (p = 0; p < pcount; ++p) {
+		if (map[p] & PME_SOFT_DIRTY)
+			set_bit(p + poff, si->pdirty_map);
+		if ((map[p] & PME_PRESENT) || (map[p] & PME_SWAP))
+			set_bit(p + poff, si->pused_map);
+	}
+}
 
 int collect_sysv_shmem(unsigned long shmid, unsigned long size)
 {
@@ -489,26 +537,32 @@ int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map)
 {
 	struct shmem_info *si;
 	unsigned long size = vma->pgoff + (vma->end - vma->start);
-	(void)map;
 
 	si = shmem_find(vma->shmid);
 	if (si) {
-		if (si->size < size)
-			si->size = size;
+		if (si->size < size) {
+			if (expand_shmem(si, size))
+				return -1;
+		}
+		update_shmem_pmaps(si, map, vma->pgoff);
+
 		return 0;
 	}
 
-	si = xmalloc(sizeof(*si));
+	si = xzalloc(sizeof(*si));
 	if (!si)
 		return -1;
 
-	si->size = size;
 	si->pid = pid;
 	si->start = vma->start;
 	si->end = vma->end;
 	si->shmid = vma->shmid;
 	shmem_hash_add(si);
 
+	if (expand_shmem(si, size))
+		return -1;
+	update_shmem_pmaps(si, map, vma->pgoff);
+
 	return 0;
 }
 
-- 
1.9.1



More information about the CRIU mailing list