[15/18] unix: Split resolv and interconnect (v2)

Submitted by Pavel Emelianov on July 10, 2017, 9:41 a.m.

Details

Message ID bb069ed5-5a4f-b241-3498-c223f8009339@virtuozzo.com
State Accepted
Series "Support descriptors sent over unix sockets"
Commit 4d958402a4d5475c9e0e666cb58314977fb04b21
Headers show

Commit Message

Pavel Emelianov July 10, 2017, 9:41 a.m.
In order to make sender of a descriptor (unix socket) be restored
_after_ the descriptor in question, we need to find out those
sockets early (before post-prep calls).

The problem is that current code gives us info about who's the
queuer for who only in post-prep hooks, so the peer resolution
should happen right in collect callback.

At the same time we need to make sure that all peers configured
in the image exist, as well as need to put master/slave flags
for socketpairs. Both these actions can only happen in post-prep.

Said that -- the current peer resolve routine should be split
into two steps.

v2: Handle the socket connected to self (dgram)

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
---
 criu/sk-unix.c | 62 ++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 23 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 5665bec..42ce1bb 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -1400,14 +1400,15 @@  static void unlink_stale(struct unix_sk_info *ui)
 	revert_unix_sk_cwd(&cwd_fd, &root_fd);
 }
 
-static int resolve_unix_peer(struct unix_sk_info *ui);
+static void try_resolve_unix_peer(struct unix_sk_info *ui);
+static int fixup_unix_peer(struct unix_sk_info *ui);
 
 static int post_prepare_unix_sk(struct pprep_head *ph)
 {
 	struct unix_sk_info *ui;
 
 	ui = container_of(ph, struct unix_sk_info, peer_resolve);
-	if (ui->ue->peer && resolve_unix_peer(ui))
+	if (ui->ue->peer && fixup_unix_peer(ui))
 		return -1;
 	if (ui->name)
 		unlink_stale(ui);
@@ -1468,6 +1469,9 @@  static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
 		ui->name_dir ? ui->name_dir : "-");
 
 	if (ui->ue->peer || ui->name) {
+		if (ui->ue->peer)
+			try_resolve_unix_peer(ui);
+
 		ui->peer_resolve.actor = post_prepare_unix_sk;
 		add_post_prepare_cb(&ui->peer_resolve);
 	}
@@ -1512,38 +1516,50 @@  static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe
 	}
 }
 
-static int resolve_unix_peer(struct unix_sk_info *ui)
+static int fixup_unix_peer(struct unix_sk_info *ui)
 {
-	struct unix_sk_info *peer;
-
-	if (ui->peer)
-		goto out;
-
-	BUG_ON(!ui->ue->peer);
+	struct unix_sk_info *peer = ui->peer;
 
-	peer = find_unix_sk_by_ino(ui->ue->peer);
 	if (!peer) {
 		pr_err("FATAL: Peer %#x unresolved for %#x\n",
 				ui->ue->peer, ui->ue->ino);
 		return -1;
 	}
 
-	set_peer(ui, peer);
-	if (ui == peer)
-		/* socket connected to self %) */
-		goto out;
-	if (peer->ue->peer != ui->ue->ino)
-		goto out;
-
-	pr_info("Connected %#x -> %#x (%#x) flags %#x\n",
-			ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags);
-	set_peer(peer, ui);
-	/* socketpair or interconnected sockets */
-	interconnected_pair(ui, peer);
-out:
+	if (peer != ui && peer->peer == ui &&
+			!(ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))) {
+		pr_info("Connected %#x -> %#x (%#x) flags %#x\n",
+				ui->ue->ino, ui->ue->peer, peer->ue->ino, ui->flags);
+		/* socketpair or interconnected sockets */
+		interconnected_pair(ui, peer);
+	}
+
 	return 0;
 }
 
+static void try_resolve_unix_peer(struct unix_sk_info *ui)
+{
+	struct unix_sk_info *peer;
+
+	if (ui->peer)
+		return;
+
+	BUG_ON(!ui->ue->peer);
+
+	if (ui->ue->peer == ui->ue->ino) {
+		/* socket connected to self %) */
+		set_peer(ui, ui);
+		return;
+	}
+
+	peer = find_unix_sk_by_ino(ui->ue->peer);
+	if (peer) {
+		set_peer(ui, peer);
+		if (peer->ue->peer == ui->ue->ino)
+			set_peer(peer, ui);
+	} /* else -- maybe later */
+}
+
 int unix_sk_id_add(unsigned int ino)
 {
 	char *e_str;