[CRIU] [PATCH 2/2] plugin: Rework plugins API, v2

Andrew Vagin avagin at parallels.com
Thu Aug 14 01:42:22 PDT 2014


On Wed, Aug 13, 2014 at 11:52:24PM +0400, Cyrill Gorcunov wrote:
> On Thu, Aug 07, 2014 at 11:40:29PM +0400, Cyrill Gorcunov wrote:
> > 
> > Here we define new api to be used in plugins.
> 
> There were a small nit, so updated variant attached.

> From 936627ec8a04456ea3502bd760d6a05fa7833ac8 Mon Sep 17 00:00:00 2001
> From: Cyrill Gorcunov <gorcunov at openvz.org>
> Date: Thu, 27 Feb 2014 20:58:23 +0400
> Subject: [PATCH 1/2] plugin: Rework plugins API, v2
> 
> Here we define new api to be used in plugins.
> 
>  - Plugin should provide a descriptor with help of
>    CR_PLUGIN_REGISTER macro, or in case if plugin require
>    no init/exit functions -- with CR_PLUGIN_REGISTER_DUMMY.
> 
>  - Plugin should define a plugin hook with help of
>    CR_PLUGIN_REGISTER_HOOK macro.
> 
>  - Now init/exit functions of plugins takes @stage
>    argument which tells plugin which stage of criu
>    it's been called on dump/restore. For exit it
>    also takes @ret which allows plugin to know if
>    something went wrong and it needs to cleanup
>    own resources.
> 
> The idea behind is to not limit plugins authors with names
> of functions they might need to use for particular hook.
> 
> Such new API deprecates olds plugins structure but to keep
> backward compatibility we will provide a tiny layer of
> additional code to support old plugins for at least a couple
> of release cycles.
> 
> For example a trivial plugin might look like
> 
>  | #include <sys/types.h>
>  | #include <sys/stat.h>
>  | #include <fcntl.h>
>  | #include <libgen.h>
>  | #include <errno.h>
>  |
>  | #include <sys/socket.h>
>  | #include <linux/un.h>
>  |
>  | #include <stdio.h>
>  | #include <stdlib.h>
>  | #include <string.h>
>  | #include <unistd.h>
>  |
>  | #include "criu-plugin.h"
>  | #include "criu-log.h"
>  |
>  | static int dump_ext_file(int fd, int id)
>  | {
>  |	pr_info("dump_ext_file: fd %d id %d\n", fd, id);
>  |	return 0;
>  | }
>  |
>  | CR_PLUGIN_REGISTER_DUMMY("trivial")
>  | CR_PLUGIN_REGISTER_HOOK(CR_PLUGIN_HOOK__DUMP_EXT_FILE, dump_ext_file)
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
Acked-by: Andrew Vagin <avagin at openvz.org>

> ---
>  cr-dump.c             |   4 +-
>  cr-restore.c          |   4 +-
>  files-ext.c           |   4 +-
>  include/criu-plugin.h | 102 +++++++++++++++++--
>  include/plugin.h      |  50 +++++++---
>  mount.c               |   4 +-
>  net.c                 |   2 +-
>  plugin.c              | 271 +++++++++++++++++++++++++-------------------------
>  sk-unix.c             |   4 +-
>  9 files changed, 279 insertions(+), 166 deletions(-)
> 
> diff --git a/cr-dump.c b/cr-dump.c
> index 1700d9dc071f..75f634a25a5a 100644
> --- a/cr-dump.c
> +++ b/cr-dump.c
> @@ -1761,7 +1761,7 @@ int cr_dump_tasks(pid_t pid)
>  	if (init_stats(DUMP_STATS))
>  		goto err;
>  
> -	if (cr_plugin_init())
> +	if (cr_plugin_init(CR_PLUGIN_STAGE__DUMP))
>  		goto err;
>  
>  	if (kerndat_init())
> @@ -1858,7 +1858,7 @@ err:
>  
>  	close_cr_fdset(&glob_fdset);
>  
> -	cr_plugin_fini();
> +	cr_plugin_fini(CR_PLUGIN_STAGE__DUMP, ret);
>  
>  	if (!ret) {
>  		/*
> diff --git a/cr-restore.c b/cr-restore.c
> index 2bc98e83fedd..c38526673d27 100644
> --- a/cr-restore.c
> +++ b/cr-restore.c
> @@ -1723,7 +1723,7 @@ int cr_restore_tasks(void)
>  {
>  	int ret = -1;
>  
> -	if (cr_plugin_init())
> +	if (cr_plugin_init(CR_PLUGIN_STAGE__RESTORE))
>  		return -1;
>  
>  	if (check_img_inventory() < 0)
> @@ -1762,7 +1762,7 @@ int cr_restore_tasks(void)
>  
>  	fini_cgroup();
>  err:
> -	cr_plugin_fini();
> +	cr_plugin_fini(CR_PLUGIN_STAGE__RESTORE, ret);
>  	return ret;
>  }
>  
> diff --git a/files-ext.c b/files-ext.c
> index d9640c49ccb2..a5ca5945d4ac 100644
> --- a/files-ext.c
> +++ b/files-ext.c
> @@ -15,7 +15,7 @@ static int dump_one_ext_file(int lfd, u32 id, const struct fd_parms *p)
>  
>  	ExtFileEntry xfe = EXT_FILE_ENTRY__INIT;
>  
> -	ret = cr_plugin_dump_file(lfd, id);
> +	ret = run_plugins(DUMP_EXT_FILE, lfd, id);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -44,7 +44,7 @@ static int open_fd(struct file_desc *d)
>  
>  	xfi = container_of(d, struct ext_file_info, d);
>  
> -	fd = cr_plugin_restore_file(xfi->xfe->id);
> +	fd = run_plugins(RESTORE_EXT_FILE, xfi->xfe->id);
>  	if (fd < 0) {
>  		pr_err("Unable to restore %#x\n", xfi->xfe->id);
>  		return -1;
> diff --git a/include/criu-plugin.h b/include/criu-plugin.h
> index cda8c8eb98e6..3f76b8fe6e54 100644
> --- a/include/criu-plugin.h
> +++ b/include/criu-plugin.h
> @@ -23,21 +23,109 @@
>  #include <limits.h>
>  #include <stdbool.h>
>  
> +#define CRIU_PLUGIN_GEN_VERSION(a,b,c)	(((a) << 16) + ((b) << 8) + (c))
> +#define CRIU_PLUGIN_VERSION_MAJOR	0
> +#define CRIU_PLUGIN_VERSION_MINOR	2
> +#define CRIU_PLUGIN_VERSION_SUBLEVEL	0
> +
> +#define CRIU_PLUGIN_VERSION_OLD		CRIU_PLUGIN_GEN_VERSION(0,1,0)
> +
> +#define CRIU_PLUGIN_VERSION					\
> +	CRIU_PLUGIN_GEN_VERSION(CRIU_PLUGIN_VERSION_MAJOR,	\
> +				CRIU_PLUGIN_VERSION_MINOR,	\
> +				CRIU_PLUGIN_VERSION_SUBLEVEL)
> +
> +/*
> + * Plugin hook points and their arguments in hooks.
> + */
> +enum {
> +	CR_PLUGIN_HOOK__DUMP_UNIX_SK,
> +	CR_PLUGIN_HOOK__RESTORE_UNIX_SK,
> +
> +	CR_PLUGIN_HOOK__DUMP_EXT_FILE,
> +	CR_PLUGIN_HOOK__RESTORE_EXT_FILE,
> +
> +	CR_PLUGIN_HOOK__DUMP_EXT_MOUNT,
> +	CR_PLUGIN_HOOK__RESTORE_EXT_MOUNT,
> +
> +	CR_PLUGIN_HOOK__DUMP_EXT_LINK,
> +
> +	CR_PLUGIN_HOOK__MAX
> +};
> +
> +#define DECLARE_PLUGIN_HOOK_ARGS(__hook, ...)	\
> +	typedef int (__hook ##_t)(__VA_ARGS__)
> +
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_UNIX_SK, int fd, int id);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__RESTORE_UNIX_SK, int id);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_EXT_FILE, int fd, int id);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__RESTORE_EXT_FILE, int id);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_EXT_MOUNT, char *mountpoint, int id);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__RESTORE_EXT_MOUNT, int id, char *mountpoint, char *old_root, int *is_file);
> +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_EXT_LINK, int index, int type, char *kind);
> +
> +enum {
> +	CR_PLUGIN_STAGE__DUMP,
> +	CR_PLUGIN_STAGE__RESTORE,
> +
> +	CR_PLUGIN_STAGE_MAX
> +};
> +
> +/*
> + * Plugin descriptor.
> + */
> +typedef struct {
> +	const char		*name;
> +	int			(*init)(int stage);
> +	void			(*exit)(int stage, int ret);
> +	unsigned int		version;
> +	unsigned int		max_hooks;
> +	void			*hooks[CR_PLUGIN_HOOK__MAX];
> +} cr_plugin_desc_t;
> +
> +extern cr_plugin_desc_t CR_PLUGIN_DESC;
> +
> +#define CR_PLUGIN_REGISTER(___name, ___init, ___exit)					\
> +	cr_plugin_desc_t CR_PLUGIN_DESC = {						\
> +		.name		= ___name,						\
> +		.init		= ___init,						\
> +		.exit		= ___exit,						\
> +		.version	= CRIU_PLUGIN_VERSION,					\
> +		.max_hooks	= CR_PLUGIN_HOOK__MAX,					\
> +	};
> +
> +static inline int cr_plugin_dummy_init(int stage) { return 0; }
> +static inline void cr_plugin_dummy_exit(int stage, int ret) { }
> +
> +#define CR_PLUGIN_REGISTER_DUMMY(___name)						\
> +	cr_plugin_desc_t CR_PLUGIN_DESC = {						\
> +		.name		= ___name,						\
> +		.init		= cr_plugin_dummy_init,					\
> +		.exit		= cr_plugin_dummy_exit,					\
> +		.version	= CRIU_PLUGIN_VERSION,					\
> +		.max_hooks	= CR_PLUGIN_HOOK__MAX,					\
> +	};
> +
> +#define CR_PLUGIN_REGISTER_HOOK(__hook, __func)						\
> +static void __attribute__((constructor)) cr_plugin_register_hook_##__func (void)	\
> +{											\
> +	CR_PLUGIN_DESC.hooks[__hook] = (void *)__func;					\
> +}
> +
> +/* Public API */
> +extern int criu_get_image_dir(void);
> +
> +/*
> + * Deprecated, will be removed in next version.
> + */
>  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);
> -
>  typedef int (cr_plugin_dump_file_t)(int fd, int id);
>  typedef int (cr_plugin_restore_file_t)(int id);
> -
>  typedef int (cr_plugin_dump_ext_mount_t)(char *mountpoint, int id);
>  typedef int (cr_plugin_restore_ext_mount_t)(int id, char *mountpoint, char *old_root, int *is_file);
> -
>  typedef int (cr_plugin_dump_ext_link_t)(int index, int type, char *kind);
>  
> -/* Public API */
> -extern int criu_get_image_dir(void);
> -
>  #endif /* __CRIU_PLUGIN_H__ */
> diff --git a/include/plugin.h b/include/plugin.h
> index 3c53e3003de3..2855836206d9 100644
> --- a/include/plugin.h
> +++ b/include/plugin.h
> @@ -2,21 +2,45 @@
>  #define __CR_PLUGIN_H__
>  
>  #include "criu-plugin.h"
> +#include "compiler.h"
> +#include "list.h"
>  
>  #define CR_PLUGIN_DEFAULT "/var/lib/criu/"
>  
> -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);
> -
> -int cr_plugin_dump_file(int fd, int id);
> -int cr_plugin_restore_file(int id);
> -
> -int cr_plugin_dump_ext_mount(char *mountpoint, int id);
> -int cr_plugin_restore_ext_mount(int id, char *mountpoint, char *old_root, int *is_file);
> -
> -int cr_plugin_dump_ext_link(int index, int type, char *kind);
> +void cr_plugin_fini(int stage, int err);
> +int cr_plugin_init(int stage);
> +
> +typedef struct {
> +	struct list_head	head;
> +	struct list_head	hook_chain[CR_PLUGIN_HOOK__MAX];
> +} cr_plugin_ctl_t;
> +
> +extern cr_plugin_ctl_t cr_plugin_ctl;
> +
> +typedef struct {
> +	cr_plugin_desc_t	*d;
> +	struct list_head	list;
> +	void			*dlhandle;
> +	struct list_head	link[CR_PLUGIN_HOOK__MAX];
> +} plugin_desc_t;
> +
> +#define run_plugins(__hook, ...)								\
> +({												\
> +	plugin_desc_t *this;									\
> +	int __ret = -ENOTSUP;									\
> +												\
> +	list_for_each_entry(this, &cr_plugin_ctl.hook_chain[CR_PLUGIN_HOOK__ ##__hook],		\
> +			    link[CR_PLUGIN_HOOK__ ##__hook]) {					\
> +		pr_debug("plugin: `%s' hook %u -> %p\n",					\
> +			 this->d->name, CR_PLUGIN_HOOK__ ##__hook,				\
> +			 this->d->hooks[CR_PLUGIN_HOOK__ ##__hook]);				\
> +		__ret = ((CR_PLUGIN_HOOK__ ##__hook ##_t *)					\
> +			 this->d->hooks[CR_PLUGIN_HOOK__ ##__hook])(__VA_ARGS__);		\
> +		if (__ret == -ENOTSUP)								\
> +			continue;								\
> +		break;										\
> +	}											\
> +	__ret;											\
> +})
>  
>  #endif
> diff --git a/mount.c b/mount.c
> index 9a147abe4ddd..81f358399c90 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -425,7 +425,7 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
>  				int ret;
>  
>  				if (for_dump) {
> -					ret = cr_plugin_dump_ext_mount(m->mountpoint + 1, m->mnt_id);
> +					ret = run_plugins(DUMP_EXT_MOUNT, m->mountpoint, m->mnt_id);
>  					if (ret == 0)
>  						m->need_plugin = true;
>  					else if (ret == -ENOTSUP)
> @@ -1297,7 +1297,7 @@ static int restore_ext_mount(struct mount_info *mi)
>  	int ret;
>  
>  	pr_debug("Restoring external bind mount %s\n", mi->mountpoint);
> -	ret = cr_plugin_restore_ext_mount(mi->mnt_id, mi->mountpoint, "/", NULL);
> +	ret = run_plugins(RESTORE_EXT_MOUNT, mi->mnt_id, mi->mountpoint, "/", NULL);
>  	if (ret)
>  		pr_perror("Can't restore ext mount (%d)\n", ret);
>  	return ret;
> diff --git a/net.c b/net.c
> index 206736ad764b..177b7592f6a4 100644
> --- a/net.c
> +++ b/net.c
> @@ -106,7 +106,7 @@ static int dump_unknown_device(struct ifinfomsg *ifi, char *kind,
>  {
>  	int ret;
>  
> -	ret = cr_plugin_dump_ext_link(ifi->ifi_index, ifi->ifi_type, kind);
> +	ret = run_plugins(DUMP_EXT_LINK, ifi->ifi_index, ifi->ifi_type, kind);
>  	if (ret == 0)
>  		return dump_one_netdev(ND_TYPE__EXTLINK, ifi, tb, fds, NULL);
>  
> diff --git a/plugin.c b/plugin.c
> index 367f9fda39eb..c4584657f2e0 100644
> --- a/plugin.c
> +++ b/plugin.c
> @@ -1,117 +1,97 @@
> +#include <unistd.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <dirent.h>
> -#include <errno.h>
>  #include <stdio.h>
> +#include <errno.h>
>  #include <dlfcn.h>
> -#include <unistd.h>
>  
>  #include "cr_options.h"
> +#include "compiler.h"
> +#include "xmalloc.h"
>  #include "plugin.h"
> +#include "list.h"
>  #include "log.h"
> -#include "xmalloc.h"
>  
> -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;
> -		cr_plugin_dump_file_t		*cr_plugin_dump_file;
> -		cr_plugin_restore_file_t	*cr_plugin_restore_file;
> -		cr_plugin_dump_ext_mount_t	*cr_plugin_dump_ext_mount;
> -		cr_plugin_restore_ext_mount_t	*cr_plugin_restore_ext_mount;
> -		cr_plugin_dump_ext_link_t	*cr_plugin_dump_ext_link;
> -	};
> -
> -	struct cr_plugin_entry *next;
> -};
> -
> -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_plugin_entry *cr_plugin_dump_file;
> -	struct cr_plugin_entry *cr_plugin_restore_file;
> -	struct cr_plugin_entry *cr_plugin_dump_ext_mount;
> -	struct cr_plugin_entry *cr_plugin_restore_ext_mount;
> -	struct cr_plugin_entry *cr_plugin_dump_ext_link;
> -};
> -
> -struct cr_plugins cr_plugins;
> -
> -#define add_plugin_func(name)						\
> +cr_plugin_ctl_t cr_plugin_ctl;
> +
> +/*
> + * If we met old version of a plugin, selfgenerate a plugin descriptor for it.
> + */
> +static cr_plugin_desc_t *cr_gen_plugin_desc(void *h, char *path)
> +{
> +	cr_plugin_desc_t *d;
> +
> +	d = xzalloc(sizeof(*d));
> +	if (!d)
> +		return NULL;
> +
> +	d->name		= strdup(path);
> +	d->max_hooks	= CR_PLUGIN_HOOK__MAX;
> +	d->version	= CRIU_PLUGIN_VERSION_OLD;
> +
> +	pr_warn("Generating dynamic descriptor for plugin `%s'."
> +		"Won't work in next version of the program."
> +		"Please update your plugin.\n", path);
> +
> +#define __assign_hook(__hook, __name)					\
>  	do {								\
> -		name ## _t *name;					\
> -		name = dlsym(h, #name);					\
> -		if (name) {						\
> -			struct cr_plugin_entry *__ce;			\
> -			__ce = xmalloc(sizeof(*__ce));			\
> -			if (__ce == NULL)				\
> -				goto nomem;				\
> -			__ce->name = name;				\
> -			__ce->next = cr_plugins.name;			\
> -			cr_plugins.name = __ce;				\
> -		}							\
> +		void *name;						\
> +		name = dlsym(h, __name);				\
> +		if (name)						\
> +			d->hooks[CR_PLUGIN_HOOK__ ##__hook] = name;	\
>  	} 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);
> -}
> +	__assign_hook(DUMP_UNIX_SK,		"cr_plugin_dump_unix_sk");
> +	__assign_hook(RESTORE_UNIX_SK,		"cr_plugin_restore_unix_sk");
> +	__assign_hook(DUMP_EXT_FILE,		"cr_plugin_dump_file");
> +	__assign_hook(RESTORE_EXT_FILE,		"cr_plugin_restore_file");
> +	__assign_hook(DUMP_EXT_MOUNT,		"cr_plugin_dump_ext_mount");
> +	__assign_hook(RESTORE_EXT_MOUNT,	"cr_plugin_restore_ext_mount");
> +	__assign_hook(DUMP_EXT_LINK,		"cr_plugin_dump_ext_link");
>  
> -int cr_plugin_restore_unix_sk(int id)
> -{
> -	return run_plugin_funcs(cr_plugin_restore_unix_sk, id);
> -}
> +#undef __assign_hook
>  
> -int cr_plugin_dump_file(int fd, int id)
> -{
> -	return run_plugin_funcs(cr_plugin_dump_file, fd, id);
> -}
> +	d->init = dlsym(h, "cr_plugin_init");
> +	d->exit = dlsym(h, "cr_plugin_fini");
>  
> -int cr_plugin_restore_file(int id)
> -{
> -	return run_plugin_funcs(cr_plugin_restore_file, id);
> +	return d;
>  }
>  
> -int cr_plugin_dump_ext_mount(char *mountpoint, int id)
> +static void show_plugin_desc(cr_plugin_desc_t *d)
>  {
> -	return run_plugin_funcs(cr_plugin_dump_ext_mount, mountpoint, id);
> -}
> +	size_t i;
>  
> -int cr_plugin_restore_ext_mount(int id, char *mountpoint, char *old_root, int *is_file)
> -{
> -	return run_plugin_funcs(cr_plugin_restore_ext_mount, id, mountpoint, old_root, is_file);
> +	pr_debug("Plugin \"%s\" (version %u hooks %u)\n",
> +		 d->name, d->version, d->max_hooks);
> +	for (i = 0; i < d->max_hooks; i++) {
> +		if (d->hooks[i])
> +			pr_debug("\t%4zu -> %p\n", i, d->hooks[i]);
> +	}
>  }
>  
> -int cr_plugin_dump_ext_link(int index, int type, char *kind)
> +static int verify_plugin(cr_plugin_desc_t *d)
>  {
> -	return run_plugin_funcs(cr_plugin_dump_ext_link, index, type, kind);
> +	if (d->version > CRIU_PLUGIN_VERSION) {
> +		pr_debug("Plugin %s has version %x while max %x supported\n",
> +			 d->name, d->version, CRIU_PLUGIN_VERSION);
> +		return -1;
> +	}
> +
> +	if (d->max_hooks > CR_PLUGIN_HOOK__MAX) {
> +		pr_debug("Plugin %s has %u assigned while max %u supported\n",
> +			 d->name, d->max_hooks, CR_PLUGIN_HOOK__MAX);
> +		return -1;
> +	}
> +
> +	return 0;
>  }
>  
> -static int cr_lib_load(char *path)
> +static int cr_lib_load(int stage, char *path)
>  {
> -	struct cr_plugin_entry *ce;
> -	cr_plugin_init_t *f_init;
> -	cr_plugin_fini_t *f_fini;
> +	cr_plugin_desc_t *d;
> +	plugin_desc_t *this;
> +	size_t i;
>  	void *h;
>  
>  	h = dlopen(path, RTLD_LAZY);
> @@ -120,77 +100,98 @@ 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);
> +	/*
> +	 * Load plugin descriptor. If plugin is too old -- create
> +	 * dynamic plugin descriptor. In most cases this won't
> +	 * be a common operation and plugins are not supposed to
> +	 * be changing own format frequently.
> +	 */
> +	d = dlsym(h, "CR_PLUGIN_DESC");
> +	if (!d)
> +		d = cr_gen_plugin_desc(h, path);
> +	if (!d) {
> +		pr_err("Can't load plugin %s\n", path);
> +		dlclose(h);
> +		return -1;
> +	}
> +
> +	this = xzalloc(sizeof(*this));
> +	if (!this) {
> +		dlclose(h);
> +		return -1;
> +	}
>  
> -	add_plugin_func(cr_plugin_dump_file);
> -	add_plugin_func(cr_plugin_restore_file);
> +	if (verify_plugin(d)) {
> +		pr_err("Corrupted plugin %s\n", path);
> +		xfree(this);
> +		dlclose(h);
> +		return -1;
> +	}
>  
> -	add_plugin_func(cr_plugin_dump_ext_mount);
> -	add_plugin_func(cr_plugin_restore_ext_mount);
> +	this->d = d;
> +	this->dlhandle = h;
> +	INIT_LIST_HEAD(&this->list);
>  
> -	add_plugin_func(cr_plugin_dump_ext_link);
> +	for (i = 0; i < d->max_hooks; i++)
> +		INIT_LIST_HEAD(&this->link[i]);
>  
> -	ce = NULL;
> -	f_fini = dlsym(h, "cr_plugin_fini");
> -	if (f_fini) {
> -		ce = xmalloc(sizeof(*ce));
> -		if (ce == NULL)
> -			goto nomem;
> -		ce->cr_fini = f_fini;
> -	}
> +	list_add_tail(&this->list, &cr_plugin_ctl.head);
> +	show_plugin_desc(d);
>  
> -	f_init = dlsym(h, "cr_plugin_init");
> -	if (f_init && f_init()) {
> -		xfree(ce);
> +	if (d->init && d->init(stage)) {
> +		pr_err("Failed in init(%d) of \"%s\"\n", stage, d->name);
> +		list_del(&this->list);
> +		xfree(this);
> +		dlclose(h);
>  		return -1;
>  	}
>  
> -	if (ce) {
> -		ce->next = cr_plugins.cr_fini;
> -		cr_plugins.cr_fini = ce;
> +	/*
> +	 * Chain hooks into appropriate places for
> +	 * fast handler access.
> +	 */
> +	for (i = 0; i < d->max_hooks; i++) {
> +		if (!d->hooks[i])
> +			continue;
> +		list_add_tail(&this->link[i], &cr_plugin_ctl.hook_chain[i]);
>  	}
>  
>  	return 0;
> -
> -nomem:
> -	return -1;
>  }
>  
> -#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)
> +void cr_plugin_fini(int stage, int ret)
>  {
> -	struct cr_plugin_entry *ce;
> +	plugin_desc_t *this, *tmp;
>  
> -	cr_plugin_free(cr_plugin_dump_unix_sk);
> -	cr_plugin_free(cr_plugin_restore_unix_sk);
> +	list_for_each_entry_safe(this, tmp, &cr_plugin_ctl.head, list) {
> +		void *h = this->dlhandle;
> +		size_t i;
>  
> -	cr_plugin_free(cr_plugin_dump_file);
> -	cr_plugin_free(cr_plugin_restore_file);
> +		list_del(&this->list);
> +		if (this->d->exit)
> +			this->d->exit(stage, ret);
>  
> -	while (cr_plugins.cr_fini) {
> -		ce = cr_plugins.cr_fini;
> -		cr_plugins.cr_fini = cr_plugins.cr_fini->next;
> +		for (i = 0; i < this->d->max_hooks; i++) {
> +			if (!list_empty(&this->link[i]))
> +				list_del(&this->link[i]);
> +		}
>  
> -		ce->cr_fini();
> -		xfree(ce);
> +		if (this->d->version == CRIU_PLUGIN_VERSION_OLD)
> +			xfree(this->d);
> +		dlclose(h);
>  	}
>  }
>  
> -int cr_plugin_init(void)
> +int cr_plugin_init(int stage)
>  {
>  	int exit_code = -1;
>  	char *path;
> +	size_t i;
>  	DIR *d;
>  
> -	memset(&cr_plugins, 0, sizeof(cr_plugins));
> +	INIT_LIST_HEAD(&cr_plugin_ctl.head);
> +	for (i = 0; i < ARRAY_SIZE(cr_plugin_ctl.hook_chain); i++)
> +		INIT_LIST_HEAD(&cr_plugin_ctl.hook_chain[i]);
>  
>  	if (opts.libdir == NULL) {
>  		path = getenv("CRIU_LIBS_DIR");
> @@ -231,7 +232,7 @@ int cr_plugin_init(void)
>  
>  		snprintf(path, sizeof(path), "%s/%s", opts.libdir, de->d_name);
>  
> -		if (cr_lib_load(path))
> +		if (cr_lib_load(stage, path))
>  			goto err;
>  	}
>  
> @@ -240,7 +241,7 @@ err:
>  	closedir(d);
>  
>  	if (exit_code)
> -		cr_plugin_fini();
> +		cr_plugin_fini(stage, exit_code);
>  
>  	return exit_code;
>  }
> diff --git a/sk-unix.c b/sk-unix.c
> index f205d8f46cdc..dad07505f98e 100644
> --- a/sk-unix.c
> +++ b/sk-unix.c
> @@ -550,7 +550,7 @@ static int dump_external_sockets(struct unix_sk_desc *peer)
>  	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);
> +		ret = run_plugins(DUMP_UNIX_SK, sk->fd, sk->sd.ino);
>  		if (ret == -ENOTSUP) {
>  			if (!opts.ext_unix_sk) {
>  				show_one_unix("Runaway socket", peer);
> @@ -917,7 +917,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
>  		sk = sks[0];
>  	} else {
>  		if (ui->ue->uflags & USK_CALLBACK) {
> -			sk = cr_plugin_restore_unix_sk(ui->ue->ino);
> +			sk = run_plugins(RESTORE_UNIX_SK, ui->ue->ino);
>  			if (sk >= 0)
>  				goto out;
>  		}
> -- 
> 1.9.3
> 



More information about the CRIU mailing list