Commit 9e3f4451 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

unix: add ability to set callbacks for external sockets (v5)

We don't know a state behind an external socket. It depends on logic
of the program, which handles this socket.

This patch adds ability to load a library with callbacks for dumping
and restoring external sockets.

This patch introduces two callbacks cr_plugin_dump_unix_sk and
cr_plugin_restore_unix_sk. If a callback can not handle a socket, it
must return -ENOTSUP.

The main questions, what kind of information should be tranfered in
these callbacks. Pls, think a few minutes about that and send me
your opinion.

v2: Use uflags instread of adding a new field
v3: clean up
v4: Unsuitable callbacks return -ENOTSUP.
v5: set USK_CALLBACK, if a socket was dumped by callback.
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent afc61ba5
......@@ -20,9 +20,14 @@
#ifndef __CRIU_PLUGIN_H__
#define __CRIU_PLUGIN_H__
#include <limits.h>
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);
/* Public API */
extern int criu_get_image_dir(void);
......
......@@ -33,6 +33,7 @@
#define USK_EXTERN (1 << 0)
#define USK_SERVICE (1 << 1)
#define USK_CALLBACK (1 << 2)
#define VMA_AREA_NONE (0 << 0)
#define VMA_AREA_REGULAR (1 << 0) /* Dumpable area */
......
......@@ -7,4 +7,8 @@
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);
#endif
......@@ -14,6 +14,9 @@
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;
};
struct cr_plugin_entry *next;
......@@ -21,10 +24,55 @@ struct cr_plugin_entry {
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_plugins cr_plugins;
#define add_plugin_func(name) \
do { \
name ## _t *name; \
name = dlsym(h, #name); \
if (name) { \
struct cr_plugin_entry *__ce; \
__ce = xmalloc(sizeof(struct cr_plugin_entry)); \
if (__ce == NULL) \
return -1; \
__ce->name = name; \
__ce->next = cr_plugins.name; \
cr_plugins.name = __ce; \
} \
} 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);
}
int cr_plugin_restore_unix_sk(int id)
{
return run_plugin_funcs(cr_plugin_restore_unix_sk, id);
}
static int cr_lib_load(char *path)
{
struct cr_plugin_entry *ce;
......@@ -38,6 +86,9 @@ 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);
ce = NULL;
f_fini = dlsym(h, "cr_plugin_fini");
if (f_fini) {
......@@ -61,10 +112,21 @@ static int cr_lib_load(char *path)
return 0;
}
#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;
cr_plugin_free(cr_plugin_dump_unix_sk);
cr_plugin_free(cr_plugin_restore_unix_sk);
while (cr_plugins.cr_fini) {
ce = cr_plugins.cr_fini;
cr_plugins.cr_fini = cr_plugins.cr_fini->next;
......
......@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <sys/un.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "asm/types.h"
#include "libnetlink.h"
......@@ -23,6 +24,7 @@
#include "sk-queue.h"
#include "mount.h"
#include "cr-service.h"
#include "plugin.h"
#include "protobuf.h"
#include "protobuf/sk-unix.pb-c.h"
......@@ -519,6 +521,42 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
return unix_collect_one(m, tb);
}
static int dump_external_sockets(struct unix_sk_desc *peer)
{
struct unix_sk_desc *sk;
int ret;
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);
if (ret == -ENOTSUP) {
if (!opts.ext_unix_sk) {
show_one_unix("Runaway socket", peer);
pr_err("External socket is used. "
"Consider using --" USK_EXT_PARAM " option.\n");
return -1;
}
if (peer->type != SOCK_DGRAM) {
show_one_unix("Ext stream not supported", peer);
pr_err("Can't dump half of stream unix connection.\n");
return -1;
}
} else if (ret < 0)
return -1;
else
sk->ue->uflags |= USK_CALLBACK;
if (write_unix_entry(sk))
return -1;
close_safe(&sk->fd);
list_del_init(&sk->peer_node);
}
return 0;
}
int fix_external_unix_sockets(void)
{
struct unix_sk_desc *sk;
......@@ -534,19 +572,6 @@ int fix_external_unix_sockets(void)
BUG_ON(sk->sd.already_dumped);
if (!opts.ext_unix_sk) {
show_one_unix("Runaway socket", sk);
pr_err("External socket is used. "
"Consider using --" USK_EXT_PARAM " option.\n");
goto err;
}
if (sk->type != SOCK_DGRAM) {
show_one_unix("Ext stream not supported", sk);
pr_err("Can't dump half of stream unix connection.\n");
goto err;
}
e.id = fd_id_generate_special();
e.ino = sk->sd.ino;
e.type = SOCK_DGRAM;
......@@ -563,15 +588,8 @@ int fix_external_unix_sockets(void)
show_one_unix_img("Dumped extern", &e);
while (!list_empty(&sk->peer_list)) {
struct unix_sk_desc *psk;
psk = list_first_entry(&sk->peer_list, struct unix_sk_desc, peer_node);
close_safe(&psk->fd);
list_del_init(&psk->peer_node);
if (write_unix_entry(psk))
goto err;
}
if (dump_external_sockets(sk))
goto err;
}
return 0;
......@@ -637,6 +655,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
if (peer == NULL)
return 0;
if (ui->ue->uflags & USK_CALLBACK)
return 0;
pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
/* Skip external sockets */
......@@ -874,6 +895,25 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
close(sks[1]);
sk = sks[0];
} else {
if (ui->ue->uflags & USK_CALLBACK) {
sk = cr_plugin_restore_unix_sk(ui->ue->ino);
if (sk >= 0)
goto out;
}
/*
* Connect to external sockets requires
* special option to be passed.
*/
if (ui->peer && (ui->peer->ue->uflags & USK_EXTERN) &&
!(opts.ext_unix_sk)) {
pr_err("External socket found in image. "
"Consider using the --" USK_EXT_PARAM
"option to allow restoring it.\n");
return -1;
}
sk = socket(PF_UNIX, ui->ue->type, 0);
if (sk < 0) {
pr_perror("Can't make unix socket");
......@@ -891,7 +931,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
return -1;
}
}
out:
if (rst_file_params(sk, ui->ue->fown, ui->ue->flags))
return -1;
......@@ -987,18 +1027,6 @@ int resolve_unix_peers(void)
return -1;
}
/*
* Connect to external sockets requires
* special option to be passed.
*/
if ((peer->ue->uflags & USK_EXTERN) &&
!(opts.ext_unix_sk)) {
pr_err("External socket found in image. "
"Consider using the --" USK_EXT_PARAM " option "
"to allow restoring it.\n");
return -1;
}
ui->peer = peer;
if (ui == peer)
/* socket connected to self %) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment