mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-18 00:58:31 +00:00
unix: Add fake queuer for standalone stream sockets in established state
This makes the second end of socketpair to live till post_open. We need it alive if we want to restore message queue later. Otherwise, we do not have a queuer, which fd is used to actually write messages. Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
aae41a6367
commit
d8ae190ef6
3 changed files with 111 additions and 9 deletions
|
|
@ -378,6 +378,10 @@ static int root_prepare_shared(void)
|
|||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = add_fake_unix_queuers();
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
show_saved_files();
|
||||
err:
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct ns_id;
|
|||
extern int collect_sockets(struct ns_id *);
|
||||
extern struct collect_image_info inet_sk_cinfo;
|
||||
extern struct collect_image_info unix_sk_cinfo;
|
||||
extern int add_fake_unix_queuers(void);
|
||||
extern int fix_external_unix_sockets(void);
|
||||
extern int prepare_scms(void);
|
||||
extern int unix_note_scm_rights(int id_for, uint32_t *file_ids, int *fds, int n_ids);
|
||||
|
|
|
|||
115
criu/sk-unix.c
115
criu/sk-unix.c
|
|
@ -54,6 +54,8 @@
|
|||
#define USK_CALLBACK (1 << 2)
|
||||
#define USK_INHERIT (1 << 3)
|
||||
|
||||
#define FAKE_INO 0
|
||||
|
||||
typedef struct {
|
||||
char *dir;
|
||||
unsigned int udiag_vfs_dev;
|
||||
|
|
@ -1123,6 +1125,11 @@ static int post_open_standalone(struct file_desc *d, int fd)
|
|||
if (!peer || ui->is_connected)
|
||||
goto restore_sk_common;
|
||||
|
||||
if (ui->ue->ino == FAKE_INO) {
|
||||
BUG_ON(ui->queuer);
|
||||
goto restore_queue;
|
||||
}
|
||||
|
||||
/* Skip external sockets */
|
||||
if (!list_empty(&peer->d.fd_info_head))
|
||||
if (peer_is_not_prepared(peer))
|
||||
|
|
@ -1148,6 +1155,7 @@ static int post_open_standalone(struct file_desc *d, int fd)
|
|||
|
||||
revert_unix_sk_cwd(&cwd_fd, &root_fd);
|
||||
|
||||
restore_queue:
|
||||
if (peer->queuer == ui &&
|
||||
!(peer->ue->uflags & USK_EXTERN) &&
|
||||
restore_unix_queue(fd, peer))
|
||||
|
|
@ -1364,8 +1372,39 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui, int *new_fd)
|
|||
return (fle_peer->stage != FLE_RESTORED);
|
||||
}
|
||||
|
||||
/*
|
||||
* When sks[0]'s fle requires to create socketpair, and sks[1] is also
|
||||
* somebody's fle, this makes file engine to make note the second_end
|
||||
* is also open.
|
||||
*/
|
||||
static int setup_second_end(int *sks, struct fdinfo_list_entry *second_end)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (sks[0] == second_end->fe->fd) {
|
||||
/*
|
||||
* Below setup_and_serve_out() will reuse this fd,
|
||||
* so this dups it in something else.
|
||||
*/
|
||||
ret = dup(sks[0]);
|
||||
if (ret < 0) {
|
||||
pr_perror("Can't dup()");
|
||||
return -1;
|
||||
}
|
||||
close(sks[0]);
|
||||
sks[0] = ret;
|
||||
}
|
||||
|
||||
if (setup_and_serve_out(second_end, sks[1])) {
|
||||
pr_err("Can't send pair slave\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
|
||||
{
|
||||
struct unix_sk_info *queuer = ui->queuer;
|
||||
struct fdinfo_list_entry *fle;
|
||||
int sk;
|
||||
|
||||
|
|
@ -1375,6 +1414,10 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
|
|||
if (fle->stage == FLE_OPEN)
|
||||
return post_open_standalone(&ui->d, fle->fe->fd);
|
||||
|
||||
/* Fake socket will be restored by its peer */
|
||||
if (!(ui->ue->uflags & USK_EXTERN) && ui->ue->ino == FAKE_INO)
|
||||
return 1;
|
||||
|
||||
if (set_netns(ui->ue->ns_id))
|
||||
return -1;
|
||||
|
||||
|
|
@ -1396,7 +1439,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
|
|||
|
||||
close(sks[1]);
|
||||
sk = sks[0];
|
||||
} else if ((ui->ue->state == TCP_ESTABLISHED) && !ui->ue->peer) {
|
||||
} else if (ui->ue->state == TCP_ESTABLISHED && queuer && queuer->ue->ino == FAKE_INO) {
|
||||
int ret, sks[2];
|
||||
|
||||
if (ui->ue->type != SOCK_STREAM) {
|
||||
|
|
@ -1417,16 +1460,9 @@ static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore queue at the one end,
|
||||
* before closing the second one.
|
||||
*/
|
||||
if (restore_unix_queue(sks[1], ui)) {
|
||||
pr_perror("Can't restore socket queue");
|
||||
if (setup_second_end(sks, file_master(&queuer->d)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(sks[1]);
|
||||
sk = sks[0];
|
||||
} else if (ui->ue->type == SOCK_DGRAM && !ui->queuer) {
|
||||
struct sockaddr_un addr;
|
||||
|
|
@ -1697,6 +1733,67 @@ static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer)
|
|||
peer->queuer = ui;
|
||||
}
|
||||
|
||||
static int add_fake_queuer(struct unix_sk_info *ui)
|
||||
{
|
||||
struct unix_sk_info *peer;
|
||||
struct pstree_item *task;
|
||||
UnixSkEntry *peer_ue;
|
||||
SkOptsEntry *skopts;
|
||||
FownEntry *fown;
|
||||
|
||||
if (ui->ue->ino == FAKE_INO)
|
||||
return 0;
|
||||
|
||||
peer = xzalloc(sizeof(struct unix_sk_info) +
|
||||
sizeof(UnixSkEntry) +
|
||||
sizeof(SkOptsEntry) +
|
||||
sizeof(FownEntry));
|
||||
if (peer == NULL)
|
||||
return -1;
|
||||
|
||||
peer_ue = (void *) peer + sizeof(struct unix_sk_info);
|
||||
skopts = (void *) peer_ue + sizeof(UnixSkEntry);
|
||||
fown = (void *) skopts + sizeof(SkOptsEntry);
|
||||
memcpy(skopts, ui->ue->opts, sizeof(SkOptsEntry));
|
||||
memcpy(fown, ui->ue->fown, sizeof(FownEntry));
|
||||
memcpy(peer_ue, ui->ue, sizeof(UnixSkEntry));
|
||||
peer_ue->opts = skopts;
|
||||
peer_ue->file_perms = NULL;
|
||||
peer_ue->fown = fown;
|
||||
peer_ue->name.len = 0;
|
||||
peer_ue->name_dir = NULL;
|
||||
|
||||
if (init_unix_sk_info(peer, peer_ue))
|
||||
return -1;
|
||||
|
||||
peer_ue->id = find_unused_file_desc_id();
|
||||
set_peer(peer, ui);
|
||||
|
||||
/* Note, that this fake fdesc has no ino */
|
||||
peer->ue->ino = FAKE_INO;
|
||||
file_desc_add(&peer->d, peer_ue->id, &unix_desc_ops);
|
||||
list_del_init(&peer->d.fake_master_list);
|
||||
list_add(&peer->list, &unix_sockets);
|
||||
task = file_master(&ui->d)->task;
|
||||
|
||||
return (get_fle_for_task(&peer->d, task, true) == NULL);
|
||||
}
|
||||
|
||||
int add_fake_unix_queuers(void)
|
||||
{
|
||||
struct unix_sk_info *ui;
|
||||
|
||||
list_for_each_entry(ui, &unix_sockets, list) {
|
||||
if ((ui->ue->uflags & USK_EXTERN) || ui->queuer)
|
||||
continue;
|
||||
if (!(ui->ue->state == TCP_ESTABLISHED && !ui->peer))
|
||||
continue;
|
||||
if (add_fake_queuer(ui))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called from post prepare only */
|
||||
static int interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *peer)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue