[CRIU] [PATCH 5/9] unix: add ability to set callbacks for external sockets (v5)

Andrey Vagin avagin at openvz.org
Thu Dec 19 09:35:01 PST 2013


We don't know a state behind an external socket. It depends on logic
of the program, which handles this socket.

This patch adds ability to load a library with callbacks for dumping
and restoring external sockets.

This patch introduces two callbacks cr_plugin_dump_unix_sk and
cr_plugin_restore_unix_sk. If a callback can not handle a socket, it
must return -ENOTSUP.

The main questions, what kind of information should be tranfered in
these callbacks. Pls, think a few minutes about that and send me
your opinion.

v2: Use uflags instread of adding a new field
v3: clean up
v4: Unsuitable callbacks return -ENOTSUP.
v5: set USK_CALLBACK, if a socket was dumped by callback.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/criu-plugin.h |  5 +++
 include/image.h       |  1 +
 include/plugin.h      |  4 +++
 plugin.c              | 62 ++++++++++++++++++++++++++++++++
 sk-unix.c             | 98 +++++++++++++++++++++++++++++++++------------------
 5 files changed, 135 insertions(+), 35 deletions(-)

diff --git a/include/criu-plugin.h b/include/criu-plugin.h
index 44abb2a..b022a5f 100644
--- a/include/criu-plugin.h
+++ b/include/criu-plugin.h
@@ -20,7 +20,12 @@
 #ifndef __CRIU_PLUGIN_H__
 #define __CRIU_PLUGIN_H__
 
+#include <limits.h>
+
 typedef int (cr_plugin_init_t)(void);
 typedef void (cr_plugin_fini_t)(void);
 
+typedef int (cr_plugin_dump_unix_sk_t)(int fd, int id);
+typedef int (cr_plugin_restore_unix_sk_t)(int id);
+
 #endif
diff --git a/include/image.h b/include/image.h
index 099f510..32ee0af 100644
--- a/include/image.h
+++ b/include/image.h
@@ -33,6 +33,7 @@
 
 #define USK_EXTERN	(1 << 0)
 #define USK_SERVICE	(1 << 1)
+#define USK_CALLBACK	(1 << 2)
 
 #define VMA_AREA_NONE		(0 <<  0)
 #define VMA_AREA_REGULAR	(1 <<  0)	/* Dumpable area */
diff --git a/include/plugin.h b/include/plugin.h
index 87a38ec..a70dde3 100644
--- a/include/plugin.h
+++ b/include/plugin.h
@@ -7,4 +7,8 @@
 
 void cr_plugin_fini(void);
 int cr_plugin_init(void);
+
+int cr_plugin_dump_unix_sk(int fd, int id);
+int cr_plugin_restore_unix_sk(int id);
+
 #endif
diff --git a/plugin.c b/plugin.c
index 373629a..e65cd3f 100644
--- a/plugin.c
+++ b/plugin.c
@@ -14,6 +14,9 @@
 struct cr_plugin_entry {
 	union {
 		cr_plugin_fini_t *cr_fini;
+
+		cr_plugin_dump_unix_sk_t *cr_plugin_dump_unix_sk;
+		cr_plugin_restore_unix_sk_t *cr_plugin_restore_unix_sk;
 	};
 
 	struct cr_plugin_entry *next;
@@ -21,10 +24,55 @@ struct cr_plugin_entry {
 
 struct cr_plugins {
 	struct cr_plugin_entry *cr_fini;
+
+	struct cr_plugin_entry *cr_plugin_dump_unix_sk;
+	struct cr_plugin_entry *cr_plugin_restore_unix_sk;
 };
 
 struct cr_plugins cr_plugins;
 
+#define add_plugin_func(name)						\
+	do {								\
+		name ## _t *name;					\
+		name = dlsym(h, #name);					\
+		if (name) {						\
+			struct cr_plugin_entry *__ce;			\
+			__ce = xmalloc(sizeof(struct cr_plugin_entry));	\
+			if (__ce == NULL)				\
+				return -1;				\
+			__ce->name = name;				\
+			__ce->next = cr_plugins.name;			\
+			cr_plugins.name = __ce;				\
+		}							\
+	} while (0);							\
+
+
+#define run_plugin_funcs(name, ...) ({					\
+		struct cr_plugin_entry *__ce = cr_plugins.name;		\
+		int __ret = -ENOTSUP;					\
+									\
+		while (__ce) {						\
+			__ret = __ce->name(__VA_ARGS__);		\
+			if (__ret == -ENOTSUP) {			\
+				__ce = __ce->next;			\
+				continue;				\
+			}						\
+			break;						\
+		}							\
+									\
+		__ret;							\
+	})								\
+
+int cr_plugin_dump_unix_sk(int fd, int id)
+{
+	return run_plugin_funcs(cr_plugin_dump_unix_sk, fd, id);
+}
+
+int cr_plugin_restore_unix_sk(int id)
+{
+	return run_plugin_funcs(cr_plugin_restore_unix_sk, id);
+}
+
 static int cr_lib_load(char *path)
 {
 	struct cr_plugin_entry *ce;
@@ -38,6 +86,9 @@ static int cr_lib_load(char *path)
 		return -1;
 	}
 
+	add_plugin_func(cr_plugin_dump_unix_sk);
+	add_plugin_func(cr_plugin_restore_unix_sk);
+
 	ce = NULL;
 	f_fini = dlsym(h, "cr_plugin_fini");
 	if (f_fini) {
@@ -61,10 +112,21 @@ static int cr_lib_load(char *path)
 	return 0;
 }
 
+#define cr_plugin_free(name) do {				\
+	while (cr_plugins.name) {				\
+		ce = cr_plugins.name;				\
+		cr_plugins.name = cr_plugins.name->next;	\
+		xfree(ce);					\
+	}							\
+} while (0)							\
+
 void cr_plugin_fini(void)
 {
 	struct cr_plugin_entry *ce;
 
+	cr_plugin_free(cr_plugin_dump_unix_sk);
+	cr_plugin_free(cr_plugin_restore_unix_sk);
+
 	while (cr_plugins.cr_fini) {
 		ce = cr_plugins.cr_fini;
 		cr_plugins.cr_fini = cr_plugins.cr_fini->next;
diff --git a/sk-unix.c b/sk-unix.c
index 7cc1093..17f3c73 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -7,6 +7,7 @@
 #include <fcntl.h>
 #include <sys/un.h>
 #include <stdlib.h>
+#include <dlfcn.h>
 
 #include "asm/types.h"
 #include "libnetlink.h"
@@ -23,6 +24,7 @@
 #include "sk-queue.h"
 #include "mount.h"
 #include "cr-service.h"
+#include "plugin.h"
 
 #include "protobuf.h"
 #include "protobuf/sk-unix.pb-c.h"
@@ -513,6 +515,42 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
 	return unix_collect_one(m, tb);
 }
 
+static int dump_external_sockets(struct unix_sk_desc *peer)
+{
+	struct unix_sk_desc *sk;
+	int ret;
+
+	while (!list_empty(&peer->peer_list)) {
+		sk = list_first_entry(&peer->peer_list, struct unix_sk_desc, peer_node);
+
+		ret = cr_plugin_dump_unix_sk(sk->fd, sk->sd.ino);
+		if (ret == -ENOTSUP) {
+			if (!opts.ext_unix_sk) {
+				show_one_unix("Runaway socket", peer);
+				pr_err("External socket is used. "
+						"Consider using --" USK_EXT_PARAM " option.\n");
+				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;
+			}
+		} else if (ret < 0)
+			return -1;
+		else
+			sk->ue->uflags |= USK_CALLBACK;
+
+		if (write_unix_entry(sk))
+			return -1;
+		close_safe(&sk->fd);
+		list_del_init(&sk->peer_node);
+	}
+
+	return 0;
+}
+
 int fix_external_unix_sockets(void)
 {
 	struct unix_sk_desc *sk;
@@ -528,19 +566,6 @@ int fix_external_unix_sockets(void)
 
 		BUG_ON(sk->sd.already_dumped);
 
-		if (!opts.ext_unix_sk) {
-			show_one_unix("Runaway socket", sk);
-			pr_err("External socket is used. "
-					"Consider using --" USK_EXT_PARAM " option.\n");
-			goto err;
-		}
-
-		if (sk->type != SOCK_DGRAM) {
-			show_one_unix("Ext stream not supported", sk);
-			pr_err("Can't dump half of stream unix connection.\n");
-			goto err;
-		}
-
 		e.id		= fd_id_generate_special();
 		e.ino		= sk->sd.ino;
 		e.type		= SOCK_DGRAM;
@@ -557,15 +582,8 @@ int fix_external_unix_sockets(void)
 
 		show_one_unix_img("Dumped extern", &e);
 
-		while (!list_empty(&sk->peer_list)) {
-			struct unix_sk_desc *psk;
-			psk = list_first_entry(&sk->peer_list, struct unix_sk_desc, peer_node);
-			close_safe(&psk->fd);
-			list_del_init(&psk->peer_node);
-
-			if (write_unix_entry(psk))
-				goto err;
-		}
+		if (dump_external_sockets(sk))
+			goto err;
 	}
 
 	return 0;
@@ -631,6 +649,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 	if (peer == NULL)
 		return 0;
 
+	if (ui->ue->uflags & USK_CALLBACK)
+		return 0;
+
 	pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
 
 	/* Skip external sockets */
@@ -868,6 +889,25 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
 		close(sks[1]);
 		sk = sks[0];
 	} else {
+		if (ui->ue->uflags & USK_CALLBACK) {
+			sk = cr_plugin_restore_unix_sk(ui->ue->ino);
+			if (sk >= 0)
+				goto out;
+		}
+
+		/*
+		 * Connect to external sockets requires
+		 * special option to be passed.
+		 */
+		if (ui->peer && (ui->peer->ue->uflags & USK_EXTERN) &&
+				!(opts.ext_unix_sk)) {
+			pr_err("External socket found in image. "
+					"Consider using the --" USK_EXT_PARAM
+					"option to allow restoring it.\n");
+			return -1;
+		}
+
+
 		sk = socket(PF_UNIX, ui->ue->type, 0);
 		if (sk < 0) {
 			pr_perror("Can't make unix socket");
@@ -885,7 +925,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
 			return -1;
 		}
 	}
-
+out:
 	if (rst_file_params(sk, ui->ue->fown, ui->ue->flags))
 		return -1;
 
@@ -981,18 +1021,6 @@ int resolve_unix_peers(void)
 			return -1;
 		}
 
-		/*
-		 * Connect to external sockets requires
-		 * special option to be passed.
-		 */
-		if ((peer->ue->uflags & USK_EXTERN) &&
-				!(opts.ext_unix_sk)) {
-			pr_err("External socket found in image. "
-					"Consider using the --" USK_EXT_PARAM " option "
-					"to allow restoring it.\n");
-			return -1;
-		}
-
 		ui->peer = peer;
 		if (ui == peer)
 			/* socket connected to self %) */
-- 
1.8.3.1



More information about the CRIU mailing list