From e6f39a41bf6ccfea766114884cc65c7f5d25f21c Mon Sep 17 00:00:00 2001 From: Kinsbursky Stanislav Date: Wed, 29 Feb 2012 16:06:56 +0300 Subject: [PATCH] restore: socket queues support This patch was designed to be generic and thus usable for all kinds of sockets. Not sure, thah this goal has been reached, but at least I tried. Key ideas: 1) sockets queue dump file have to be readed first and then packets entries with offset for it's data in image will be collected in doubly linked list by read_sockets_queue() function. Note: list will contain sockets queues for all (!) the sockets of the task. 2) socket queue can be restored by restore_socket_queue(), which selects packets from the list by passed id and use sendfile() top send them to the passed socket. It also removes packet from the list and frees it. Based on xemul@ patches. Signed-off-by: Stanislav Kinsbursky Acked-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov --- sockets.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/sockets.c b/sockets.c index 52bf91e20..6c7b99fc9 100644 --- a/sockets.c +++ b/sockets.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "types.h" #include "libnetlink.h" @@ -675,6 +676,81 @@ out: return err; } +struct sk_packet { + struct list_head list; + struct sk_packet_entry entry; + off_t img_off; +}; + +struct sk_packets_pool { + struct list_head packets_list; + int img_fd; +}; + +static int read_sockets_queues(struct sk_packets_pool *pool) +{ + struct sk_packet *pkt; + int ret; + + pr_info("Trying to read socket queues image\n"); + + lseek(pool->img_fd, MAGIC_OFFSET, SEEK_SET); + while (1) { + struct sk_packet_entry tmp; + + pkt = xmalloc(sizeof(*pkt)); + if (!pkt) { + pr_err("Failed to allocate packet header\n"); + return -ENOMEM; + } + ret = read_img_eof(pool->img_fd, &pkt->entry); + if (ret <= 0) + break; + pkt->img_off = lseek(pool->img_fd, 0, SEEK_CUR); + /* + * NOTE: packet must be added to the tail. Otherwise sequence + * will be broken. + */ + list_add_tail(&pkt->list, &pool->packets_list); + lseek(pool->img_fd, pkt->entry.length, SEEK_CUR); + } + xfree(pkt); + return ret; +} + +static int restore_socket_queue(struct sk_packets_pool *pool, int fd, + unsigned int peer_id) +{ + struct sk_packet *pkt, *tmp; + int ret; + + pr_info("Trying to restore recv queue for %u\n", peer_id); + + list_for_each_entry_safe(pkt, tmp, &pool->packets_list, list) { + struct sk_packet_entry *entry = &pkt->entry; + + if (entry->id_for != peer_id) + continue; + + pr_info("\tRestoring %d-bytes skb for %u\n", + entry->length, peer_id); + + ret = sendfile(fd, pool->img_fd, &pkt->img_off, entry->length); + if (ret < 0) { + pr_perror("Failed to sendfile packet"); + return -1; + } + if (ret != entry->length) { + pr_err("Restored skb trimmed to %d/%d\n", + ret, entry->length); + return -1; + } + list_del(&pkt->list); + xfree(pkt); + } + return 0; +} + static void prep_conn_addr(int id, struct sockaddr_un *addr, int *addrlen) { addr->sun_family = AF_UNIX;