[1/2] lazy-pages: make the check for outstanding request more strict

Submitted by Mike Rapoport on June 15, 2017, 4 p.m.

Details

Message ID 1497542434-28806-2-git-send-email-rppt@linux.vnet.ibm.com
State New
Series "lazy-pages: handle_remaining_pages: enable asynchronous reads"
Headers show

Commit Message

Mike Rapoport June 15, 2017, 4 p.m.
There could be several outstaning requests for the same page, either from
page fault handler or from handle_remaining_pages. Verifying that the
faulting address is already requested is not enough. We need to check if
there any request in flight that covers the faulting address.

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

Patch hide | download patch | download mbox

diff --git a/criu/uffd.c b/criu/uffd.c
index 205045e..84fd07b 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -68,6 +68,7 @@  struct lazy_iov {
 struct lp_req {
 	unsigned long addr;	/* actual #PF (or background) destination */
 	unsigned long img_addr;	/* the corresponding address at the dump time */
+	unsigned long len;
 	struct list_head l;
 };
 
@@ -817,6 +818,7 @@  static int handle_remaining_pages(struct lazy_pages_info *lpi)
 
 	req->addr = iov->base;
 	req->img_addr = iov->img_base;
+	req->len = iov->len;
 	list_add(&req->l, &lpi->reqs);
 
 	err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0);
@@ -917,6 +919,17 @@  static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds)
 	return 0;
 }
 
+static bool is_page_queued(struct lazy_pages_info *lpi, unsigned long addr)
+{
+	struct lp_req *req;
+
+	list_for_each_entry(req, &lpi->reqs, l)
+		if (addr >= req->addr && addr < req->addr + req->len)
+			return true;
+
+	return false;
+}
+
 static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
 {
 	struct lp_req *req;
@@ -928,9 +941,8 @@  static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
 	address = msg->arg.pagefault.address & ~(page_size() - 1);
 	lp_debug(lpi, "#PF at 0x%llx\n", address);
 
-	list_for_each_entry(req, &lpi->reqs, l)
-		if (req->addr == address)
-			return 0;
+	if (is_page_queued(lpi, address))
+		return 0;
 
 	iov = find_lazy_iov(lpi, address);
 	if (!iov)
@@ -941,6 +953,7 @@  static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
 		return -1;
 	req->addr = address;
 	req->img_addr = iov->img_base + (address - iov->base);
+	req->len = PAGE_SIZE;
 	list_add(&req->l, &lpi->reqs);
 
 	ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP);