[3/4] sk-unix: Handle bindmounted dgram sockets on restore

Submitted by Cyrill Gorcunov on Aug. 12, 2017, 2:42 p.m.

Details

Message ID 1502548928-6706-4-git-send-email-gorcunov@openvz.org
State New
Series "Handle bindmounted unix sockets"
Headers show

Commit Message

Cyrill Gorcunov Aug. 12, 2017, 2:42 p.m.
If a socket is bindmounted one we open it early (thus mount engine
will be eable to proceed), put it into fdstore and then simply fetch
it from there.

Note it's important that only basic scenario with dgram/closed sockets
is supported by now: established, listening sockets requires a way
more code change and we will do it only when really needed.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
 criu/include/sockets.h |  2 ++
 criu/mount.c           |  7 ++++++
 criu/sk-unix.c         | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 64673c5e5dc8..3d4669859182 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -8,6 +8,7 @@ 
 
 struct fdinfo_list_entry;
 struct sk_opts_entry;
+struct mount_info;
 struct file_desc;
 struct fd_parms;
 struct cr_imgset;
@@ -38,6 +39,7 @@  extern struct collect_image_info inet_sk_cinfo;
 extern struct collect_image_info unix_sk_cinfo;
 extern int fix_external_unix_sockets(void);
 extern int collect_unix_bindmounts(void);
+extern int unix_prepare_bindmount(struct mount_info *mi);
 
 extern struct collect_image_info netlink_sk_cinfo;
 
diff --git a/criu/mount.c b/criu/mount.c
index 59fd17870db8..174cc4639209 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -27,6 +27,7 @@ 
 #include "files-reg.h"
 #include "external.h"
 #include "fdstore.h"
+#include "sockets.h"
 
 #include "images/mnt.pb-c.h"
 
@@ -2042,6 +2043,12 @@  static int do_bind_mount(struct mount_info *mi)
 		}
 	}
 
+	if (unix_prepare_bindmount(mi)) {
+		pr_err("Failed to prepare bindmount on unix at %s\n",
+		       mi->mountpoint);
+		goto err;
+	}
+
 	if (mount(root, mi->mountpoint, NULL, MS_BIND | (mi->flags & MS_REC), NULL) < 0) {
 		pr_perror("Can't mount at %s", mi->mountpoint);
 		goto err;
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index f03702658167..5f8c3d689b9d 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -93,6 +93,7 @@  struct unix_sk_desc {
 };
 
 static LIST_HEAD(unix_sockets);
+static LIST_HEAD(unix_mnt_sockets);
 
 struct unix_sk_listen_icon {
 	unsigned int			peer_ino;
@@ -858,6 +859,7 @@  int collect_unix_bindmounts(void)
 struct unix_sk_info {
 	UnixSkEntry *ue;
 	struct list_head list;
+	struct list_head mnt_list;
 	char *name;
 	char *name_dir;
 	unsigned flags;
@@ -866,6 +868,7 @@  struct unix_sk_info {
 	struct file_desc d;
 	struct list_head connected; /* List of sockets, connected to me */
 	struct list_head node; /* To link in peer's connected list  */
+	int fdstore_id;
 
 	/*
 	 * For DGRAM sockets with queues, we should only restore the queue
@@ -1240,6 +1243,12 @@  static int open_unixsk_standalone(struct unix_sk_info *ui, int *new_fd)
 	pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
 			ui->ue->id, ui->ue->ino, ui->ue->peer);
 
+	if (ui->fdstore_id >= 0) {
+		pr_debug("\tObtaining from fdstore id %#x\n", ui->fdstore_id);
+		*new_fd = fdstore_get(ui->fdstore_id);
+		return 0;
+	}
+
 	if (set_netns(ui->ue->ns_id))
 		return -1;
 
@@ -1452,6 +1461,9 @@  static void unlink_stale(struct unix_sk_info *ui)
 {
 	int ret, cwd_fd = -1, root_fd = -1;
 
+	if (ui->fdstore_id >= 0)
+		return;
+
 	if (ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN))
 		return;
 
@@ -1508,6 +1520,7 @@  static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
 	INIT_LIST_HEAD(&ui->connected);
 	INIT_LIST_HEAD(&ui->node);
 	ui->flags = 0;
+	ui->fdstore_id = -1;
 	fixup_sock_net_ns_id(&ui->ue->ns_id, &ui->ue->has_ns_id);
 
 	uname = ui->name;
@@ -1540,6 +1553,11 @@  static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
 		add_post_prepare_cb(&ui->peer_resolve);
 	}
 
+	if (ui->ue->has_mnt_id)
+		list_add_tail(&ui->mnt_list, &unix_mnt_sockets);
+	else
+		INIT_LIST_HEAD(&ui->mnt_list);
+
 	list_add_tail(&ui->list, &unix_sockets);
 	return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops);
 }
@@ -1552,6 +1570,48 @@  struct collect_image_info unix_sk_cinfo = {
 	.flags = COLLECT_SHARED,
 };
 
+int unix_prepare_bindmount(struct mount_info *mi)
+{
+	char name_dir[PATH_MAX], ns_root[PATH_MAX];
+	struct unix_sk_info *ui, *t = NULL;
+	char *old_name_dir = NULL;
+	int ret, sk;
+
+	list_for_each_entry(ui, &unix_mnt_sockets, mnt_list) {
+		if (ui->ue->mnt_id != mi->mnt_id)
+			continue;
+		t = ui;
+		break;
+	}
+
+	if (!t)
+		return 0;
+
+	print_ns_root(mi->nsid, 0, ns_root, sizeof(ns_root));
+	if (ui->name_dir) {
+		old_name_dir = ui->name_dir;
+		snprintf(name_dir, sizeof(name_dir), "%s/%s", ns_root, ui->name_dir);
+		ui->name_dir = name_dir;
+	}
+
+	ret = open_unixsk_standalone(ui, &sk);
+	if (ui->name_dir)
+		ui->name_dir = old_name_dir;
+	BUG_ON(ret > 0);
+
+	if (ret)
+		return -1;
+
+	ui->fdstore_id = fdstore_add(sk);
+	if (ui->fdstore_id < 0)
+		return -1;
+	close(sk);
+
+	pr_debug("Standalone socket moved into fdstore (id %#x ino %#x peer %#x)\n",
+		 ui->ue->id, ui->ue->ino, ui->ue->peer);
+	return 0;
+}
+
 static void set_peer(struct unix_sk_info *ui, struct unix_sk_info *peer)
 {
 	ui->peer = peer;