[CRIU] [PATCH 3/3] ipc: Keep shmem segments contents into pagemap/page images

Pavel Emelyanov xemul at virtuozzo.com
Mon Apr 3 09:20:04 PDT 2017


Right now the contents of the sysvipc shmem segment is stored as
raw blob in the ipcns-shm image. This is bad for two reasons.

First is that huge segments with holes are filled with real zeroes
in image. Second is that we prefer not to mix images with pb object
and raw data.

To fix both let's re-use the shmem.c code that keeps anon shared
memory contents in pagemap/pages images.

https://github.com/xemul/criu/issues/287

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>

---
 criu/include/shmem.h |  2 ++
 criu/ipc_ns.c        | 41 +++++++++++------------------------------
 criu/shmem.c         | 32 +++++++++++++++++++++++++++++++-
 images/ipc-shm.proto |  1 +
 4 files changed, 45 insertions(+), 31 deletions(-)

diff --git a/criu/include/shmem.h b/criu/include/shmem.h
index 63e7e9f..04ab8d0 100644
--- a/criu/include/shmem.h
+++ b/criu/include/shmem.h
@@ -13,6 +13,8 @@ extern int collect_sysv_shmem(unsigned long shmid, unsigned long size);
 extern int cr_dump_shmem(void);
 extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map);
 extern int fixup_sysv_shmems(void);
+extern int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid);
+extern int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid);
 
 #define SYSV_SHMEM_SKIP_FD	(0x7fffffff)
 
diff --git a/criu/ipc_ns.c b/criu/ipc_ns.c
index 0fcee68..d8590fa 100644
--- a/criu/ipc_ns.c
+++ b/criu/ipc_ns.c
@@ -338,15 +338,10 @@ static int ipc_sysctl_req(IpcVarEntry *e, int op)
 	return sysctl_op(req, nr, op, CLONE_NEWIPC);
 }
 
-/*
- * TODO: Function below should be later improved to locate and dump only dirty
- * pages via updated sys_mincore().
- */
-static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
+static int dump_ipc_shm_pages(const IpcShmEntry *shm)
 {
+	int ret;
 	void *data;
-	int ifd;
-	ssize_t size, off;
 
 	data = shmat(shm->desc->id, NULL, SHM_RDONLY);
 	if (data == (void *)-1) {
@@ -354,32 +349,13 @@ static int dump_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
 		return -errno;
 	}
 
-	/*
-	 * FIXME -- this just write the whole memory segment into the
-	 * image. In case the segment is huge this takes time. Need
-	 * to adopt the holes detection code (next_data_segment) from
-	 * shmem.c
-	 */
-	ifd = img_raw_fd(img);
-	size = round_up(shm->size, sizeof(u32));
-	off = 0;
-	do {
-		ssize_t ret;
-
-		ret = write(ifd, data + off, size - off);
-		if (ret <= 0) {
-			pr_perror("Failed to write IPC shared memory data");
-			return (int)ret;
-		}
-
-		off += ret;
-	} while (off < size);
+	ret = dump_one_sysv_shmem(data, shm->size, shm->desc->id);
 
 	if (shmdt(data)) {
 		pr_perror("Failed to detach IPC shared memory");
 		return -errno;
 	}
-	return 0;
+	return ret;
 }
 
 static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *ds)
@@ -390,6 +366,8 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d
 
 	shm.desc = &desc;
 	shm.size = ds->shm_segsz;
+	shm.has_in_pagemaps = true;
+	shm.in_pagemaps = true;
 	fill_ipc_desc(id, shm.desc, &ds->shm_perm);
 	pr_info_ipc_shm(&shm);
 
@@ -398,7 +376,7 @@ static int dump_ipc_shm_seg(struct cr_img *img, int id, const struct shmid_ds *d
 		pr_err("Failed to write IPC shared memory segment\n");
 		return ret;
 	}
-	return dump_ipc_shm_pages(img, &shm);
+	return dump_ipc_shm_pages(&shm);
 }
 
 static int dump_ipc_shm(struct cr_img *img)
@@ -811,7 +789,10 @@ static int prepare_ipc_shm_pages(struct cr_img *img, const IpcShmEntry *shm)
 		return -errno;
 	}
 
-	ret = restore_content(data, img, shm);
+	if (shm->has_in_pagemaps && shm->in_pagemaps)
+		ret = restore_sysv_shmem_content(data, shm->size, shm->desc->id);
+	else
+		ret = restore_content(data, img, shm);
 
 	if (shmdt(data)) {
 		pr_perror("Failed to detach IPC shared memory");
diff --git a/criu/shmem.c b/criu/shmem.c
index 603c899..a55f346 100644
--- a/criu/shmem.c
+++ b/criu/shmem.c
@@ -496,6 +496,11 @@ static int restore_shmem_content(void *addr, struct shmem_info *si)
 	return do_restore_shmem_content(addr, si->size, si->shmid);
 }
 
+int restore_sysv_shmem_content(void *addr, unsigned long size, unsigned long shmid)
+{
+	return do_restore_shmem_content(addr, round_up(size, PAGE_SIZE), shmid);
+}
+
 static int open_shmem(int pid, struct vma_area *vma)
 {
 	VmaEntry *vi = vma->e;
@@ -693,7 +698,7 @@ static int do_dump_one_shmem(int fd, void *addr, struct shmem_info *si)
 		    next_data_segment(fd, pfn, &next_data_pnf, &next_hole_pfn))
 			goto err_xfer;
 
-		if (is_shmem_tracking_en()) {
+		if (si->pstate_map && is_shmem_tracking_en()) {
 			pgstate = get_pstate(si->pstate_map, pfn);
 			use_mc = pgstate == PST_DONT_DUMP;
 		}
@@ -761,6 +766,31 @@ err:
 	return ret;
 }
 
+int dump_one_sysv_shmem(void *addr, unsigned long size, unsigned long shmid)
+{
+	int fd, ret;
+	struct shmem_info *si, det;
+
+	si = shmem_find(shmid);
+	if (!si) {
+		pr_info("Detached shmem...\n");
+		det.pid = SYSVIPC_SHMEM_PID;
+		det.shmid = shmid;
+		det.size = round_up(size, PAGE_SIZE);
+		det.pstate_map = NULL;
+		si = &det;
+	}
+
+	fd = open_proc(PROC_SELF, "map_files/%lx-%lx",
+			(unsigned long)addr, (unsigned long)addr + si->size);
+	if (fd < 0)
+		return -1;
+
+	ret = do_dump_one_shmem(fd, addr, si);
+	close(fd);
+	return ret;
+}
+
 int cr_dump_shmem(void)
 {
 	int ret = 0, i;
diff --git a/images/ipc-shm.proto b/images/ipc-shm.proto
index 4f331d2..31e172e 100644
--- a/images/ipc-shm.proto
+++ b/images/ipc-shm.proto
@@ -5,4 +5,5 @@ import "ipc-desc.proto";
 message ipc_shm_entry {
 	required ipc_desc_entry		desc	= 1;
 	required uint64			size	= 2;
+	optional bool			in_pagemaps = 3;
 }
-- 
2.5.5



More information about the CRIU mailing list