[CRIU] [PATCH 3/8] unix: add ability to set callbacks for external sockets (v4)
Pavel Emelyanov
xemul at parallels.com
Mon Dec 16 03:39:14 PST 2013
On 12/16/2013 03:26 PM, Andrey Vagin wrote:
> 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.
>
> Signed-off-by: Andrey Vagin <avagin at openvz.org>
> ---
> include/criu-plugin.h | 5 ++++
> include/plugin.h | 4 +++
> plugin.c | 62 +++++++++++++++++++++++++++++++++++++++++
> sk-unix.c | 76 +++++++++++++++++++++++++++++++++++----------------
> 4 files changed, 124 insertions(+), 23 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/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 8980efd..93bcc59 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"
> @@ -469,6 +471,22 @@ 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)
> +{
> + struct unix_sk_desc *sk;
> + int ret = -ENOTSUP;
> +
> + list_for_each_entry(sk, &peer->peer_list, peer_node) {
> + ret = cr_plugin_dump_unix_sk(sk->fd, sk->sd.ino);
> + close(sk->fd);
> + if (ret == -ENOTSUP)
> + continue;
> + return ret;
BUG here. Only one socket is dumped.
> + }
> +
> + return ret;
> +}
> +
> int fix_external_unix_sockets(void)
> {
> struct unix_sk_desc *sk;
> @@ -479,23 +497,28 @@ int fix_external_unix_sockets(void)
> UnixSkEntry e = UNIX_SK_ENTRY__INIT;
> FownEntry fown = FOWN_ENTRY__INIT;
> SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
> + int ret;
>
> 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");
> - goto err;
> - }
> + ret = try_to_dump_with_callback(sk);
> + if (ret == -ENOTSUP) {
> + 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");
> + 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;
> + }
> + } else if (ret < 0)
> goto err;
> - }
>
> e.id = fd_id_generate_special();
> e.ino = sk->sd.ino;
> @@ -814,6 +837,25 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
> close(sks[1]);
> sk = sks[0];
> } else {
> + sk = cr_plugin_restore_unix_sk(ui->ue->ino);
Let's optimize this part -- call plugins only for ui->peer->ue->uflags & USK_EXTERN.
> + if (sk >= 0)
> + goto out;
> + if (sk != -ENOTSUP)
> + return -1;
> +
> + /*
> + * 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");
> @@ -831,7 +873,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;
>
> @@ -927,18 +969,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 %) */
>
More information about the CRIU
mailing list