From 7c108b8b8db351c1940a9cde7019e7a67e093dc0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 16 Jun 2017 00:13:41 +0300 Subject: [PATCH] lazy-pages: make the check for outstanding request more strict 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 Acked-by: Pavel Emelyanov Signed-off-by: Andrei Vagin --- criu/uffd.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/criu/uffd.c b/criu/uffd.c index 205045e34..84fd07bfc 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);