[v2,10/15] unix: Resolve senders of packets in receive queue of DGRAM socket

Submitted by Kirill Tkhai on May 27, 2016, 1:07 p.m.

Details

Message ID 146435443617.31234.12047568828958123936.stgit@pro
State Rejected
Series "Support for packet's msg_name in receive queue of promiscous DGRAM sockets"
Headers show

Commit Message

Kirill Tkhai May 27, 2016, 1:07 p.m.
Determine unique senders of packets in receive queue, and notify
every of them, that it has a receiver. Link the receiver ino in
unix_sk_info::receivers list of the sender.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/include/sk-queue.h |    6 +++++
 criu/sk-queue.c         |   56 +++++++++++++++++++++++++++++++++++++++++++++++
 criu/sk-unix.c          |   37 +++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/include/sk-queue.h b/criu/include/sk-queue.h
index 93498e3..b7bb869 100644
--- a/criu/include/sk-queue.h
+++ b/criu/include/sk-queue.h
@@ -3,8 +3,14 @@ 
 
 #define SK_NONAME_SENDER	(~0ULL)
 
+struct sk_ino {
+	struct list_head list;
+	u32 ino;
+};
+
 extern struct collect_image_info sk_queues_cinfo;
 extern int dump_sk_queue(int sock_fd, int sock_id, u32 (*get_sender)(const char *, int), u64 *sender_ino);
 extern int restore_sk_queue(int fd, unsigned int peer_id);
+extern int resolve_senders(unsigned int id, u32 ino, int (*add_receiver)(u32, struct sk_ino *));
 
 #endif /* __CR_SK_QUEUE_H__ */
diff --git a/criu/sk-queue.c b/criu/sk-queue.c
index fa3407b..9a68286 100644
--- a/criu/sk-queue.c
+++ b/criu/sk-queue.c
@@ -17,6 +17,7 @@ 
 #include "servicefd.h"
 #include "cr_options.h"
 #include "util.h"
+#include "rst-malloc.h"
 #include "util-pie.h"
 #include "sockets.h"
 
@@ -203,6 +204,61 @@  int dump_sk_queue(int sock_fd, int sock_id, u32 (*get_sender)(const char *, int)
 	return ret;
 }
 
+int resolve_senders(unsigned int id, u32 ino, int (*add_receiver)(u32, struct sk_ino *))
+{
+	struct sk_ino *si, *tmp;
+	struct sk_packet *pkt;
+	u32 sender_ino;
+	LIST_HEAD(head);
+	int count = 0;
+
+	list_for_each_entry(pkt, &packets_list, list) {
+		SkPacketEntry *entry = pkt->entry;
+		bool found = false;
+
+		if (entry->id_for != id)
+			continue;
+		if (!entry->has_sender_ino)
+			continue;
+
+		sender_ino = entry->sender_ino;
+
+		list_for_each_entry(si, &head, list) {
+			if (si->ino == sender_ino) {
+				found = true;
+				break;
+			}
+		}
+
+		if (found)
+			continue;
+
+		si = shmalloc(sizeof(*si));
+		if (!si)
+			goto err;
+		si->ino = sender_ino;
+		list_add_tail(&si->list, &head);
+		count++;
+	}
+
+	list_for_each_entry_safe(si, tmp, &head, list) {
+		list_del(&si->list);
+
+		sender_ino = si->ino;
+		si->ino = ino; /* Reuse it as receiver */
+
+		if (add_receiver(sender_ino, si) < 0) {
+			list_add(&si->list, &head);
+			goto err;
+		}
+	}
+
+	return count;
+err:
+	pr_err("Resolving senders failed\n");
+	return -1;
+}
+
 int restore_sk_queue(int fd, unsigned int peer_id)
 {
 	struct sk_packet *pkt, *tmp;
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index cf589b8..fc3cb44 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -833,6 +833,7 @@  int fix_external_unix_sockets(void)
 struct unix_sk_info {
 	UnixSkEntry *ue;
 	struct list_head list;
+	struct list_head receivers;
 	char *name;
 	char *name_dir;
 	unsigned flags;
@@ -852,6 +853,8 @@  struct unix_sk_info {
 	 * that should do the queueing.
 	 */
 	u32 queuer;
+
+	u32 nr_senders;
 };
 
 #define USK_PAIR_MASTER		0x1
@@ -1058,6 +1061,8 @@  static int open_unixsk_pair_master(struct unix_sk_info *ui)
 	struct unix_sk_info *peer = ui->peer;
 	struct fdinfo_list_entry *fle;
 
+	BUG_ON(ui->nr_senders);
+
 	pr_info("Opening pair master (id %#x ino %#x peer %#x)\n",
 			ui->ue->id, ui->ue->ino, ui->ue->peer);
 
@@ -1106,6 +1111,8 @@  static int open_unixsk_pair_slave(struct unix_sk_info *ui)
 	struct fdinfo_list_entry *fle;
 	int sk;
 
+	BUG_ON(ui->nr_senders);
+
 	fle = file_master(&ui->d);
 
 	pr_info("Opening pair slave (id %#x ino %#x peer %#x) on %d\n",
@@ -1368,6 +1375,8 @@  static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
 
 	futex_init(&ui->prepared);
 	ui->queuer = 0;
+	INIT_LIST_HEAD(&ui->receivers);
+	ui->nr_senders = 0;
 	ui->peer = NULL;
 	ui->flags = 0;
 	pr_info(" `- Got %#x peer %#x (name %s dir %s)\n",
@@ -1406,6 +1415,22 @@  static u32 sk_queuer(struct unix_sk_info *sk, struct unix_sk_info *maybe_queuer)
 	return 0;
 }
 
+static int unix_add_receiver(u32 ino, struct sk_ino *si)
+{
+	struct unix_sk_info *ui;
+
+	ui = find_unix_sk_by_ino(ino);
+	if (!ui) {
+		pr_err("Can't find a sender: ino=%d\n", ino);
+		return -1;
+	}
+
+	list_add(&si->list, &ui->receivers);
+	pr_info("Add receiver %d to %u\n", si->ino, ino);
+
+	return 0;
+}
+
 static int resolve_unix_peers(void *unused)
 {
 	struct unix_sk_info *ui, *peer;
@@ -1459,6 +1484,18 @@  static int resolve_unix_peers(void *unused)
 		}
 	}
 
+	list_for_each_entry(ui, &unix_sockets, list) {
+		if (ui->ue->type != SOCK_DGRAM || ui->queuer ||
+		    (ui->ue->uflags & (USK_EMPTY_Q|USK_NONAME_SND|USK_EXTERN)))
+			continue;
+
+		ui->nr_senders = resolve_senders(ui->ue->id, ui->ue->ino, unix_add_receiver);
+		pr_info("Found a socket w/o queuer: ino=%d, senders=%d\n",
+			 ui->ue->ino, ui->nr_senders);
+		if (ui->nr_senders < 0)
+			return -1;
+	}
+
 	pr_info("Unix sockets:\n");
 	list_for_each_entry(ui, &unix_sockets, list) {
 		struct fdinfo_list_entry *fle;