[CRIU] [PATCHv0 5/8] shmem: implement dirty page tracking for anon shared memory

Eugene Batalov eabatalov89 at gmail.com
Sun Dec 6 05:15:21 PST 2015


From: Fyodor <bocharovfedor at gmail.com>

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.

Signed-off-by: Fyodor Bocharov <fbocharov at yandex.ru>
Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com>
---
 cr-dump.c       | 18 ++++++++++++++----
 include/shmem.h |  3 ++-
 shmem.c         | 47 ++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 466880e..e96c3a3 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -82,6 +82,7 @@
 #include "seccomp.h"
 #include "seize.h"
 #include "fault-injection.h"
+#include "pagemap-cache.h"
 
 #include "asm/dump.h"
 
@@ -407,6 +408,7 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
 	MmEntry mme = MM_ENTRY__INIT;
 	struct vma_area *vma_area;
 	int ret = -1, i = 0;
+	pmc_t pmc = PMC_INIT;
 
 	pr_info("\n");
 	pr_info("Dumping mm (pid: %d)\n", pid);
@@ -415,10 +417,15 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
 	mme.n_vmas = vma_area_list->nr;
 	mme.vmas = xmalloc(mme.n_vmas * sizeof(VmaEntry *));
 	if (!mme.vmas)
-		goto err;
+		goto init_err;
+
+	if (pmc_init(&pmc, pid, &vma_area_list->h,
+			 vma_area_list->longest * PAGE_SIZE))
+		goto init_err;
 
 	list_for_each_entry(vma_area, &vma_area_list->h, list) {
 		VmaEntry *vma = vma_area->e;
+		u64 *map;
 
 		pr_info_vma(vma_area);
 
@@ -426,9 +433,10 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
 			ret = 0;
 		else if (vma_entry_is(vma, VMA_AREA_SYSVIPC))
 			ret = check_sysvipc_map_dump(pid, vma);
-		else if (vma_entry_is(vma, VMA_ANON_SHARED))
-			ret = add_shmem_area(pid, vma);
-		else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
+		else if (vma_entry_is(vma, VMA_ANON_SHARED)) {
+			map = pmc_get_map(&pmc, vma_area);
+			ret = add_shmem_area(pid, vma, map);
+		} else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
 				vma_entry_is(vma, VMA_FILE_SHARED))
 			ret = dump_filemap(pid, vma_area, imgset);
 		else if (vma_entry_is(vma, VMA_AREA_SOCKET))
@@ -482,6 +490,8 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
 	free_aios(&mme);
 
 err:
+	pmc_fini(&pmc);
+init_err:
 	return ret;
 }
 
diff --git a/include/shmem.h b/include/shmem.h
index 47dd0fd..066b5c3 100644
--- a/include/shmem.h
+++ b/include/shmem.h
@@ -1,6 +1,7 @@
 #ifndef __CR_SHMEM_H__
 #define __CR_SHMEM_H__
 
+#include "asm/int.h"
 #include "lock.h"
 #include "protobuf/vma.pb-c.h"
 
@@ -10,6 +11,6 @@ extern void show_saved_shmems(void);
 extern int get_shmem_fd(int pid, VmaEntry *vi);
 
 extern int cr_dump_shmem(void);
-extern int add_shmem_area(pid_t pid, VmaEntry *vma);
+extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map);
 
 #endif /* __CR_SHMEM_H__ */
diff --git a/shmem.c b/shmem.c
index b2900f4..8563415 100644
--- a/shmem.c
+++ b/shmem.c
@@ -12,6 +12,7 @@
 #include "page-xfer.h"
 #include "rst-malloc.h"
 #include "vma.h"
+#include "mem.h"
 
 #include "protobuf.h"
 #include "protobuf/pagemap.pb-c.h"
@@ -282,6 +283,7 @@ struct shmem_info_dump {
 	unsigned long	start;
 	unsigned long	end;
 	int		pid;
+	unsigned long	*pdirty_map;
 
 	struct shmem_info_dump *next;
 };
@@ -289,6 +291,35 @@ struct shmem_info_dump {
 #define SHMEM_HASH_SIZE	32
 static struct shmem_info_dump *shmems_hash[SHMEM_HASH_SIZE];
 
+#define BLOCKS_CNT(size, block_size) (((size) + (block_size) - 1) / (block_size))
+
+static int expand_shmem_pdirty_map(struct shmem_info_dump *si, unsigned long mem_size)
+{
+	unsigned long nr_pages, size, new_size;
+
+	nr_pages = BLOCKS_CNT(si->size, PAGE_SIZE);
+	size = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map));
+
+	nr_pages = BLOCKS_CNT(mem_size, PAGE_SIZE);
+	new_size = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map));
+
+	si->pdirty_map = xrealloc(si->pdirty_map, new_size);
+	if (!si->pdirty_map)
+		return -1;
+	memzero((char *)si->pdirty_map + size, new_size - size);
+
+	return 0;
+}
+
+static void update_shmem_pdirty_map(struct shmem_info_dump *si, u64 *map)
+{
+	unsigned long p, pcount = BLOCKS_CNT(si->size, PAGE_SIZE);
+
+	for (p = 0; p < pcount; ++p)
+		if (map[p] & PME_SOFT_DIRTY)
+			set_bit(p, si->pdirty_map);
+}
+
 static struct shmem_info_dump *shmem_find(struct shmem_info_dump **chain,
 		unsigned long shmid)
 {
@@ -301,7 +332,7 @@ static struct shmem_info_dump *shmem_find(struct shmem_info_dump **chain,
 	return NULL;
 }
 
-int add_shmem_area(pid_t pid, VmaEntry *vma)
+int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map)
 {
 	struct shmem_info_dump *si, **chain;
 	unsigned long size = vma->pgoff + (vma->end - vma->start);
@@ -309,12 +340,18 @@ int add_shmem_area(pid_t pid, VmaEntry *vma)
 	chain = &shmems_hash[vma->shmid % SHMEM_HASH_SIZE];
 	si = shmem_find(chain, vma->shmid);
 	if (si) {
-		if (si->size < size)
+		if (si->size < size) {
+			if (expand_shmem_pdirty_map(si, size))
+				return -1;
+
 			si->size = size;
+		}
+		update_shmem_pdirty_map(si, map);
+
 		return 0;
 	}
 
-	si = xmalloc(sizeof(*si));
+	si = xzalloc(sizeof(*si));
 	if (!si)
 		return -1;
 
@@ -327,6 +364,10 @@ int add_shmem_area(pid_t pid, VmaEntry *vma)
 	si->end = vma->end;
 	si->shmid = vma->shmid;
 
+	if (expand_shmem_pdirty_map(si, size))
+		return -1;
+	update_shmem_pdirty_map(si, map);
+
 	return 0;
 }
 
-- 
1.9.1



More information about the CRIU mailing list