[PATCH 3/3] plugin: Use new plugin engine
Cyrill Gorcunov
gorcunov at openvz.org
Thu Mar 13 07:52:05 PDT 2014
The patch itself might look somehow scary so please review it applied.
For example, the existing test on unix callbacks reports (old version plugin)
| (00.001002) Plugin "test/unix-callback/lib/unix-lib.so" (version 256 hooks 7)
| (00.001011) 0 -> 0x7fc09f1b907e
| (00.001015) 1 -> 0x7fc09f1b9424
| (00.001423) Plugin "test/unix-callback/lib/syslog-lib.so" (version 256 hooks 7)
| (00.001431) 0 -> 0x7fc09efb65c0
| (00.001434) 1 -> 0x7fc09efb669a
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
files-ext.c | 4 +-
include/plugin.h | 11 ---
mount.c | 4 +-
net.c | 2 +-
plugin.c | 248 +++++++++++++++++++++++++++----------------------------
sk-unix.c | 4 +-
6 files changed, 129 insertions(+), 144 deletions(-)
diff --git a/files-ext.c b/files-ext.c
index d9640c49ccb2..7e6845de61c3 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(CR_PLUGIN_HOOK__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(CR_PLUGIN_HOOK__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/plugin.h b/include/plugin.h
index 7f1de63701b1..ba537852c1dd 100644
--- a/include/plugin.h
+++ b/include/plugin.h
@@ -10,17 +10,6 @@
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);
-
typedef struct {
struct list_head head;
struct list_head hook_chain[CR_PLUGIN_HOOK__MAX];
diff --git a/mount.c b/mount.c
index 522ae3c9469f..ac8c6a80aa8c 100644
--- a/mount.c
+++ b/mount.c
@@ -349,7 +349,7 @@ static int validate_mounts(struct mount_info *info, bool call_plugins)
int ret;
if (call_plugins) {
- ret = cr_plugin_dump_ext_mount(m->mountpoint, m->mnt_id);
+ ret = run_plugins(CR_PLUGIN_HOOK__DUMP_EXT_MOUNT, m->mountpoint, m->mnt_id);
if (ret == 0)
m->need_plugin = true;
} else if (m->need_plugin)
@@ -1080,7 +1080,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(CR_PLUGIN_HOOK__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 ac663749cff6..278af8b30140 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(CR_PLUGIN_HOOK__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..d6a78c787c5d 100644
--- a/plugin.c
+++ b/plugin.c
@@ -7,111 +7,87 @@
#include <unistd.h>
#include "cr_options.h"
+#include "compiler.h"
#include "plugin.h"
#include "log.h"
#include "xmalloc.h"
+#include "list.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 plugin, selfgenerate 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;
+
+#define __assign_hook(hook, name) \
do { \
- name ## _t *name; \
+ 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; \
- } \
+ if (name) \
+ d->hooks[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(CR_PLUGIN_HOOK__DUMP_UNIX_SK, cr_plugin_dump_unix_sk);
+ __assign_hook(CR_PLUGIN_HOOK__RESTORE_UNIX_SK, cr_plugin_restore_unix_sk);
+ __assign_hook(CR_PLUGIN_HOOK__DUMP_EXT_FILE, cr_plugin_dump_file);
+ __assign_hook(CR_PLUGIN_HOOK__RESTORE_EXT_FILE, cr_plugin_restore_file);
+ __assign_hook(CR_PLUGIN_HOOK__DUMP_EXT_MOUNT, cr_plugin_dump_ext_mount);
+ __assign_hook(CR_PLUGIN_HOOK__RESTORE_EXT_MOUNT,cr_plugin_restore_ext_mount);
+ __assign_hook(CR_PLUGIN_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)
{
- 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,67 +96,84 @@ 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;
+ }
- add_plugin_func(cr_plugin_dump_file);
- add_plugin_func(cr_plugin_restore_file);
+ this = xzalloc(sizeof(*this));
+ if (!this) {
+ dlclose(h);
+ return -1;
+ }
- add_plugin_func(cr_plugin_dump_ext_mount);
- add_plugin_func(cr_plugin_restore_ext_mount);
+ if (verify_plugin(d)) {
+ pr_err("Corrupted plugin %s\n", path);
+ xfree(this);
+ dlclose(h);
+ return -1;
+ }
- add_plugin_func(cr_plugin_dump_ext_link);
+ this->d = d;
+ this->dlhandle = h;
+ INIT_LIST_HEAD(&this->list);
- 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;
- }
+ for (i = 0; i < d->max_hooks; i++)
+ INIT_LIST_HEAD(&this->link[i]);
+
+ 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()) {
+ pr_err("Failed in init() of \"%s\"\n", 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 (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)
{
- 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();
- 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);
}
}
@@ -188,9 +181,12 @@ int cr_plugin_init(void)
{
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");
diff --git a/sk-unix.c b/sk-unix.c
index c2991ae33963..c8a4711e6643 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -538,7 +538,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(CR_PLUGIN_HOOK__DUMP_UNIX_SK, sk->fd, sk->sd.ino);
if (ret == -ENOTSUP) {
if (!opts.ext_unix_sk) {
show_one_unix("Runaway socket", peer);
@@ -905,7 +905,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(CR_PLUGIN_HOOK__RESTORE_UNIX_SK, ui->ue->ino);
if (sk >= 0)
goto out;
}
--
1.8.3.1
--GxcwvYAGnODwn7V8--
More information about the CRIU
mailing list