[CRIU] [PATCH 1/2] lazy-pages: make the check for outstanding request more strict
Mike Rapoport
rppt at linux.vnet.ibm.com
Thu Jun 15 11:08:36 MSK 2017
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 at linux.vnet.ibm.com>
---
criu/uffd.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
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);
--
2.7.4
More information about the CRIU
mailing list