[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