[CRIU] [PATCH 3/4] unix: add ability to set callbacks for external sockets

Andrey Vagin avagin at openvz.org
Sat Nov 30 09:43:55 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_dump_unix_sk and
cr_restore_unix_sk. If a callback can not handle a socket, it
must return CR_SK_SKIP.

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.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/cr-lib.h       | 12 +++++++
 protobuf/sk-unix.proto |  1 +
 sk-unix.c              | 92 ++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/include/cr-lib.h b/include/cr-lib.h
index 75042aa..041ef74 100644
--- a/include/cr-lib.h
+++ b/include/cr-lib.h
@@ -1,6 +1,18 @@
 #ifndef __CR_LIB_H__
 #define __CR_LIB_H__
 
+#include <limits.h>
+
 typedef int (cr_init_t)(void);
 
+#define CR_CB_SKIP INT_MIN
+/*
+ * The callbacks for unix sockets resturn:
+ * - CR_CB_SKIP if this callback is not suitable for this socket
+ * - negative values, if something failed
+ * - zero, if the socket was dumped or restored
+ */
+typedef int (cr_dump_unix_sk_t)(int fd, int ino, int peer_ino);
+typedef int (cr_restore_unix_sk_t)(int ino, char *name, int len);
+
 #endif
diff --git a/protobuf/sk-unix.proto b/protobuf/sk-unix.proto
index bbe2588..9f87baa 100644
--- a/protobuf/sk-unix.proto
+++ b/protobuf/sk-unix.proto
@@ -39,4 +39,5 @@ message unix_sk_entry {
 	optional sk_shutdown		shutdown	= 12;
 
 	optional file_perms_entry	file_perms	= 13;
+	optional bool			need_callback	= 14;
 }
diff --git a/sk-unix.c b/sk-unix.c
index 7e0bea7..e3031c0 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 "cr-lib.h"
 
 #include "protobuf.h"
 #include "protobuf/sk-unix.pb-c.h"
@@ -468,6 +470,45 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
 	return unix_collect_one(m, tb);
 }
 
+static int try_to_dump_with_callback(struct unix_sk_desc *peer, bool *need_callback)
+{
+	struct unix_sk_desc *sk;
+	struct cr_lib *l;
+	int ret;
+
+	*need_callback = false;
+
+	list_for_each_entry(l, &opts.libs, node) {
+		cr_dump_unix_sk_t *f_dump;
+
+		f_dump = dlsym(l->handle, "cr_dump_unix_sk");
+		if (f_dump == NULL)
+			continue;
+
+		list_for_each_entry(sk, &peer->peer_list, peer_node) {
+			ret = f_dump(sk->fd, sk->sd.ino, sk->peer_ino);
+			if (ret < 0 && ret != CR_CB_SKIP)
+				return -1;
+
+			if (ret == 0) {
+				*need_callback = true;
+				continue;
+			}
+
+			if (!*need_callback)
+				continue;
+
+			pr_err("The callback is not suitable for all peer sockets\n");
+			return -1;
+		}
+
+		if (*need_callback)
+			break;
+	}
+
+	return 0;
+}
+
 int fix_external_unix_sockets(void)
 {
 	struct unix_sk_desc *sk;
@@ -478,22 +519,28 @@ int fix_external_unix_sockets(void)
 		UnixSkEntry e = UNIX_SK_ENTRY__INIT;
 		FownEntry fown = FOWN_ENTRY__INIT;
 		SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
+		bool need_callback;
 
 		show_one_unix("Dumping extern", sk);
 
 		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");
+		if (try_to_dump_with_callback(sk, &need_callback))
 			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;
+		if (!need_callback) {
+			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();
@@ -506,6 +553,8 @@ int fix_external_unix_sockets(void)
 		e.peer		= 0;
 		e.fown		= &fown;
 		e.opts		= &skopts;
+		e.has_need_callback = true;
+		e.need_callback = need_callback;
 
 		if (pb_write_one(fdset_fd(glob_fdset, CR_FD_UNIXSK), &e, PB_UNIX_SK))
 			goto err;
@@ -575,6 +624,8 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 
 	if (peer == NULL)
 		return 0;
+	if (peer->ue->need_callback)
+		return 0;
 
 	pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
 
@@ -780,6 +831,27 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
 
 		close(sks[1]);
 		sk = sks[0];
+	} else if (ui->peer && ui->peer->ue->need_callback) {
+		struct cr_lib *l;
+
+		sk = -1;
+		list_for_each_entry(l, &opts.libs, node) {
+			cr_restore_unix_sk_t *f_restore;
+
+			f_restore = dlsym(l->handle, "cr_restore_unix_sk");
+			if (f_restore == NULL)
+				continue;
+
+			sk = f_restore(ui->ue->ino, ui->name, ui->ue->name.len);
+			if (sk == CR_CB_SKIP)
+				continue;
+			if (sk < 0)
+				return -1;
+		}
+		if (sk == -1)
+			return -1;
+
+		goto out;
 	} else if ((ui->ue->state == TCP_ESTABLISHED) && !ui->ue->peer) {
 		int ret, sks[2];
 
@@ -830,7 +902,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;
 
-- 
1.8.3.1



More information about the CRIU mailing list