[CRIU] [PATCH v2 1/4] page-xfer: add ability to send pages from local dump

Mike Rapoport rppt at linux.vnet.ibm.com
Sun Nov 27 02:52:54 PST 2016


Currently, standalone page-server can only receive pages from the remote
dump. Extend it with the ability to serve local memory dump to a remote
lazy-pages daemon.

Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/cr-restore.c     |  13 ++++++
 criu/include/pstree.h |   1 +
 criu/page-xfer.c      | 108 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 51c423d..c248d3d 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -2035,6 +2035,19 @@ int prepare_task_entries(void)
 	return 0;
 }
 
+int prepare_dummy_task_state(struct pstree_item *pi)
+{
+	CoreEntry *core;
+
+	if (open_core(pi->pid.virt, &core))
+		return -1;
+
+	pi->pid.state = core->tc->task_state;
+	core_entry__free_unpacked(core, NULL);
+
+	return 0;
+}
+
 int cr_restore_tasks(void)
 {
 	int ret = -1;
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
index 21a1ae0..67e8516 100644
--- a/criu/include/pstree.h
+++ b/criu/include/pstree.h
@@ -97,6 +97,7 @@ extern int pid_to_virt(pid_t pid);
 struct task_entries;
 extern struct task_entries *task_entries;
 extern int prepare_task_entries(void);
+extern int prepare_dummy_task_state(struct pstree_item *pi);
 
 extern int get_task_ids(struct pstree_item *);
 extern struct _TaskKobjIdsEntry *root_ids;
diff --git a/criu/page-xfer.c b/criu/page-xfer.c
index cae63f4..315d152 100644
--- a/criu/page-xfer.c
+++ b/criu/page-xfer.c
@@ -19,6 +19,7 @@
 #include "fcntl.h"
 #include "pstree.h"
 #include "parasite-syscall.h"
+#include "rst_info.h"
 
 static int page_server_sk = -1;
 
@@ -815,14 +816,119 @@ static int page_server_serve(int sk)
 	return ret;
 }
 
+static int fill_page_pipe(struct page_read *pr, struct page_pipe *pp)
+{
+	struct page_pipe_buf *ppb;
+	int i, ret;
+
+	pr->reset(pr);
+
+	while (pr->advance(pr)) {
+		unsigned long vaddr = pr->pe->vaddr;
+
+		for (i = 0; i < pr->pe->nr_pages; i++, vaddr += PAGE_SIZE) {
+			if (pagemap_zero(pr->pe))
+				ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_ZERO);
+			else if (pagemap_in_parent(pr->pe))
+				ret = page_pipe_add_hole(pp, vaddr, PP_HOLE_PARENT);
+			else
+				ret = page_pipe_add_page(pp, vaddr, pagemap_lazy(pr->pe) ? PPB_LAZY : 0);
+			if (ret) {
+				pr_err("Failed adding page at %lx\n", vaddr);
+				return -1;
+			}
+		}
+	}
+
+	list_for_each_entry(ppb, &pp->bufs, l) {
+		for (i = 0; i < ppb->nr_segs; i++) {
+			struct iovec iov = get_iov(ppb->iov, i,
+						   pp->flags & PP_COMPAT);
+			if (splice(img_raw_fd(pr->pi), NULL, ppb->p[1], NULL,
+				   iov.iov_len, SPLICE_F_MOVE) != iov.iov_len) {
+				pr_perror("Splice failed");
+				return -1;
+			}
+		}
+	}
+
+	debug_show_page_pipe(pp);
+
+	return 0;
+}
+
+static int page_pipe_from_pagemap(struct page_pipe **pp, int pid)
+{
+	struct page_read pr;
+	int nr_pages = 0;
+
+	if (open_page_read(pid, &pr, PR_TASK) <= 0) {
+		pr_err("Failed to open page read for %d\n", pid);
+		return -1;
+	}
+
+	while (pr.advance(&pr))
+		if (pagemap_present(pr.pe))
+			nr_pages += pr.pe->nr_pages;
+
+	*pp = create_page_pipe(nr_pages, NULL, 0);
+	if (!*pp) {
+		pr_err("Cannot create page pipe for %d\n", pid);
+		return -1;
+	}
+
+	if (fill_page_pipe(&pr, *pp))
+		return -1;
+
+	return 0;
+}
+
+static int page_server_init_send(void)
+{
+	struct pstree_item *pi;
+	struct page_pipe *pp;
+
+	BUILD_BUG_ON(sizeof(struct dmp_info) > sizeof(struct rst_info));
+
+	if (prepare_dummy_pstree())
+		return -1;
+
+	for_each_pstree_item(pi) {
+		if (prepare_dummy_task_state(pi))
+			return -1;
+
+		if (!task_alive(pi))
+			continue;
+
+		if (page_pipe_from_pagemap(&pp, pi->pid.virt)) {
+			pr_err("%d: failed to open page-read\n", pi->pid.virt);
+			return -1;
+		}
+
+		/*
+		 * prepare_dummy_pstree presumes 'restore' behaviour,
+		 * but page_server_get_pages uses dmpi() to get access
+		 * to the page-pipe, so we are faking it here.
+		 */
+		memset(rsti(pi), 0, sizeof(struct rst_info));
+		dmpi(pi)->mem_pp = pp;
+	}
+
+	return 0;
+}
+
 int cr_page_server(bool daemon_mode, int cfd)
 {
 	int ask = -1;
 	int sk = -1;
 	int ret;
 
-	if (!opts.lazy_pages)
+	if (!opts.lazy_pages) {
 		up_page_ids_base();
+	} else {
+		if (page_server_init_send())
+			return -1;
+	}
 
 	if (opts.ps_socket != -1) {
 		ret = 0;
-- 
1.9.1



More information about the CRIU mailing list