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 @@ ...@@ -20,9 +20,14 @@
#ifndef __CRIU_PLUGIN_H__ #ifndef __CRIU_PLUGIN_H__
#define __CRIU_PLUGIN_H__ #define __CRIU_PLUGIN_H__
#include <limits.h>
typedef int (cr_plugin_init_t)(void); typedef int (cr_plugin_init_t)(void);
typedef void (cr_plugin_fini_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 */ /* Public API */
extern int criu_get_image_dir(void); extern int criu_get_image_dir(void);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define USK_EXTERN (1 << 0) #define USK_EXTERN (1 << 0)
#define USK_SERVICE (1 << 1) #define USK_SERVICE (1 << 1)
#define USK_CALLBACK (1 << 2)
#define VMA_AREA_NONE (0 << 0) #define VMA_AREA_NONE (0 << 0)
#define VMA_AREA_REGULAR (1 << 0) /* Dumpable area */ #define VMA_AREA_REGULAR (1 << 0) /* Dumpable area */
......
...@@ -7,4 +7,8 @@ ...@@ -7,4 +7,8 @@
void cr_plugin_fini(void); void cr_plugin_fini(void);
int cr_plugin_init(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 #endif
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
struct cr_plugin_entry { struct cr_plugin_entry {
union { union {
cr_plugin_fini_t *cr_fini; 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; struct cr_plugin_entry *next;
...@@ -21,10 +24,55 @@ struct cr_plugin_entry { ...@@ -21,10 +24,55 @@ struct cr_plugin_entry {
struct cr_plugins { struct cr_plugins {
struct cr_plugin_entry *cr_fini; 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; 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) static int cr_lib_load(char *path)
{ {
struct cr_plugin_entry *ce; struct cr_plugin_entry *ce;
...@@ -38,6 +86,9 @@ static int cr_lib_load(char *path) ...@@ -38,6 +86,9 @@ static int cr_lib_load(char *path)
return -1; return -1;
} }
add_plugin_func(cr_plugin_dump_unix_sk);
add_plugin_func(cr_plugin_restore_unix_sk);
ce = NULL; ce = NULL;
f_fini = dlsym(h, "cr_plugin_fini"); f_fini = dlsym(h, "cr_plugin_fini");
if (f_fini) { if (f_fini) {
...@@ -61,10 +112,21 @@ static int cr_lib_load(char *path) ...@@ -61,10 +112,21 @@ static int cr_lib_load(char *path)
return 0; 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) void cr_plugin_fini(void)
{ {
struct cr_plugin_entry *ce; 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) { while (cr_plugins.cr_fini) {
ce = cr_plugins.cr_fini; ce = cr_plugins.cr_fini;
cr_plugins.cr_fini = cr_plugins.cr_fini->next; cr_plugins.cr_fini = cr_plugins.cr_fini->next;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/un.h> #include <sys/un.h>
#include <stdlib.h> #include <stdlib.h>
#include <dlfcn.h>
#include "asm/types.h" #include "asm/types.h"
#include "libnetlink.h" #include "libnetlink.h"
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#include "sk-queue.h" #include "sk-queue.h"
#include "mount.h" #include "mount.h"
#include "cr-service.h" #include "cr-service.h"
#include "plugin.h"
#include "protobuf.h" #include "protobuf.h"
#include "protobuf/sk-unix.pb-c.h" #include "protobuf/sk-unix.pb-c.h"
...@@ -519,6 +521,42 @@ int unix_receive_one(struct nlmsghdr *h, void *arg) ...@@ -519,6 +521,42 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
return unix_collect_one(m, tb); 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) int fix_external_unix_sockets(void)
{ {
struct unix_sk_desc *sk; struct unix_sk_desc *sk;
...@@ -534,19 +572,6 @@ int fix_external_unix_sockets(void) ...@@ -534,19 +572,6 @@ int fix_external_unix_sockets(void)
BUG_ON(sk->sd.already_dumped); 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.id = fd_id_generate_special();
e.ino = sk->sd.ino; e.ino = sk->sd.ino;
e.type = SOCK_DGRAM; e.type = SOCK_DGRAM;
...@@ -563,15 +588,8 @@ int fix_external_unix_sockets(void) ...@@ -563,15 +588,8 @@ int fix_external_unix_sockets(void)
show_one_unix_img("Dumped extern", &e); show_one_unix_img("Dumped extern", &e);
while (!list_empty(&sk->peer_list)) { if (dump_external_sockets(sk))
struct unix_sk_desc *psk; goto err;
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;
}
} }
return 0; return 0;
...@@ -637,6 +655,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd) ...@@ -637,6 +655,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
if (peer == NULL) if (peer == NULL)
return 0; return 0;
if (ui->ue->uflags & USK_CALLBACK)
return 0;
pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino); pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
/* Skip external sockets */ /* Skip external sockets */
...@@ -874,6 +895,25 @@ static int open_unixsk_standalone(struct unix_sk_info *ui) ...@@ -874,6 +895,25 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
close(sks[1]); close(sks[1]);
sk = sks[0]; sk = sks[0];
} else { } 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); sk = socket(PF_UNIX, ui->ue->type, 0);
if (sk < 0) { if (sk < 0) {
pr_perror("Can't make unix socket"); pr_perror("Can't make unix socket");
...@@ -891,7 +931,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui) ...@@ -891,7 +931,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
return -1; return -1;
} }
} }
out:
if (rst_file_params(sk, ui->ue->fown, ui->ue->flags)) if (rst_file_params(sk, ui->ue->fown, ui->ue->flags))
return -1; return -1;
...@@ -987,18 +1027,6 @@ int resolve_unix_peers(void) ...@@ -987,18 +1027,6 @@ int resolve_unix_peers(void)
return -1; 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; ui->peer = peer;
if (ui == peer) if (ui == peer)
/* socket connected to self %) */ /* 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