[CRIU] [PATCH 02/10] unux: postpone dumping sockets

Andrey Vagin avagin at openvz.org
Wed Dec 18 03:36:31 PST 2013


Unix sockets are dumped, when a peer socket is found.
We are going to dump external sockets with help plugins. For the we need
to set the USK_CALLBACK flags in unix entry. Currently a socket is
dumped immediately when it's transfered, but we can be sure that a
socket is not external, only when we have its peer.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 sk-unix.c | 163 +++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 103 insertions(+), 60 deletions(-)

diff --git a/sk-unix.c b/sk-unix.c
index da65368..f46546d 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -49,6 +49,10 @@ struct unix_sk_desc {
 	int			fd;
 	struct list_head	peer_list;
 	struct list_head	peer_node;
+
+	u32			id;
+	unsigned int		flags;
+	FownEntry		fown;
 };
 
 static LIST_HEAD(unix_sockets);
@@ -123,37 +127,26 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk)
 	return 1;
 }
 
-static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
+static int write_unix_entry(struct unix_sk_desc *sk,
+			struct unix_sk_desc *peer, unsigned int uflags)
 {
-	struct unix_sk_desc *sk, *peer;
 	UnixSkEntry ue = UNIX_SK_ENTRY__INIT;
 	SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
 	FilePermsEntry perms = FILE_PERMS_ENTRY__INIT;
 
-	sk = (struct unix_sk_desc *)lookup_socket(p->stat.st_ino, PF_UNIX, 0);
-	if (IS_ERR_OR_NULL(sk)) {
-		pr_err("Unix socket %#x not found\n", (int)p->stat.st_ino);
-		goto err;
-	}
-
-	if (!can_dump_unix_sk(sk))
-		goto err;
-
-	BUG_ON(sk->sd.already_dumped);
-
 	ue.name.len	= (size_t)sk->namelen;
 	ue.name.data	= (void *)sk->name;
 
-	ue.id		= id;
+	ue.id		= sk->id;
 	ue.ino		= sk->sd.ino;
 	ue.type		= sk->type;
 	ue.state	= sk->state;
-	ue.flags	= p->flags;
+	ue.flags	= sk->flags;
 	ue.backlog	= sk->wqlen;
 	ue.peer		= sk->peer_ino;
-	ue.fown		= (FownEntry *)&p->fown;
+	ue.fown		= &sk->fown;
 	ue.opts		= &skopts;
-	ue.uflags	= 0;
+	ue.uflags	= uflags;
 
 	/*
 	 * Check if this socket is connected to criu service.
@@ -176,43 +169,6 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
 	sk_encode_shutdown(&ue, sk->shutdown);
 
 	if (ue.peer) {
-		peer = (struct unix_sk_desc *)lookup_socket(ue.peer, PF_UNIX, 0);
-		if (IS_ERR_OR_NULL(peer)) {
-			pr_err("Unix socket %#x without peer %#x\n",
-					ue.ino, ue.peer);
-			goto err;
-		}
-
-		/*
-		 * Peer should have us as peer or have a name by which
-		 * we can access one.
-		 */
-		if (peer->peer_ino != ue.ino) {
-			if (!peer->name) {
-				pr_err("Unix socket %#x with unreachable peer %#x (%#x/%s)\n",
-				       ue.ino, ue.peer, peer->peer_ino, peer->name);
-				goto err;
-			}
-		}
-
-		/*
-		 * It can be external socket, so we defer dumping
-		 * until all sockets the program owns are processed.
-		 */
-		if (!peer->sd.already_dumped) {
-			if (list_empty(&peer->list)) {
-				show_one_unix("Add a peer", peer);
-				list_add_tail(&peer->list, &unix_sockets);
-			}
-
-			list_add(&sk->peer_node, &peer->peer_list);
-			sk->fd = dup(lfd);
-			if (sk->fd < 0) {
-				pr_perror("Unable to dup(%d)", lfd);
-				goto err;
-			}
-		}
-
 		if ((ue.type != SOCK_DGRAM) && (
 				((ue.shutdown == SK_SHUTDOWN__READ)  &&
 				 (peer->shutdown != SK_SHUTDOWN__WRITE)) ||
@@ -270,12 +226,85 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
 				ue.ino, ue.peer);
 	}
 dump:
-	if (dump_socket_opts(lfd, &skopts))
+	if (dump_socket_opts(sk->fd, &skopts))
 		goto err;
 
 	if (pb_write_one(fdset_fd(glob_fdset, CR_FD_UNIXSK), &ue, PB_UNIX_SK))
 		goto err;
+	show_one_unix_img("Dumped", &ue);
+	release_skopts(&skopts);
+	return 0;
+err:
+	release_skopts(&skopts);
+	return -1;
+}
+
+static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
+{
+	struct unix_sk_desc *sk, *peer = NULL;
+	unsigned int ino;
+
+	sk = (struct unix_sk_desc *)lookup_socket(p->stat.st_ino, PF_UNIX, 0);
+	if (IS_ERR_OR_NULL(sk)) {
+		pr_err("Unix socket %#x not found\n", (int)p->stat.st_ino);
+		goto err;
+	}
+
+	if (!can_dump_unix_sk(sk))
+		goto err;
+
+	BUG_ON(sk->sd.already_dumped);
+
+	ino = sk->sd.ino;
+	sk->id = id;
+	sk->fown = p->fown;
+	sk->fd = lfd;
+
+	if (sk->peer_ino) {
+		peer = (struct unix_sk_desc *)lookup_socket(sk->peer_ino, PF_UNIX, 0);
+		if (IS_ERR_OR_NULL(peer)) {
+			pr_err("Unix socket %#x without peer %#x\n",
+					ino, sk->peer_ino);
+			goto err;
+		}
+
+		/*
+		 * Peer should have us as peer or have a name by which
+		 * we can access one.
+		 */
+		if (peer->peer_ino != ino) {
+			if (!peer->name) {
+				pr_err("Unix socket %#x with unreachable peer %#x (%#x/%s)\n",
+				       ino, sk->peer_ino, peer->peer_ino, peer->name);
+				goto err;
+			}
+		}
+
+		/*
+		 * It can be external socket, so we defer dumping
+		 * until all sockets the program owns are processed.
+		 */
+		if (!peer->sd.already_dumped) {
+			if (list_empty(&peer->list)) {
+				show_one_unix("Add a peer", peer);
+				list_add_tail(&peer->list, &unix_sockets);
+			}
+
+			list_add(&sk->peer_node, &peer->peer_list);
+			sk->fd = dup(lfd);
+			if (sk->fd < 0) {
+				pr_perror("Unable to dup(%d)", lfd);
+				goto err;
+			}
+			pr_err("\n");
+			goto dump_queue;
+		}
+	}
+
+	if (write_unix_entry(sk, peer, 0))
+		goto err;
 
+dump_queue:
 	/*
 	 * If a stream listening socket has non-zero rqueue, this
 	 * means there are in-flight connections waiting to get
@@ -284,13 +313,11 @@ dump:
 	 */
 	if (sk->rqlen != 0 && !(sk->type == SOCK_STREAM &&
 				sk->state == TCP_LISTEN))
-		if (dump_sk_queue(lfd, ue.id))
+		if (dump_sk_queue(lfd, id))
 			goto err;
 
 	pr_info("Dumping unix socket at %d\n", p->fd);
 	show_one_unix("Dumping", sk);
-	show_one_unix_img("Dumped", &ue);
-	release_skopts(&skopts);
 
 	list_del_init(&sk->list);
 	sk->sd.already_dumped = 1;
@@ -298,14 +325,14 @@ dump:
 	while (!list_empty(&sk->peer_list)) {
 		struct unix_sk_desc *psk;
 		psk = list_first_entry(&sk->peer_list, struct unix_sk_desc, peer_node);
+		if (write_unix_entry(psk, sk, 0))
+			goto err;
 		close_safe(&psk->fd);
 		list_del(&psk->peer_node);
 	}
 
 	return 0;
-
 err:
-	release_skopts(&skopts);
 	return -1;
 }
 
@@ -473,6 +500,19 @@ int unix_receive_one(struct nlmsghdr *h, void *arg)
 	return unix_collect_one(m, tb);
 }
 
+static int dump_external_sockets(struct unix_sk_desc *peer)
+{
+	struct unix_sk_desc *sk;
+
+	list_for_each_entry(sk, &peer->peer_list, peer_node) {
+		if (write_unix_entry(sk, peer, 0))
+			return -1;
+		close_safe(&sk->fd);
+	}
+
+	return 0;
+}
+
 int fix_external_unix_sockets(void)
 {
 	struct unix_sk_desc *sk;
@@ -501,6 +541,9 @@ int fix_external_unix_sockets(void)
 			goto err;
 		}
 
+		if (dump_external_sockets(sk))
+			goto err;
+
 		e.id		= fd_id_generate_special();
 		e.ino		= sk->sd.ino;
 		e.type		= SOCK_DGRAM;
-- 
1.8.3.1



More information about the CRIU mailing list