[CRIU] [PATCH 2/3] plugin: Rework plugins API
Andrew Vagin
avagin at parallels.com
Wed Mar 12 03:57:27 PDT 2014
On Thu, Mar 06, 2014 at 08:53:45PM +0400, Cyrill Gorcunov wrote:
>
> 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.
>
> The idea behind is to not limit plugins authors with names
> of functions they might need to use for particular hook.
> Also plugin descriptor allows us to not call for additional
> malloc()'s during plugin handling -- all information needed
> will be stored in plugin descriptor statically allocated
> in plugin library itself.
>
> 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>
> ---
> include/criu-plugin.h | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++
> include/plugin.h | 35 +++++++++++++++++
> 2 files changed, 138 insertions(+)
>
> diff --git a/include/criu-plugin.h b/include/criu-plugin.h
> index cda8c8eb98e6..fb2558d50deb 100644
> --- a/include/criu-plugin.h
> +++ b/include/criu-plugin.h
> @@ -23,6 +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.
> + */
> +
> +#define DECLARE_PLUGIN_HOOK_ARGS(__hook, ...) \
> + typedef int (__hook ##_t)(__VA_ARGS__)
> +
> +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
> +};
> +
> +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);
> +
> +/*
> + * Strictly speaking this CR_PRIV_CHAIN_ENTRY_SIZE stands for
> + * double linked list entry size.
> + */
> +#define CR_PRIV_CHAIN_ENTRY_SIZE (2 * sizeof(void *))
> +#define CR_PRIV_SIZE ((CR_PLUGIN_HOOK__MAX) * CR_PRIV_CHAIN_ENTRY_SIZE + \
> + CR_PRIV_CHAIN_ENTRY_SIZE + 16 * sizeof(void *))
What is a magic 16 here?
> +
> +typedef struct {
> + const char *name;
> + int (*init)(void);
> + void (*exit)(void);
> + unsigned int version;
> + unsigned int max_hooks;
> + void *hooks[CR_PLUGIN_HOOK__MAX];
> + size_t priv_size;
> +
> + /*
> + * @private is CRIU plugin engine private field,
> + * don't ever modify inside plugin code!
> + *
> + * Also if this structure need to be extended
> + * put new members _AFTER_ the @private field.
> + */
> + char private[CR_PRIV_SIZE];
How we are going to support its backward compatibility in a future?
> +} __attribute__((__packed__)) cr_plugin_desc_t;
Why do we need __packed__ here?
> +
> +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, \
> + .priv_size = CR_PRIV_SIZE, \
> + }
> +
> +static inline int cr_plugin_dummy_init(void) { return 0; }
> +static inline void cr_plugin_dummy_exit(void) { }
I think inline is useless here, because you are going to access these
function by pointers.
> +
> +#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, \
> + .priv_size = CR_PRIV_SIZE, \
> + };
> +
> +#define CR_PLUGIN_REGISTER_HOOK(__hook, __func) \
> +static void __attribute__((constructor)) cr_plugin_register_hook_##__func (void) \
> +{ \
> + CR_PLUGIN_DESC.hooks[__hook] = (void *)__func; \
> +}
> +
> +/*
> + * Obsolete, will be dropped off after a couple of releases.
> + */
> typedef int (cr_plugin_init_t)(void);
> typedef void (cr_plugin_fini_t)(void);
>
> diff --git a/include/plugin.h b/include/plugin.h
> index 3c53e3003de3..ddcfcc99ca0d 100644
> --- a/include/plugin.h
> +++ b/include/plugin.h
> @@ -2,6 +2,8 @@
> #define __CR_PLUGIN_H__
>
> #include "criu-plugin.h"
> +#include "compiler.h"
> +#include "list.h"
>
> #define CR_PLUGIN_DEFAULT "/var/lib/criu/"
>
> @@ -19,4 +21,37 @@ int cr_plugin_restore_ext_mount(int id, char *mountpoint, char *old_root, int *i
>
> int cr_plugin_dump_ext_link(int index, int type, char *kind);
>
> +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 {
> + struct list_head list;
> + void *dlhandle;
> + struct list_head link[0];
> +} __packed plugin_desc_t;
> +
> +#define cr_plugin_desc_from(this) \
> + ((void *)this - (size_t)offsetof(cr_plugin_desc_t, private))
> +
> +#define run_plugins(__hook, ...) \
> +({ \
> + cr_plugin_desc_t *d; \
> + plugin_desc_t *this; \
> + int __ret = -ENOTSUP; \
> + \
> + list_for_each_entry(this, &cr_plugin_ctl.hook_chain[__hook], link[__hook]) { \
> + d = cr_plugin_desc_from(this); \
> + pr_debug("plugin: `%s' hook %u -> %p\n", d->name, __hook, d->hooks[__hook]); \
> + __ret = ((__hook ##_t *)d->hooks[__hook])(__VA_ARGS__); \
> + if (__ret == -ENOTSUP) \
> + continue; \
> + break; \
> + } \
> + __ret; \
> +})
> +
> #endif
More information about the CRIU
mailing list