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

Pavel Emelyanov xemul at virtuozzo.com
Thu Jun 9 06:14:04 PDT 2016


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?

>  		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;
>  		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;
>  
>  		peer->peer = ui;
> +		if (!peer->queuer || !ui->queuer)
> +			continue;

I don't get the logic in this particular hunk. Please, explain.

>  
>  		/* 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