[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