[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