Commit 7c108b8b authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

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: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 9354582f
...@@ -68,6 +68,7 @@ struct lazy_iov { ...@@ -68,6 +68,7 @@ struct lazy_iov {
struct lp_req { struct lp_req {
unsigned long addr; /* actual #PF (or background) destination */ unsigned long addr; /* actual #PF (or background) destination */
unsigned long img_addr; /* the corresponding address at the dump time */ unsigned long img_addr; /* the corresponding address at the dump time */
unsigned long len;
struct list_head l; struct list_head l;
}; };
...@@ -817,6 +818,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi) ...@@ -817,6 +818,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi)
req->addr = iov->base; req->addr = iov->base;
req->img_addr = iov->img_base; req->img_addr = iov->img_base;
req->len = iov->len;
list_add(&req->l, &lpi->reqs); list_add(&req->l, &lpi->reqs);
err = uffd_handle_pages(lpi, req->img_addr, nr_pages, 0); 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) ...@@ -917,6 +919,17 @@ static int complete_forks(int epollfd, struct epoll_event **events, int *nr_fds)
return 0; 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) static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
{ {
struct lp_req *req; struct lp_req *req;
...@@ -928,9 +941,8 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) ...@@ -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); address = msg->arg.pagefault.address & ~(page_size() - 1);
lp_debug(lpi, "#PF at 0x%llx\n", address); lp_debug(lpi, "#PF at 0x%llx\n", address);
list_for_each_entry(req, &lpi->reqs, l) if (is_page_queued(lpi, address))
if (req->addr == address) return 0;
return 0;
iov = find_lazy_iov(lpi, address); iov = find_lazy_iov(lpi, address);
if (!iov) if (!iov)
...@@ -941,6 +953,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg) ...@@ -941,6 +953,7 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
return -1; return -1;
req->addr = address; req->addr = address;
req->img_addr = iov->img_base + (address - iov->base); req->img_addr = iov->img_base + (address - iov->base);
req->len = PAGE_SIZE;
list_add(&req->l, &lpi->reqs); list_add(&req->l, &lpi->reqs);
ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP); ret = uffd_handle_pages(lpi, req->img_addr, 1, PR_ASYNC | PR_ASAP);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment