[CRIU] [RFC PATCH 05/12] lazy-pages: track outstanding page faults
Pavel Emelyanov
xemul at virtuozzo.com
Tue Jan 10 05:58:53 PST 2017
On 01/09/2017 11:23 AM, Mike Rapoport wrote:
> Multithreaded applications may concurrently generate page faults at the
> same address, which will cause creation of multiple requests for remote
> page, and, consequently, confuse the page server on the dump side.
> We can keep track on page fault requests in flight and ensure this way that
> we request a page from the remote side only once.
>
> Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
> ---
> criu/uffd.c | 31 +++++++++++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
>
> diff --git a/criu/uffd.c b/criu/uffd.c
> index 8c357b1..a5b990e 100644
> --- a/criu/uffd.c
> +++ b/criu/uffd.c
> @@ -55,10 +55,16 @@ struct lazy_iovec {
>
> struct lazy_pages_info;
>
> +struct pf_info {
> + unsigned long addr;
> + struct list_head l;
> +};
> +
> struct lazy_pages_info {
> int pid;
>
> struct list_head iovs;
> + struct list_head pfs;
>
> struct page_read pr;
>
> @@ -85,6 +91,7 @@ static struct lazy_pages_info *lpi_init(void)
>
> memset(lpi, 0, sizeof(*lpi));
> INIT_LIST_HEAD(&lpi->iovs);
> + INIT_LIST_HEAD(&lpi->pfs);
> INIT_LIST_HEAD(&lpi->l);
> lpi->lpfd.revent = handle_uffd_event;
>
> @@ -537,9 +544,19 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages)
>
> static int complete_page_fault(struct lazy_pages_info *lpi, unsigned long vaddr, int nr)
> {
> + struct pf_info *pf;
> +
> if (uffd_copy(lpi, vaddr, nr))
> return -1;
>
> + list_for_each_entry(pf, &lpi->pfs, l) {
> + if (pf->addr == vaddr) {
> + list_del(&pf->l);
> + xfree(pf);
> + break;
> + }
> + }
> +
> return update_lazy_iovecs(lpi, vaddr, nr * PAGE_SIZE);
> }
>
> @@ -635,6 +652,7 @@ static int handle_remaining_pages(struct lazy_pages_info *lpi)
>
> static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
> {
> + struct pf_info *pf;
> __u64 address;
> int ret;
>
> @@ -657,6 +675,16 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
> }
> #endif
>
> + list_for_each_entry(pf, &lpi->pfs, l)
> + if (pf->addr == address)
> + return 0;
> +
> + pf = xzalloc(sizeof(*pf));
> + if (!pf)
> + return -1;
> + pf->addr = address;
> + list_add(&pf->l, &lpi->pfs);
Shouldn't we instead __move__ the iovec from iovs list into pfs one? Splited
if being too big. This will allow us to make good asynchronous handling of
what's currently called "remaining pages" :)
-- Pavel
> +
> ret = uffd_handle_pages(lpi, address, 1, PR_ASYNC | PR_ASAP);
> if (ret < 0) {
> pr_err("Error during regular page copy\n");
> @@ -679,6 +707,9 @@ static int handle_uffd_event(struct epoll_rfd *lpfd)
> return 1;
>
> if (ret != sizeof(msg)) {
> + /* we've already handled the page fault for another thread */
> + if (errno == EAGAIN)
> + return 0;
> if (ret < 0)
> pr_perror("Can't read userfaultfd message");
> else
>
More information about the CRIU
mailing list