Commit 79fd764a authored by Artem Kuzmitskiy's avatar Artem Kuzmitskiy Committed by Pavel Emelyanov

Add dumping of unnamed unix sockets.

* Added functionality for dumping unnamed unix sockets.
  When we call CRIU with dump option, for unnamed socket we
  should pass it inode into --ext-unix-sk. Details about this problem
  described in http://criu.org/External_UNIX_socket#What_to_do_with_socketpair.28.29-s.3F.
  Usage example:
    criu dump -D images -o dump.log -v4 --ext-unix-sk=4529709 -t 13506

* fix typo error in log output
Signed-off-by: 's avatarArtem Kuzmitskiy <artem.kuzmitskiy@lge.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b9259712
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "cgroup.h" #include "cgroup.h"
#include "action-scripts.h" #include "action-scripts.h"
#include "security.h" #include "security.h"
#include "sockets.h"
#include "setproctitle.h" #include "setproctitle.h"
...@@ -285,8 +286,13 @@ static int setup_opts_from_req(int sk, CriuOpts *req) ...@@ -285,8 +286,13 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
req->pid = ids.pid; req->pid = ids.pid;
} }
if (req->has_ext_unix_sk) if (req->has_ext_unix_sk) {
opts.ext_unix_sk = req->ext_unix_sk; opts.ext_unix_sk = req->ext_unix_sk;
for (i = 0; i < req->n_unix_sk_ino; i++) {
if (unix_sk_id_add(req->unix_sk_ino[i]->inode) < 0)
goto err;
}
}
if (req->root) if (req->root)
opts.root = req->root; opts.root = req->root;
......
...@@ -50,6 +50,7 @@ void init_opts(void) ...@@ -50,6 +50,7 @@ void init_opts(void)
/* Default options */ /* Default options */
opts.final_state = TASK_DEAD; opts.final_state = TASK_DEAD;
INIT_LIST_HEAD(&opts.ext_unixsk_ids);
INIT_LIST_HEAD(&opts.veth_pairs); INIT_LIST_HEAD(&opts.veth_pairs);
INIT_LIST_HEAD(&opts.scripts); INIT_LIST_HEAD(&opts.scripts);
INIT_LIST_HEAD(&opts.ext_mounts); INIT_LIST_HEAD(&opts.ext_mounts);
...@@ -184,7 +185,7 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -184,7 +185,7 @@ int main(int argc, char *argv[], char *envp[])
int log_level = LOG_UNSET; int log_level = LOG_UNSET;
char *imgs_dir = "."; char *imgs_dir = ".";
char *work_dir = NULL; char *work_dir = NULL;
static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::xVr:jlW:L:M:"; static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jlW:L:M:";
static struct option long_opts[] = { static struct option long_opts[] = {
{ "tree", required_argument, 0, 't' }, { "tree", required_argument, 0, 't' },
{ "pid", required_argument, 0, 'p' }, { "pid", required_argument, 0, 'p' },
...@@ -201,7 +202,7 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -201,7 +202,7 @@ int main(int argc, char *argv[], char *envp[])
{ "log-file", required_argument, 0, 'o' }, { "log-file", required_argument, 0, 'o' },
{ "namespaces", required_argument, 0, 'n' }, { "namespaces", required_argument, 0, 'n' },
{ "root", required_argument, 0, 'r' }, { "root", required_argument, 0, 'r' },
{ USK_EXT_PARAM, no_argument, 0, 'x' }, { USK_EXT_PARAM, optional_argument, 0, 'x' },
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },
{ SK_EST_PARAM, no_argument, 0, 1042 }, { SK_EST_PARAM, no_argument, 0, 1042 },
{ "close", required_argument, 0, 1043 }, { "close", required_argument, 0, 1043 },
...@@ -278,6 +279,8 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -278,6 +279,8 @@ int main(int argc, char *argv[], char *envp[])
opts.final_state = TASK_ALIVE; opts.final_state = TASK_ALIVE;
break; break;
case 'x': case 'x':
if (optarg && unix_sk_ids_parse(optarg) < 0)
return 1;
opts.ext_unix_sk = true; opts.ext_unix_sk = true;
break; break;
case 'p': case 'p':
...@@ -675,7 +678,7 @@ usage: ...@@ -675,7 +678,7 @@ usage:
" restore making it the parent of the restored process\n" " restore making it the parent of the restored process\n"
"\n" "\n"
"* Special resources support:\n" "* Special resources support:\n"
" -x|--" USK_EXT_PARAM " allow external unix connections\n" " -x|--" USK_EXT_PARAM "inode,.." " allow external unix connections (optionally can be assign socket's inode that allows one-sided dump)\n"
" --" SK_EST_PARAM " checkpoint/restore established TCP connections\n" " --" SK_EST_PARAM " checkpoint/restore established TCP connections\n"
" -r|--root PATH change the root filesystem (when run in mount namespace)\n" " -r|--root PATH change the root filesystem (when run in mount namespace)\n"
" --evasive-devices use any path to a device file if the original one\n" " --evasive-devices use any path to a device file if the original one\n"
......
...@@ -1424,7 +1424,7 @@ bool inherited_fd(struct file_desc *d, int *fd_p) ...@@ -1424,7 +1424,7 @@ bool inherited_fd(struct file_desc *d, int *fd_p)
if (*fd_p < 0) if (*fd_p < 0)
pr_perror("Inherit fd DUP failed"); pr_perror("Inherit fd DUP failed");
else else
pr_info("File %s will be restored from fd %d duped " pr_info("File %s will be restored from fd %d dumped "
"from inherit fd %d\n", id_str, *fd_p, i_fd); "from inherit fd %d\n", id_str, *fd_p, i_fd);
return true; return true;
} }
......
...@@ -45,6 +45,7 @@ struct cr_options { ...@@ -45,6 +45,7 @@ struct cr_options {
}; };
bool restore_sibling; bool restore_sibling;
bool ext_unix_sk; bool ext_unix_sk;
struct list_head ext_unixsk_ids;
bool shell_job; bool shell_job;
bool handle_file_locks; bool handle_file_locks;
bool tcp_established_ok; bool tcp_established_ok;
......
...@@ -60,6 +60,9 @@ extern int inet_collect_one(struct nlmsghdr *h, int family, int type); ...@@ -60,6 +60,9 @@ extern int inet_collect_one(struct nlmsghdr *h, int family, int type);
extern int unix_receive_one(struct nlmsghdr *h, void *); extern int unix_receive_one(struct nlmsghdr *h, void *);
extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg); extern int netlink_receive_one(struct nlmsghdr *hdr, void *arg);
extern int unix_sk_id_add(ino_t ino);
extern int unix_sk_ids_parse(char *optarg);
extern int do_dump_opt(int sk, int level, int name, void *val, int len); extern int do_dump_opt(int sk, int level, int name, void *val, int len);
#define dump_opt(s, l, n, f) do_dump_opt(s, l, n, f, sizeof(*f)) #define dump_opt(s, l, n, f) do_dump_opt(s, l, n, f, sizeof(*f))
extern int do_restore_opt(int sk, int level, int name, void *val, int len); extern int do_restore_opt(int sk, int level, int name, void *val, int len);
......
...@@ -225,6 +225,53 @@ void criu_set_ext_unix_sk(bool ext_unix_sk) ...@@ -225,6 +225,53 @@ void criu_set_ext_unix_sk(bool ext_unix_sk)
criu_local_set_ext_unix_sk(global_opts, ext_unix_sk); criu_local_set_ext_unix_sk(global_opts, ext_unix_sk);
} }
int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode)
{
int nr;
UnixSk **a, *u;
/*if caller forgot enable ext_unix_sk option we do it*/
if (!opts->rpc->has_ext_unix_sk) {
criu_local_set_ext_unix_sk(opts, true);
}
/*if user disabled ext_unix_sk and try to add unixsk inode after that*/
if (opts->rpc->has_ext_unix_sk && !opts->rpc->ext_unix_sk) {
if (opts->rpc->n_unix_sk_ino > 0) {
free(opts->rpc->unix_sk_ino);
opts->rpc->n_unix_sk_ino = 0;
}
return -1;
}
u = malloc(sizeof(*u));
if (!u)
goto er;
unix_sk__init(u);
u->inode = inode;
nr = opts->rpc->n_unix_sk_ino + 1;
a = realloc(opts->rpc->unix_sk_ino, nr * sizeof(u));
if (!a)
goto er_u;
a[nr - 1] = u;
opts->rpc->unix_sk_ino = a;
opts->rpc->n_unix_sk_ino = nr;
return 0;
er_u:
free(u);
er:
return -ENOMEM;
}
int criu_add_unix_sk(unsigned int inode)
{
return criu_local_add_unix_sk(global_opts, inode);
}
void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established) void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established)
{ {
opts->rpc->has_tcp_established = true; opts->rpc->has_tcp_established = true;
......
...@@ -51,6 +51,7 @@ void criu_set_parent_images(char *path); ...@@ -51,6 +51,7 @@ void criu_set_parent_images(char *path);
void criu_set_work_dir_fd(int fd); void criu_set_work_dir_fd(int fd);
void criu_set_leave_running(bool leave_running); void criu_set_leave_running(bool leave_running);
void criu_set_ext_unix_sk(bool ext_unix_sk); void criu_set_ext_unix_sk(bool ext_unix_sk);
int criu_add_unix_sk(unsigned int inode);
void criu_set_tcp_established(bool tcp_established); void criu_set_tcp_established(bool tcp_established);
void criu_set_evasive_devices(bool evasive_devices); void criu_set_evasive_devices(bool evasive_devices);
void criu_set_shell_job(bool shell_job); void criu_set_shell_job(bool shell_job);
...@@ -74,8 +75,6 @@ int criu_add_cg_root(char *ctrl, char *path); ...@@ -74,8 +75,6 @@ int criu_add_cg_root(char *ctrl, char *path);
int criu_add_enable_fs(char *fs); int criu_add_enable_fs(char *fs);
int criu_add_skip_mnt(char *mnt); int criu_add_skip_mnt(char *mnt);
/* /*
* The criu_notify_arg_t na argument is an opaque * The criu_notify_arg_t na argument is an opaque
* value that callbacks (cb-s) should pass into * value that callbacks (cb-s) should pass into
...@@ -160,6 +159,7 @@ void criu_local_set_parent_images(criu_opts *opts, char *path); ...@@ -160,6 +159,7 @@ void criu_local_set_parent_images(criu_opts *opts, char *path);
void criu_local_set_work_dir_fd(criu_opts *opts, int fd); void criu_local_set_work_dir_fd(criu_opts *opts, int fd);
void criu_local_set_leave_running(criu_opts *opts, bool leave_running); void criu_local_set_leave_running(criu_opts *opts, bool leave_running);
void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk); void criu_local_set_ext_unix_sk(criu_opts *opts, bool ext_unix_sk);
int criu_local_add_unix_sk(criu_opts *opts, unsigned int inode);
void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established); void criu_local_set_tcp_established(criu_opts *opts, bool tcp_established);
void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices); void criu_local_set_evasive_devices(criu_opts *opts, bool evasive_devices);
void criu_local_set_shell_job(criu_opts *opts, bool shell_job); void criu_local_set_shell_job(criu_opts *opts, bool shell_job);
......
...@@ -25,6 +25,10 @@ message cgroup_root { ...@@ -25,6 +25,10 @@ message cgroup_root {
required string path = 2; required string path = 2;
}; };
message unix_sk {
required uint32 inode = 1;
};
message criu_opts { message criu_opts {
required int32 images_dir_fd = 1; required int32 images_dir_fd = 1;
optional int32 pid = 2; /* if not set on dump, will dump requesting process */ optional int32 pid = 2; /* if not set on dump, will dump requesting process */
...@@ -68,6 +72,8 @@ message criu_opts { ...@@ -68,6 +72,8 @@ message criu_opts {
repeated string skip_mnt = 31; repeated string skip_mnt = 31;
repeated string enable_fs = 32; repeated string enable_fs = 32;
repeated unix_sk unix_sk_ino = 33;
} }
message criu_dump_resp { message criu_dump_resp {
......
...@@ -75,6 +75,11 @@ struct unix_sk_listen_icon { ...@@ -75,6 +75,11 @@ struct unix_sk_listen_icon {
struct unix_sk_listen_icon *next; struct unix_sk_listen_icon *next;
}; };
struct unix_sk_exception {
struct list_head unix_sk_list;
ino_t unix_sk_ino;
};
#define SK_HASH_SIZE 32 #define SK_HASH_SIZE 32
static struct unix_sk_listen_icon *unix_listen_icons[SK_HASH_SIZE]; static struct unix_sk_listen_icon *unix_listen_icons[SK_HASH_SIZE];
...@@ -139,6 +144,23 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk) ...@@ -139,6 +144,23 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk)
return 1; return 1;
} }
static bool unix_sk_exception_lookup_id(ino_t ino)
{
bool ret = false;
struct unix_sk_exception *sk;
list_for_each_entry(sk, &opts.ext_unixsk_ids, unix_sk_list) {
if (sk->unix_sk_ino == ino) {
pr_debug("Found ino %u in exception unix sk list\n", (unsigned int)ino);
ret = true;
break;
}
}
return ret;
}
static int write_unix_entry(struct unix_sk_desc *sk) static int write_unix_entry(struct unix_sk_desc *sk)
{ {
int ret; int ret;
...@@ -663,16 +685,21 @@ static int dump_external_sockets(struct unix_sk_desc *peer) ...@@ -663,16 +685,21 @@ static int dump_external_sockets(struct unix_sk_desc *peer)
return -1; return -1;
} }
if (peer->type != SOCK_DGRAM) { if (unix_sk_exception_lookup_id(sk->sd.ino)) {
show_one_unix("Ext stream not supported", peer); pr_debug("found exception for unix name-less external socket.\n");
pr_err("Can't dump half of stream unix connection.\n"); } else {
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");
if (!peer->name) { return -1;
show_one_unix("Ext dgram w/o name", peer); }
pr_err("Can't dump name-less external socket.\n");
return -1; if (!peer->name) {
show_one_unix("Ext dgram w/o name", peer);
pr_err("Can't dump name-less external socket.\n");
pr_err("%d\n", sk->fd);
return -1;
}
} }
} else if (ret < 0) } else if (ret < 0)
return -1; return -1;
...@@ -1257,3 +1284,47 @@ int resolve_unix_peers(void) ...@@ -1257,3 +1284,47 @@ int resolve_unix_peers(void)
return 0; return 0;
} }
int unix_sk_id_add(ino_t ino)
{
struct unix_sk_exception *unix_sk;
/* TODO: validate inode here? */
unix_sk = xmalloc(sizeof *unix_sk);
if (unix_sk == NULL)
return -1;
unix_sk->unix_sk_ino = ino;
list_add_tail(&unix_sk->unix_sk_list, &opts.ext_unixsk_ids);
return 0;
}
int unix_sk_ids_parse(char *optarg)
{
/*
* parsing option of the following form: --ext-unix-sk=<inode value>,<inode
* value>... or short form -x<inode>,<inode>...
*/
char *iter = optarg;
while (*iter != '\0') {
if (*iter == ',')
iter++;
else {
ino_t ino = (ino_t)strtoul(iter, &iter, 10);
if (0 == ino) {
pr_err("Can't parse unix socket inode from optarg: %s\n", optarg);
return -1;
}
if (unix_sk_id_add(ino) < 0) {
pr_err("Can't add unix socket inode in list: %s\n", optarg);
return -1;
}
}
}
return 0;
}
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