[CRIU] [RFC PATCH 7/7] lazy-pages: implement semi-async remote page transfer

Mike Rapoport rppt at linux.vnet.ibm.com
Mon Nov 14 07:37:30 PST 2016


The synchronous remote page transfer prevents reception of uffd events
during the communications with the page server on the dump side. Adding
socket file descriptor to epoll_wait allows processing of incoming uffd
events after non-blocking request for remote page is issued and before the
dump side page server replies.

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

diff --git a/criu/uffd.c b/criu/uffd.c
index e4bf383..8efa69e 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -110,6 +110,25 @@ static void lpi_fini(struct lazy_pages_info *lpi)
 	free(lpi);
 }
 
+static struct lazy_pages_info *pid2lpi(int pid)
+{
+	struct lazy_pages_info *lpi;
+
+	list_for_each_entry(lpi, &lpis, l) {
+		if (lpi->pid == pid)
+			return lpi;
+	}
+
+	return NULL;
+}
+
+static int epoll_nr_fds(int nr_tasks)
+{
+       if (opts.use_page_server)
+               return nr_tasks + 1;
+       return nr_tasks;
+}
+
 static int prepare_sock_addr(struct sockaddr_un *saddr)
 {
 	int len;
@@ -637,24 +656,45 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi)
 	return 0;
 }
 
-static int handle_regular_pages(struct lazy_pages_info *lpi, __u64 address,
-				int nr)
+static int page_fault_common(struct lazy_pages_info *lpi, __u64 address, int nr,
+			     int pr_flags)
 {
-	int rc;
+	int ret;
 
-	rc = uffd_handle_pages(lpi, address, nr);
-	if (rc < 0) {
-		pr_err("Error during UFFD copy\n");
-		return -1;
+	ret = uffd_seek_or_zero_pages(lpi, address, nr);
+	if (ret <= 0)
+		return ret;
+
+	ret = lpi->pr.read_pages(&lpi->pr, address, nr, lpi->buf, pr_flags);
+	if (ret <= 0) {
+		pr_err("%d: failed reading pages at %llx\n", lpi->pid, address);
+		return ret;
 	}
 
-	rc = update_lazy_iovecs(lpi, address, PAGE_SIZE * nr);
-	if (rc < 0)
+	return 0;
+}
+
+static int page_fault_local(struct lazy_pages_info *lpi, __u64 address, int nr)
+{
+	if (page_fault_common(lpi, address, nr, 0))
+		return -1;
+
+	if (uffd_copy(lpi, address, nr))
+		return -1;
+
+	if (update_lazy_iovecs(lpi, address, PAGE_SIZE * nr))
 		return -1;
 
 	return 0;
 }
 
+static int page_fault_remote(struct lazy_pages_info *lpi, __u64 address, int nr)
+{
+	return page_fault_common(lpi, address, nr, PR_ASYNC);
+}
+
+static int (*pf_handler)(struct lazy_pages_info *lpi, __u64 address, int nr);
+
 static int handle_user_fault(struct lazy_pages_fd *lpfd)
 {
 	struct lazy_pages_info *lpi;
@@ -691,7 +731,7 @@ static int handle_user_fault(struct lazy_pages_fd *lpfd)
 	flags = msg.arg.pagefault.flags;
 	pr_debug("msg.arg.pagefault.flags 0x%llx\n", flags);
 
-	ret = handle_regular_pages(lpi, address, 1);
+	ret = pf_handler(lpi, address, 1);
 	if (ret < 0) {
 		pr_err("Error during regular page copy\n");
 		return -1;
@@ -719,7 +759,7 @@ static int lazy_pages_summary(struct lazy_pages_info *lpi)
 
 static int handle_requests(int epollfd, struct epoll_event *events)
 {
-	int nr_fds = task_entries->nr_tasks;
+	int nr_fds = epoll_nr_fds(task_entries->nr_tasks);
 	struct lazy_pages_info *lpi;
 	int ret = -1;
 	int i;
@@ -873,7 +913,36 @@ close_uffd:
 	return -1;
 }
 
-static int prepare_page_server_socket(void)
+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 = pid2lpi(pid);
+	if (!lpi)
+		return -1;
+
+	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 lazy_pages_fd page_server_sk_fd = {
+	.event = page_server_event,
+};
+
+static int prepare_page_server_socket(int epollfd)
 {
 	int sk;
 
@@ -881,13 +950,16 @@ static int prepare_page_server_socket(void)
 	if (sk < 0)
 		return -1;
 
-	return 0;
+	page_server_sk_fd.fd = sk;
+
+	return epoll_add_lpfd(epollfd, &page_server_sk_fd);
 }
 
 int cr_lazy_pages(bool daemon)
 {
 	struct epoll_event *events;
 	int epollfd;
+	int nr_fds;
 	int lazy_sk;
 	int ret;
 
@@ -921,15 +993,21 @@ int cr_lazy_pages(bool daemon)
 		}
 	}
 
-	epollfd = prepare_epoll(task_entries->nr_tasks, &events);
+	nr_fds = epoll_nr_fds(task_entries->nr_tasks);
+	epollfd = prepare_epoll(nr_fds, &events);
 	if (epollfd < 0)
 		return -1;
 
 	if (prepare_uffds(lazy_sk, epollfd))
 		return -1;
 
-	if (prepare_page_server_socket())
-		return -1;
+	if (opts.use_page_server) {
+		if (prepare_page_server_socket(epollfd))
+			return -1;
+		pf_handler = page_fault_remote;
+	} else {
+		pf_handler = page_fault_local;
+	}
 
 	ret = handle_requests(epollfd, events);
 
-- 
1.9.1



More information about the CRIU mailing list