[CRIU] [PATCH 1/3] Add dumping of unnamed unix sockets.

Artem Kuzmitskiy artem.kuzmitskiy at gmail.com
Wed Jul 29 04:05:50 PDT 2015


* Added functionality for dumping unnamed unix sockets.
  When we call CRIU with dump option, for unnamed socket we
  should pass it inode into --ext-unix-sk. Details about this problem
  described in http://criu.org/External_UNIX_socket#What_to_do_with_socketpair.28.29-s.3F.
  Usage example:
    criu dump -D images -o dump.log -v4 --ext-unix-sk=4529709 -t 13506

* fix typo error in log output

Signed-off-by: Artem Kuzmitskiy <artem.kuzmitskiy at lge.com>
---
 cr-service.c         |  8 ++++-
 crtools.c            |  9 ++++--
 files.c              |  2 +-
 include/cr_options.h |  1 +
 include/sockets.h    |  3 ++
 lib/criu.c           | 47 +++++++++++++++++++++++++++
 lib/criu.h           |  4 +--
 protobuf/rpc.proto   |  6 ++++
 sk-unix.c            | 91 ++++++++++++++++++++++++++++++++++++++++++++++------
 9 files changed, 154 insertions(+), 17 deletions(-)

diff --git a/cr-service.c b/cr-service.c
index 9c40989..105787e 100644
--- a/cr-service.c
+++ b/cr-service.c
@@ -30,6 +30,7 @@
 #include "cgroup.h"
 #include "action-scripts.h"
 #include "security.h"
+#include "sockets.h"

 #include "setproctitle.h"

@@ -285,8 +286,13 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		req->pid = ids.pid;
 	}

-	if (req->has_ext_unix_sk)
+	if (req->has_ext_unix_sk) {
 		opts.ext_unix_sk = req->ext_unix_sk;
+		for (i = 0; i < req->n_unix_sk_ino; i++) {
+			if (unix_sk_id_add(req->unix_sk_ino[i]->inode) < 0)
+				goto err;
+		}
+	}

 	if (req->root)
 		opts.root = req->root;
diff --git a/crtools.c b/crtools.c
index b085d33..6af6080 100644
--- a/crtools.c
+++ b/crtools.c
@@ -50,6 +50,7 @@ void init_opts(void)

 	/* Default options */
 	opts.final_state = TASK_DEAD;
+	INIT_LIST_HEAD(&opts.ext_unixsk_ids);
 	INIT_LIST_HEAD(&opts.veth_pairs);
 	INIT_LIST_HEAD(&opts.scripts);
 	INIT_LIST_HEAD(&opts.ext_mounts);
@@ -184,7 +185,7 @@ int main(int argc, char *argv[], char *envp[])
 	int log_level = LOG_UNSET;
 	char *imgs_dir = ".";
 	char *work_dir = NULL;
-	static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::xVr:jlW:L:M:";
+	static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jlW:L:M:";
 	static struct option long_opts[] = {
 		{ "tree",			required_argument,	0, 't'	},
 		{ "pid",			required_argument,	0, 'p'	},
@@ -201,7 +202,7 @@ int main(int argc, char *argv[], char *envp[])
 		{ "log-file",			required_argument,	0, 'o'	},
 		{ "namespaces",			required_argument,	0, 'n'	},
 		{ "root",			required_argument,	0, 'r'	},
-		{ USK_EXT_PARAM,		no_argument,		0, 'x'	},
+		{ USK_EXT_PARAM,		optional_argument,	0, 'x'	},
 		{ "help",			no_argument,		0, 'h'	},
 		{ SK_EST_PARAM,			no_argument,		0, 1042	},
 		{ "close",			required_argument,	0, 1043	},
@@ -278,6 +279,8 @@ int main(int argc, char *argv[], char *envp[])
 			opts.final_state = TASK_ALIVE;
 			break;
 		case 'x':
+			if (optarg && unix_sk_ids_parse(optarg) < 0)
+				return 1;
 			opts.ext_unix_sk = true;
 			break;
 		case 'p':
@@ -675,7 +678,7 @@ usage:
 "                        restore making it the parent of the restored process\n"
 "\n"
 "* Special resources support:\n"
-"  -x|--" USK_EXT_PARAM "      allow external unix connections\n"
+"  -x|--" USK_EXT_PARAM "inode,.." "      allow external unix connections (optionally can be assign socket's inode that allows one-sided dump)\n"
 "     --" SK_EST_PARAM "  checkpoint/restore established TCP connections\n"
 "  -r|--root PATH        change the root filesystem (when run in mount namespace)\n"
 "  --evasive-devices     use any path to a device file if the original one\n"
diff --git a/files.c b/files.c
index 071fa69..c82920d 100644
--- a/files.c
+++ b/files.c
@@ -1424,7 +1424,7 @@ bool inherited_fd(struct file_desc *d, int *fd_p)
 	if (*fd_p < 0)
 		pr_perror("Inherit fd DUP failed");
 	else
-		pr_info("File %s will be restored from fd %d duped "
+		pr_info("File %s will be restored from fd %d dumped "
 				"from inherit fd %d\n", id_str, *fd_p, i_fd);
 	return true;
 }
diff --git a/include/cr_options.h b/include/cr_options.h
index bf57ef9..19c2f77 100644
--- a/include/cr_options.h
+++ b/include/cr_options.h
@@ -45,6 +45,7 @@ struct cr_options {
 	};
 	bool			restore_sibling;
 	bool			ext_unix_sk;
+	struct list_head        ext_unixsk_ids;
 	bool			shell_job;
 	bool			handle_file_locks;
 	bool			tcp_established_ok;
diff --git a/include/sockets.h b/include/sockets.h
index a3010e1..39c22fd 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -60,6 +60,9 @@ extern int inet_collect_one(struct nlmsghdr *h, int family, int type);
 extern int unix_receive_one(struct nlmsghdr *h, void *);
 extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg);

+extern int unix_sk_id_add(ino_t ino);
+extern int unix_sk_ids_parse(char *optarg);
+
 extern int do_dump_opt(int sk, int level, int name, void *val, int len);
 #define dump_opt(s, l, n, f)	do_dump_opt(s, l, n, f, sizeof(*f))
 extern int do_restore_opt(int sk, int level, int name, void *val, int len);
diff --git a/lib/criu.c b/lib/criu.c
index be848bb..95bc2f6 100644
--- a/lib/criu.c
+++ b/lib/criu.c
@@ -225,6 +225,53 @@ void criu_set_ext_unix_sk(bool ext_unix_sk)
 	criu_local_set_ext_unix_sk(global_opts, ext_unix_sk);
 }

+int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode)
+{
+	int nr;
+	UnixSk **a, *u;
+
+	/*if caller forgot enable ext_unix_sk option we do it*/
+	if (!opts->rpc->has_ext_unix_sk) {
+		criu_local_set_ext_unix_sk(opts, true);
+	}
+
+	/*if user disabled ext_unix_sk and try to add unixsk inode after that*/
+	if (opts->rpc->has_ext_unix_sk && !opts->rpc->ext_unix_sk) {
+		if (opts->rpc->n_unix_sk_ino > 0) {
+			free(opts->rpc->unix_sk_ino);
+			opts->rpc->n_unix_sk_ino = 0;
+		}
+		return -1;
+	}
+
+	u = malloc(sizeof(*u));
+	if (!u)
+		goto er;
+	unix_sk__init(u);
+
+	u->inode = inode;
+
+	nr = opts->rpc->n_unix_sk_ino + 1;
+	a = realloc(opts->rpc->unix_sk_ino, nr * sizeof(u));
+	if (!a)
+		goto er_u;
+
+	a[nr - 1] = u;
+	opts->rpc->unix_sk_ino = a;
+	opts->rpc->n_unix_sk_ino = nr;
+	return 0;
+
+er_u:
+	free(u);
+er:
+	return -ENOMEM;
+}
+
+int criu_add_unix_sk(unsigned int inode)
+{
+	return criu_local_add_unix_sk(global_opts, inode);
+}
+
 void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established)
 {
 	opts->rpc->has_tcp_established	= true;
diff --git a/lib/criu.h b/lib/criu.h
index 30d0b4a..85f7788 100644
--- a/lib/criu.h
+++ b/lib/criu.h
@@ -51,6 +51,7 @@ void criu_set_parent_images(char *path);
 void criu_set_work_dir_fd(int fd);
 void criu_set_leave_running(bool leave_running);
 void criu_set_ext_unix_sk(bool ext_unix_sk);
+int criu_add_unix_sk(unsigned int inode);
 void criu_set_tcp_established(bool tcp_established);
 void criu_set_evasive_devices(bool evasive_devices);
 void criu_set_shell_job(bool shell_job);
@@ -74,8 +75,6 @@ int criu_add_cg_root(char *ctrl, char *path);
 int criu_add_enable_fs(char *fs);
 int criu_add_skip_mnt(char *mnt);

-
-
 /*
  * The criu_notify_arg_t na argument is an opaque
  * value that callbacks (cb-s) should pass into
@@ -160,6 +159,7 @@ void criu_local_set_parent_images(criu_opts *opts, char *path);
 void criu_local_set_work_dir_fd(criu_opts *opts, int fd);
 void criu_local_set_leave_running(criu_opts *opts, bool leave_running);
 void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk);
+int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode);
 void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established);
 void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices);
 void criu_local_set_shell_job(criu_opts *opts, bool shell_job);
diff --git a/protobuf/rpc.proto b/protobuf/rpc.proto
index c1969c6..2f4d0c0 100644
--- a/protobuf/rpc.proto
+++ b/protobuf/rpc.proto
@@ -25,6 +25,10 @@ message cgroup_root {
 	required string		path	= 2;
 };

+message unix_sk {
+	required uint32		inode 	= 1;
+};
+
 message criu_opts {
 	required int32			images_dir_fd	= 1;
 	optional int32			pid		= 2; /* if not set on dump, will dump requesting process */
@@ -68,6 +72,8 @@ message criu_opts {

 	repeated string			skip_mnt	= 31;
 	repeated string			enable_fs	= 32;
+
+	repeated unix_sk                unix_sk_ino     = 33;
 }

 message criu_dump_resp {
diff --git a/sk-unix.c b/sk-unix.c
index d17cc8e..ed8f319 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -68,6 +68,11 @@ struct unix_sk_listen_icon {
 	struct unix_sk_listen_icon	*next;
 };

+struct  unix_sk_exception {
+	struct list_head unix_sk_list;
+	ino_t unix_sk_ino;
+};
+
 #define SK_HASH_SIZE		32

 static struct unix_sk_listen_icon *unix_listen_icons[SK_HASH_SIZE];
@@ -132,6 +137,23 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk)
 	return 1;
 }

+static bool unix_sk_exception_lookup_id(ino_t ino)
+{
+	bool ret = false;
+	struct unix_sk_exception *sk;
+
+	list_for_each_entry(sk, &opts.ext_unixsk_ids, unix_sk_list) {
+		if (sk->unix_sk_ino == ino) {
+			pr_debug("Found ino %u in exception unix sk list\n", (unsigned int)ino);
+			ret = true;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+
 static int write_unix_entry(struct unix_sk_desc *sk)
 {
 	int ret;
@@ -572,16 +594,21 @@ static int dump_external_sockets(struct unix_sk_desc *peer)
 				return -1;
 			}

-			if (peer->type != SOCK_DGRAM) {
-				show_one_unix("Ext stream not supported", peer);
-				pr_err("Can't dump half of stream unix connection.\n");
-				return -1;
-			}
-
-			if (!peer->name) {
-				show_one_unix("Ext dgram w/o name", peer);
-				pr_err("Can't dump name-less external socket.\n");
-				return -1;
+			if (unix_sk_exception_lookup_id(sk->sd.ino)) {
+				pr_debug("found exception for unix name-less external socket.\n");
+			} else {
+				if (peer->type != SOCK_DGRAM) {
+					show_one_unix("Ext stream not supported", peer);
+					pr_err("Can't dump half of stream unix connection.\n");
+					return -1;
+				}
+
+				if (!peer->name) {
+					show_one_unix("Ext dgram w/o name", peer);
+					pr_err("Can't dump name-less external socket.\n");
+					pr_err("%d\n", sk->fd);
+					return -1;
+				}
 			}
 		} else if (ret < 0)
 			return -1;
@@ -1128,3 +1155,47 @@ int resolve_unix_peers(void)
 	return 0;
 }

+int unix_sk_id_add(ino_t ino)
+{
+	struct unix_sk_exception *unix_sk;
+
+	/* TODO: validate inode here? */
+
+	unix_sk = xmalloc(sizeof *unix_sk);
+	if (unix_sk == NULL)
+		return -1;
+	unix_sk->unix_sk_ino = ino;
+	list_add_tail(&unix_sk->unix_sk_list, &opts.ext_unixsk_ids);
+
+	return 0;
+}
+
+int unix_sk_ids_parse(char *optarg)
+{
+	/*
+	 * parsing option of the following form: --ext-unix-sk=<inode value>,<inode
+	 * value>... or short form -x<inode>,<inode>...
+	 */
+
+	char *iter = optarg;
+
+	while (*iter != '\0') {
+		if (*iter == ',')
+			iter++;
+		else {
+			ino_t ino = (ino_t)strtoul(iter, &iter, 10);
+
+			if (0 == ino) {
+				pr_err("Can't parse unix socket inode from optarg: %s\n", optarg);
+				return -1;
+			}
+			if (unix_sk_id_add(ino) < 0) {
+				pr_err("Can't add unix socket inode in list: %s\n", optarg);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
--
2.4.6



More information about the CRIU mailing list