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@openvz.org>
Acked-by: Andrew Vagin <avagin@parallels.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
Cyrill Gorcunov 2014-02-27 20:58:23 +04:00 committed by Pavel Emelyanov
parent b858711726
commit 3146f58317
9 changed files with 281 additions and 168 deletions

View file

@ -1759,7 +1759,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())
@ -1859,7 +1859,7 @@ err:
close_cr_fdset(&glob_fdset);
cr_plugin_fini();
cr_plugin_fini(CR_PLUGIN_STAGE__DUMP, ret);
if (!ret) {
/*

View file

@ -1792,7 +1792,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)
@ -1831,7 +1831,7 @@ int cr_restore_tasks(void)
err:
fini_cgroup();
cr_plugin_fini();
cr_plugin_fini(CR_PLUGIN_STAGE__RESTORE, ret);
return ret;
}

View file

@ -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;

View file

@ -23,21 +23,109 @@
#include <limits.h>
#include <stdbool.h>
typedef int (cr_plugin_init_t)(void);
typedef void (cr_plugin_fini_t)(void);
#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
typedef int (cr_plugin_dump_unix_sk_t)(int fd, int id);
typedef int (cr_plugin_restore_unix_sk_t)(int id);
#define CRIU_PLUGIN_VERSION_OLD CRIU_PLUGIN_GEN_VERSION(0,1,0)
typedef int (cr_plugin_dump_file_t)(int fd, int id);
typedef int (cr_plugin_restore_file_t)(int id);
#define CRIU_PLUGIN_VERSION \
CRIU_PLUGIN_GEN_VERSION(CRIU_PLUGIN_VERSION_MAJOR, \
CRIU_PLUGIN_VERSION_MINOR, \
CRIU_PLUGIN_VERSION_SUBLEVEL)
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);
/*
* Plugin hook points and their arguments in hooks.
*/
enum {
CR_PLUGIN_HOOK__DUMP_UNIX_SK,
CR_PLUGIN_HOOK__RESTORE_UNIX_SK,
typedef int (cr_plugin_dump_ext_link_t)(int index, int type, char *kind);
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);
#endif /* __CRIU_PLUGIN_H__ */

View file

@ -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);
void cr_plugin_fini(int stage, int err);
int cr_plugin_init(int stage);
int cr_plugin_dump_unix_sk(int fd, int id);
int cr_plugin_restore_unix_sk(int id);
typedef struct {
struct list_head head;
struct list_head hook_chain[CR_PLUGIN_HOOK__MAX];
} cr_plugin_ctl_t;
int cr_plugin_dump_file(int fd, int id);
int cr_plugin_restore_file(int id);
extern cr_plugin_ctl_t cr_plugin_ctl;
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);
typedef struct {
cr_plugin_desc_t *d;
struct list_head list;
void *dlhandle;
struct list_head link[CR_PLUGIN_HOOK__MAX];
} plugin_desc_t;
int cr_plugin_dump_ext_link(int index, int type, char *kind);
#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

View file

@ -426,7 +426,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)
@ -1302,7 +1302,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_err("Can't restore ext mount (%d)\n", ret);
return ret;

2
net.c
View file

@ -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);

279
plugin.c
View file

@ -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 "plugin.h"
#include "log.h"
#include "compiler.h"
#include "xmalloc.h"
#include "plugin.h"
#include "list.h"
#include "log.h"
struct cr_plugin_entry {
union {
cr_plugin_fini_t *cr_fini;
cr_plugin_ctl_t cr_plugin_ctl;
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;
};
/*
* 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;
struct cr_plugin_entry *next;
};
d = xzalloc(sizeof(*d));
if (!d)
return NULL;
struct cr_plugins {
struct cr_plugin_entry *cr_fini;
d->name = strdup(path);
d->max_hooks = CR_PLUGIN_HOOK__MAX;
d->version = CRIU_PLUGIN_VERSION_OLD;
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;
};
pr_warn("Generating dynamic descriptor for plugin `%s'."
"Won't work in next version of the program."
"Please update your plugin.\n", path);
struct cr_plugins cr_plugins;
#define add_plugin_func(name) \
#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; \
}) \
__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_dump_unix_sk(int fd, int id)
{
return run_plugin_funcs(cr_plugin_dump_unix_sk, fd, id);
#undef __assign_hook
d->init = dlsym(h, "cr_plugin_init");
d->exit = dlsym(h, "cr_plugin_fini");
return d;
}
int cr_plugin_restore_unix_sk(int id)
static void show_plugin_desc(cr_plugin_desc_t *d)
{
return run_plugin_funcs(cr_plugin_restore_unix_sk, id);
size_t i;
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_file(int fd, int id)
static int verify_plugin(cr_plugin_desc_t *d)
{
return run_plugin_funcs(cr_plugin_dump_file, fd, id);
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;
}
int cr_plugin_restore_file(int id)
static int cr_lib_load(int stage, char *path)
{
return run_plugin_funcs(cr_plugin_restore_file, id);
}
int cr_plugin_dump_ext_mount(char *mountpoint, int id)
{
return run_plugin_funcs(cr_plugin_dump_ext_mount, mountpoint, id);
}
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);
}
int cr_plugin_dump_ext_link(int index, int type, char *kind)
{
return run_plugin_funcs(cr_plugin_dump_ext_link, index, type, kind);
}
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,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);
add_plugin_func(cr_plugin_dump_file);
add_plugin_func(cr_plugin_restore_file);
add_plugin_func(cr_plugin_dump_ext_mount);
add_plugin_func(cr_plugin_restore_ext_mount);
add_plugin_func(cr_plugin_dump_ext_link);
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;
}
f_init = dlsym(h, "cr_plugin_init");
if (f_init && f_init()) {
xfree(ce);
/*
* 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;
}
if (ce) {
ce->next = cr_plugins.cr_fini;
cr_plugins.cr_fini = ce;
this = xzalloc(sizeof(*this));
if (!this) {
dlclose(h);
return -1;
}
if (verify_plugin(d)) {
pr_err("Corrupted plugin %s\n", path);
xfree(this);
dlclose(h);
return -1;
}
this->d = d;
this->dlhandle = h;
INIT_LIST_HEAD(&this->list);
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);
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;
}
/*
* 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;
}

View file

@ -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;
}