[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