[CRIU] [PATCH 15/19] unix: Add fake queuer for standalone stream sockets in established state
Kirill Tkhai
ktkhai at virtuozzo.com
Tue Jan 30 18:43:06 MSK 2018
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 at virtuozzo.com>
---
criu/cr-restore.c | 4 ++
criu/include/sockets.h | 1
criu/sk-unix.c | 115 ++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 111 insertions(+), 9 deletions(-)
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index c6c9a7daf..f616de817 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -384,6 +384,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;
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 1bd5c67d2..cb233b9f9 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -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);
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index f5c825381..bfbe44af5 100644
--- a/criu/sk-unix.c
+++ b/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;
@@ -1712,6 +1748,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)
{
More information about the CRIU
mailing list