[CRIU] Attempt for process migration

Adrian Reber adrian at lisas.de
Tue Mar 6 06:19:31 EST 2012


I have been successfully using criu. Now I looked into migrating one
process from one machine to another. I written some code but before I am
going to continue I wanted to ask if there has been already any
discussion in that direction? Also, the current code makes it hard to
implement migration over TCP and therefore I wanted some feedback before
continuing. Not that I am doing it completely wrong. Attached is a patch
which I am using to write the image to another machine.

It basically works that way:

 * user supplies with -r [host:port] on which machine a server is
   listening to receive the checkpoint image

 * after that I changed cr_fdset_open() to open a socket instead of
   a file to which the checkpoint can be transferred

So far it still seems correct. Unfortunately I had to add at the opts
structure to many functions as parameter to have it available in the
cr_fdset_open() function. The problem I have with cr_fdset_open() is
that it is writing the magic string just after the file has been opened
and that is something I cannot do with the socket if I want to use only
one TCP connection for the complete migration. Would it be somehow
possible to move the writing of the magic string to the low level
write_img_buf() function? Is it at all possible with the current code to
use one socket to write all images serialized over the network to
another machine?

Does it make any sense how I started with this?

Are there ideas how correctly implement this?

		Adrian
-------------- next part --------------
diff --git a/cr-dump.c b/cr-dump.c
index c4d62fe..49452ff 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1222,11 +1222,11 @@ err:
 }
 
 static int dump_one_zombie(struct pstree_item *item, struct proc_pid_stat *pps,
-		struct cr_fdset *cr_fdset)
+		struct cr_fdset *cr_fdset, struct cr_options *opts)
 {
 	struct core_entry *core;
 
-	cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset);
+	cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset, opts);
 	if (cr_fdset == NULL)
 		return -1;
 
@@ -1243,7 +1243,7 @@ static int dump_one_zombie(struct pstree_item *item, struct proc_pid_stat *pps,
 static struct proc_pid_stat pps_buf;
 
 static int dump_task_threads(struct parasite_ctl *parasite_ctl,
-					struct pstree_item *item)
+				struct pstree_item *item, struct cr_options *opts)
 {
 	int i;
 	struct cr_fdset *cr_fdset_thread = NULL;
@@ -1256,7 +1256,7 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
 		if (item->pid == item->threads[i])
 			continue;
 
-		cr_fdset_thread = cr_dump_fdset_open(item->threads[i], CR_FD_DESC_CORE, NULL);
+		cr_fdset_thread = cr_dump_fdset_open(item->threads[i], CR_FD_DESC_CORE, NULL, opts);
 		if (!cr_fdset_thread)
 			goto err;
 
@@ -1274,7 +1274,7 @@ err:
 	return -1;
 }
 
-static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
+static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset, struct cr_options *opts)
 {
 	pid_t pid = item->pid;
 	LIST_HEAD(vma_area_list);
@@ -1298,10 +1298,10 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 
 	if (item->state == TASK_DEAD)
-		return dump_one_zombie(item, &pps_buf, cr_fdset);
+		return dump_one_zombie(item, &pps_buf, cr_fdset, opts);
 
 	ret = -1;
-	if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_TASK, cr_fdset))
+	if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_TASK, cr_fdset, opts))
 		goto err;
 
 	ret = collect_mappings(pid, &vma_area_list);
@@ -1352,7 +1352,7 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 	}
 
-	ret = dump_task_threads(parasite_ctl, item);
+	ret = dump_task_threads(parasite_ctl, item, opts);
 	if (ret) {
 		pr_err("Can't dump threads\n");
 		goto err;
@@ -1415,7 +1415,7 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
 		goto err;
 
 	if (opts->namespaces_flags) {
-		ret = dump_namespaces(pid, opts->namespaces_flags);
+		ret = dump_namespaces(pid, opts);
 		if (ret < 0)
 			goto err;
 	}
@@ -1430,12 +1430,12 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
 	collect_sockets();
 
 	list_for_each_entry(item, &pstree_list, list) {
-		cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_NONE, NULL);
+		cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_NONE, NULL, opts);
 		if (!cr_fdset)
 			goto err;
 
 		if (item->pid == pid) {
-			if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_USE(CR_FD_PSTREE), cr_fdset))
+			if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_USE(CR_FD_PSTREE), cr_fdset, opts))
 				goto err;
 			if (dump_pstree(pid, &pstree_list, cr_fdset))
 				goto err;
@@ -1448,10 +1448,10 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
 		 * That's why we open the file with tree leader's pid for any
 		 * of it's children.
 		 */
-		if (!cr_dump_fdset_open(pid, CR_FD_DESC_USE(CR_FD_SK_QUEUES), cr_fdset))
+		if (!cr_dump_fdset_open(pid, CR_FD_DESC_USE(CR_FD_SK_QUEUES), cr_fdset, opts))
 			goto err;
 
-		if (dump_one_task(item, cr_fdset))
+		if (dump_one_task(item, cr_fdset, opts))
 			goto err;
 
 		close_cr_fdset(&cr_fdset);
diff --git a/cr-show.c b/cr-show.c
index eeb7042..28a5f9e 100644
--- a/cr-show.c
+++ b/cr-show.c
@@ -551,7 +551,7 @@ static int cr_show_all(unsigned long pid, struct cr_options *opts)
 	LIST_HEAD(pstree_list);
 	int i, ret = -1;
 
-	cr_fdset = cr_show_fdset_open(pid, CR_FD_DESC_PSTREE | CR_FD_DESC_SK_QUEUES);
+	cr_fdset = cr_show_fdset_open(pid, CR_FD_DESC_PSTREE | CR_FD_DESC_SK_QUEUES, opts);
 	if (!cr_fdset)
 		goto out;
 
@@ -565,13 +565,13 @@ static int cr_show_all(unsigned long pid, struct cr_options *opts)
 
 	close_cr_fdset(&cr_fdset);
 
-	ret = try_show_namespaces(pid);
+	ret = try_show_namespaces(pid, opts);
 	if (ret)
 		goto out;
 
 	list_for_each_entry(item, &pstree_list, list) {
 
-		cr_fdset = cr_show_fdset_open(item->pid, CR_FD_DESC_TASK);
+		cr_fdset = cr_show_fdset_open(item->pid, CR_FD_DESC_TASK, opts);
 		if (!cr_fdset)
 			goto out;
 
@@ -586,7 +586,7 @@ static int cr_show_all(unsigned long pid, struct cr_options *opts)
 				if (item->threads[i] == item->pid)
 					continue;
 
-				cr_fdset_th = cr_show_fdset_open(item->threads[i], CR_FD_DESC_CORE);
+				cr_fdset_th = cr_show_fdset_open(item->threads[i], CR_FD_DESC_CORE, opts);
 				if (!cr_fdset_th)
 					goto out;
 
diff --git a/crtools.c b/crtools.c
index 469a7b3..2640474 100644
--- a/crtools.c
+++ b/crtools.c
@@ -6,6 +6,7 @@
 #include <getopt.h>
 #include <string.h>
 #include <ctype.h>
+#include <netdb.h>
 
 #include <fcntl.h>
 
@@ -142,6 +143,34 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
 	},
 };
 
+static int open_socket(char *hostname, int portno)
+{
+	static int sockfd = -1;
+	struct hostent *server;
+	struct sockaddr_in serveraddr;
+
+	if (sockfd != -1)
+		return sockfd;
+
+	sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sockfd < 0)
+		pr_perror("ERROR opening socket");
+
+	server = gethostbyname(hostname);
+	if (server == NULL)
+		pr_perror("ERROR, no such host as %s\n", hostname);
+
+	memset((char *) &serveraddr, 0, sizeof(serveraddr));
+	serveraddr.sin_family = AF_INET;
+	memcpy((char *)&serveraddr.sin_addr.s_addr,(char *)server->h_addr, server->h_length);
+	serveraddr.sin_port = htons(portno);
+
+	if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
+		pr_perror("ERROR connecting\n");
+
+	return sockfd;
+}
+
 static struct cr_fdset *alloc_cr_fdset(void)
 {
 	struct cr_fdset *cr_fdset;
@@ -181,7 +210,8 @@ void close_cr_fdset(struct cr_fdset **cr_fdset)
 }
 
 static struct cr_fdset *cr_fdset_open(int pid, unsigned long use_mask,
-			       unsigned long flags, struct cr_fdset *cr_fdset)
+			       unsigned long flags, struct cr_fdset *cr_fdset,
+			       struct cr_options *opts)
 {
 	struct cr_fdset *fdset;
 	unsigned int i;
@@ -205,6 +235,11 @@ static struct cr_fdset *cr_fdset_open(int pid, unsigned long use_mask,
 		if (fdset->fds[i] != -1)
 			continue;
 
+		if (opts->host && (opts->port > 0)) {
+			fdset->fds[i] = open_socket(opts->host, opts->port);
+			continue;
+		}
+
 		ret = get_image_path(path, sizeof(path),
 				fdset_template[i].fmt, pid);
 		if (ret)
@@ -254,15 +289,17 @@ err:
 }
 
 struct cr_fdset *cr_dump_fdset_open(int pid, unsigned long use_mask,
-				     struct cr_fdset *cr_fdset)
+				     struct cr_fdset *cr_fdset,
+				     struct cr_options *opts)
 {
 	return cr_fdset_open(pid, use_mask, O_RDWR | O_CREAT | O_EXCL,
-			     cr_fdset);
+			     cr_fdset, opts);
 }
 
-struct cr_fdset *cr_show_fdset_open(int pid, unsigned long use_mask)
+struct cr_fdset *cr_show_fdset_open(int pid, unsigned long use_mask,
+				     struct cr_options *opts)
 {
-	return cr_fdset_open(pid, use_mask, O_RDONLY, NULL);
+	return cr_fdset_open(pid, use_mask, O_RDONLY, NULL, opts);
 }
 
 static int parse_ns_string(const char *ptr, unsigned int *flags)
@@ -296,7 +333,7 @@ int main(int argc, char *argv[])
 	int log_inited = 0;
 	int log_level = 0;
 
-	static const char short_opts[] = "dsf:p:t:hcD:o:n:v";
+	static const char short_opts[] = "dsf:p:t:hcD:o:n:vr:";
 
 	BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
 
@@ -365,6 +402,17 @@ int main(int argc, char *argv[])
 					log_level++;
 			}
 			break;
+		case 'r':
+			opts.host = strchr(optarg, ':');
+			if (!opts.host)
+				goto usage;
+			/* port needs to be at least one digit long after ':' */
+			if (strlen(optarg) < strchr(optarg, ':') - optarg + 2)
+				goto usage;
+			opts.port = atoi(strchr(optarg, ':') + 1);
+			optarg[strchr(optarg, ':') - optarg] = 0;
+			opts.host = strdup(optarg);
+			break;			
 		case 'h':
 		default:
 			goto usage;
@@ -441,6 +489,7 @@ usage:
 
 	pr_msg("\nAdditional common parameters:\n");
 	pr_msg("  -D dir         save checkpoint files in specified directory\n");
+	pr_msg("  -r [host:port] write checkpoint to remote host:port\n");
 	pr_msg("  -v [num]       set logging level\n");
 	pr_msg("                 0 - silent (only error messages)\n");
 	pr_msg("                 1 - informative (default)\n");
diff --git a/include/crtools.h b/include/crtools.h
index 795626f..7370461 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -54,6 +54,8 @@ struct cr_options {
 	bool			show_pages_content;
 	bool			restore_detach;
 	unsigned int		namespaces_flags;
+	char			*host;
+	int			port;
 };
 
 /* file descriptors template */
@@ -127,8 +129,8 @@ int cr_show(unsigned long pid, struct cr_options *opts);
 int convert_to_elf(char *elf_path, int fd_core);
 int cr_check(void);
 
-struct cr_fdset *cr_dump_fdset_open(int pid, unsigned long use_mask, struct cr_fdset *);
-struct cr_fdset *cr_show_fdset_open(int pid, unsigned long use_mask);
+struct cr_fdset *cr_dump_fdset_open(int pid, unsigned long use_mask, struct cr_fdset *, struct cr_options *opts);
+struct cr_fdset *cr_show_fdset_open(int pid, unsigned long use_mask, struct cr_options *opts);
 void close_cr_fdset(struct cr_fdset **cr_fdset);
 
 void free_mappings(struct list_head *vma_area_list);
diff --git a/include/namespaces.h b/include/namespaces.h
index 9e0c04f..40dc820 100644
--- a/include/namespaces.h
+++ b/include/namespaces.h
@@ -1,7 +1,9 @@
+#include "crtools.h"
+
 #ifndef __CR_NS_H__
 #define __CR_NS_H__
-int dump_namespaces(int pid, unsigned int ns_flags);
+int dump_namespaces(int pid, struct cr_options *opts);
 int prepare_namespace(int pid, unsigned long clone_flags);
-int try_show_namespaces(int pid);
+int try_show_namespaces(int pid, struct cr_options *opts);
 int switch_ns(int pid, int type, char *ns);
 #endif
diff --git a/namespaces.c b/namespaces.c
index b64f9b0..2c01db9 100644
--- a/namespaces.c
+++ b/namespaces.c
@@ -28,12 +28,12 @@ out:
 	return ret;
 }
 
-static int do_dump_namespaces(int ns_pid, unsigned int ns_flags)
+static int do_dump_namespaces(int ns_pid, unsigned int ns_flags, struct cr_options *opts)
 {
 	struct cr_fdset *fdset;
 	int ret = 0;
 
-	fdset = cr_dump_fdset_open(ns_pid, CR_FD_DESC_NS, NULL);
+	fdset = cr_dump_fdset_open(ns_pid, CR_FD_DESC_NS, NULL, opts);
 	if (fdset == NULL)
 		return -1;
 
@@ -55,10 +55,11 @@ err:
 
 }
 
-int dump_namespaces(int ns_pid, unsigned int ns_flags)
+int dump_namespaces(int ns_pid, struct cr_options *opts)
 {
 	int pid, status;
 	int ret = 0;
+	unsigned int ns_flags = opts->namespaces_flags;
 
 	/*
 	 * The setns syscall is cool, we can switch to the other
@@ -80,7 +81,7 @@ int dump_namespaces(int ns_pid, unsigned int ns_flags)
 	}
 
 	if (pid == 0) {
-		ret = do_dump_namespaces(ns_pid, ns_flags);
+		ret = do_dump_namespaces(ns_pid, ns_flags, opts);
 		exit(ret);
 	}
 
@@ -114,11 +115,11 @@ int prepare_namespace(int pid, unsigned long clone_flags)
 	return ret;
 }
 
-int try_show_namespaces(int ns_pid)
+int try_show_namespaces(int ns_pid, struct cr_options *opts)
 {
 	struct cr_fdset *fdset;
 
-	fdset = cr_show_fdset_open(ns_pid, CR_FD_DESC_NS);
+	fdset = cr_show_fdset_open(ns_pid, CR_FD_DESC_NS, opts);
 	if (!fdset)
 		return -1;
 


More information about the CRIU mailing list