[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