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 {
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,8 +941,7 @@ 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)
if (is_page_queued(lpi, address))
return 0;
iov = find_lazy_iov(lpi, address);
......@@ -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);
......
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