[CRIU] [PATCH v4 10/15] unix: Resolve senders of packets in receive queue of DGRAM socket

Kirill Tkhai ktkhai at virtuozzo.com
Thu Jun 9 07:01:01 PDT 2016


On 09.06.2016 16:14, Pavel Emelyanov wrote:
> On 06/01/2016 07:03 PM, Kirill Tkhai wrote:
>> 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 at virtuozzo.com>
>> ---
>>  criu/include/sk-queue.h |    6 ++++
>>  criu/sk-queue.c         |   73 +++++++++++++++++++++++++++++++++++++++++++++++
>>  criu/sk-unix.c          |   55 ++++++++++++++++++++++++++++++++++-
>>  3 files changed, 132 insertions(+), 2 deletions(-)
>>
>> diff --git a/criu/include/sk-queue.h b/criu/include/sk-queue.h
>> index 5fd2e01..0ad9da2 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;
>> +};
>> +
> 
> Document this structure.
> 
>>  extern struct collect_image_info sk_queues_cinfo;
>>  extern int dump_sk_queue(int sock_fd, int sock_id, u64 (*get_sender)(const char *, int));
>>  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 *, bool, void *), void *);
>>  
>>  #endif /* __CR_SK_QUEUE_H__ */
>> diff --git a/criu/sk-queue.c b/criu/sk-queue.c
>> index ded9ca9..f40bc2d 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"
>>  
>> @@ -194,6 +195,78 @@ int dump_sk_queue(int sock_fd, int sock_id, u64 (*get_sender)(const char *, int)
>>  	return ret;
>>  }
>>  
>> +/*
>> + * Resolves senders and returns number of foreign senders, we should receive.
>> + */
>> +int resolve_senders(unsigned int id, u32 ino, int (*add_receiver)(u32, struct sk_ino *, bool, void *), void *data)
>> +{
>> +	bool has_noname_sender = false, only_sender;
>> +	struct sk_ino *si, *tmp;
>> +	struct sk_packet *pkt;
>> +	int count = 0, ret;
>> +	u32 sender_ino;
>> +	LIST_HEAD(head);
>> +
>> +	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)
>> +			sender_ino = entry->sender_ino;
>> +		else {
>> +			has_noname_sender = true;
>> +			continue;
>> +		}
>> +
>> +		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++;
>> +	}
>> +
>> +	if (count == 0) {
>> +		BUG_ON(!has_noname_sender);
>> +		return 0;
>> +	}
>> +
>> +	only_sender = !(count > 1 || (count && has_noname_sender));
>> +
>> +	list_for_each_entry_safe(si, tmp, &head, list) {
>> +		list_del(&si->list);
>> +
>> +		sender_ino = si->ino;
>> +		si->ino = ino; /* Reuse it as receiver */
>> +
>> +		ret = add_receiver(sender_ino, si, only_sender, data);
>> +		if (ret < 0)
>> +			goto err;
>> +		else if (ret == 1) {
>> +			BUG_ON(!only_sender);
>> +			shfree_last(si);
>> +			return 0;
>> +		}
>> +	}
>> +
>> +	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 758eba6..7e717bc 100644
>> --- a/criu/sk-unix.c
>> +++ b/criu/sk-unix.c
>> @@ -821,6 +821,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;
>> @@ -840,6 +841,8 @@ struct unix_sk_info {
>>  	 * that should do the queueing.
>>  	 */
>>  	u32 queuer;
>> +
>> +	u32 nr_senders;
>>  };
>>  
>>  #define USK_PAIR_MASTER		0x1
>> @@ -1046,6 +1049,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);
>>  
>> @@ -1094,6 +1099,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",
>> @@ -1336,7 +1343,7 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
>>  	ui->ue = pb_msg(base, UnixSkEntry);
>>  	ui->name_dir = (void *)ui->ue->name_dir;
>>  
>> -	if (ui->ue->peer && !post_queued) {
>> +	if ((ui->ue->peer || !(ui->ue->uflags & USK_EMPTY_Q)) && !post_queued) {
>>  		post_queued = true;
>>  		if (add_post_prepare_cb(resolve_unix_peers, NULL))
>>  			return -1;
>> @@ -1356,6 +1363,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",
>> @@ -1394,11 +1403,49 @@ static void interconnected_pair(struct unix_sk_info *ui, struct unix_sk_info *pe
>>  	}
>>  }
>>  
>> +static int unix_add_receiver(u32 s_ino, struct sk_ino *ski, bool only_sender, void *r_ptr)
>> +{
>> +	struct unix_sk_info *s_ui, *r_ui;
>> +
>> +	s_ui = find_unix_sk_by_ino(s_ino);
>> +	if (!s_ui) {
>> +		pr_err("Can't find a sender: ino=%d\n", s_ino);
>> +		return -1;
>> +	}
>> +
>> +	if (s_ui->ue->peer != ski->ino || !only_sender) {
>> +		list_add(&ski->list, &s_ui->receivers);
>> +		pr_info("Add receiver %u to %u\n", ski->ino, s_ino);
>> +		return 0;
>> +	}
>> +
>> +	r_ui = r_ptr;
>> +	s_ui->peer = r_ui;
>> +	r_ui->queuer = s_ino;
>> +
>> +	if (s_ui->queuer == r_ui->ue->ino)
>> +		interconnected_pair(s_ui, r_ui);
>> +
>> +	return 1;
>> +}
>> +
>>  static int resolve_unix_peers(void *unused)
>>  {
>>  	struct unix_sk_info *ui, *peer;
>>  
>>  	list_for_each_entry(ui, &unix_sockets, list) {
>> +		if (ui->ue->type != SOCK_DGRAM ||
>> +		    (ui->ue->uflags & (USK_EMPTY_Q|USK_EXTERN)))
>> +			continue;
>> +
>> +		ui->nr_senders = resolve_senders(ui->ue->id, ui->ue->ino, unix_add_receiver, ui);
>> +		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;
>> +	}
>> +
>> +	list_for_each_entry(ui, &unix_sockets, list) {
> 
> Why 2nd walk over the list? Can't we call whatever is below and resolve_senders()
> in one loop?

It seems, we can. Maybe currently hidden problems will happen in further. I'll try.

> 
>>  		if (ui->peer)
>>  			continue;
>>  		if (!ui->ue->peer)
>> @@ -1413,15 +1460,19 @@ static int resolve_unix_peers(void *unused)
>>  		}
>>  
>>  		ui->peer = peer;
>> -		if (!peer->queuer)
>> +		if (!peer->queuer && !peer->nr_senders)
>>  			peer->queuer = ui->ue->ino;

nr_senders is number of foreign sockets, who are involved in writing to its queue.
We set it, if several named sockets are involved, OR if the only named socket and an unnamed socket.

If peer has a foreign sender, than it's not possible to make any socket as its queuer.

>>  		if (ui == peer)
>>  			/* socket connected to self %) */
>>  			continue;
>>  		if (peer->ue->peer != ui->ue->ino)
>>  			continue;
>> +		if (!ui->queuer && !ui->nr_senders)
>> +			ui->queuer = peer->ue->ino;

The same is here

>>  
>>  		peer->peer = ui;
>> +		if (!peer->queuer || !ui->queuer)
>> +			continue;
> 
> I don't get the logic in this particular hunk. Please, explain.

If they both are queuers of each other, than it's interconnected
pair. If at least one of them is not queuer, we restore them
by standalone scenario, where foreign socket may should be received.
 
>>  
>>  		/* socketpair or interconnected sockets */
>>  		interconnected_pair(ui, peer);
>>
>> _______________________________________________
>> CRIU mailing list
>> CRIU at openvz.org
>> https://lists.openvz.org/mailman/listinfo/criu
>> .
>>
> 


More information about the CRIU mailing list