[CRIU] [PATCH v3 19/19] lazy-pages: unblock second receive in page_server_event

Mike Rapoport rppt at linux.vnet.ibm.com
Tue Nov 15 08:57:28 PST 2016


The page transfer protocol is completely synchronous on the dump side,
therefore we can presume that when we get POLLIN event on the page server
socket it is either page info response for the last sent page request or
the page data following the last page info.
In the first case we set ev_data associated with page server socket events
to values received in receive_remote_page_info and in the second case we
reset ev_data to zero. This allows us to distinguish what was the reason
page_server_event have been called.

Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/uffd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 49 insertions(+), 12 deletions(-)

diff --git a/criu/uffd.c b/criu/uffd.c
index 95a116a..7efccf5 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -53,9 +53,18 @@ struct lazy_iovec {
 	unsigned long len;
 };
 
+struct lazy_pages_info;
+
+struct sk_event_data {
+	int nr_pages;
+	unsigned long addr;
+	struct lazy_pages_info *lpi;
+};
+
 struct lazy_pages_fd {
 	int fd;
 	int (*event)(struct lazy_pages_fd *);
+	struct sk_event_data *ev_data;
 };
 
 struct lazy_pages_info {
@@ -914,33 +923,61 @@ close_uffd:
 	return -1;
 }
 
+/*
+ * There are two possible event types we need to handle:
+ * - page info is available as a reply to request_remote_page
+ * - page data is available, and it follows page info we've just received
+ * Since the on dump side communications are completely synchronous,
+ * we can return to epoll right after the reception of page info and
+ * for sure the next time socket event will occur we'll get page data
+ * related to info we've just received
+ */
 static int page_server_event(struct lazy_pages_fd *lpfd)
 {
 	struct lazy_pages_info *lpi;
 	int pid, nr_pages;
 	unsigned long addr;
 
-	if (receive_remote_pages_info(&nr_pages, &addr, &pid))
-		return -1;
+	lpi = lpfd->ev_data->lpi;
 
-	lpi = pid2lpi(pid);
-	if (!lpi)
-		return -1;
+	if (!lpi) {
+		if (receive_remote_pages_info(&nr_pages, &addr, &pid))
+			return -1;
 
-	if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf))
-		return -1;
+		lpi = pid2lpi(pid);
+		if (!lpi)
+			return -1;
 
-	if (uffd_copy(lpi, addr, nr_pages))
-		return -1;
+		lpfd->ev_data->lpi = lpi;
+		lpfd->ev_data->nr_pages = nr_pages;
+		lpfd->ev_data->addr = addr;
 
-	if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages))
-		return -1;
+		return 0;
+	} else {
+		lpi = lpfd->ev_data->lpi;
+		nr_pages = lpfd->ev_data->nr_pages;
+		addr = lpfd->ev_data->addr;
 
-	return 0;
+		memset(lpfd->ev_data, 0, sizeof(*lpfd->ev_data));
+
+		if (receive_remote_pages(nr_pages * PAGE_SIZE, lpi->buf))
+			return -1;
+
+		if (uffd_copy(lpi, addr, nr_pages))
+			return -1;
+
+		if (update_lazy_iovecs(lpi, addr, PAGE_SIZE * nr_pages))
+			return -1;
+
+		return 0;
+	}
 }
 
+static struct sk_event_data sk_event_data;
+
 static struct lazy_pages_fd page_server_sk_fd = {
 	.event = page_server_event,
+	.ev_data = &sk_event_data,
 };
 
 static int prepare_page_server_socket(int epollfd)
-- 
1.9.1



More information about the CRIU mailing list