lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <94fcc32f-574a-4934-b7a9-1ed8bd32a97f@kernel.org>
Date: Mon, 17 Nov 2025 18:08:57 +0100
From: "David Hildenbrand (Red Hat)" <david@...nel.org>
To: Mike Rapoport <rppt@...nel.org>, linux-mm@...ck.org
Cc: Andrea Arcangeli <aarcange@...hat.com>,
 Andrew Morton <akpm@...ux-foundation.org>,
 Baolin Wang <baolin.wang@...ux.alibaba.com>, Hugh Dickins
 <hughd@...gle.com>, "Liam R. Howlett" <Liam.Howlett@...cle.com>,
 Lorenzo Stoakes <lorenzo.stoakes@...cle.com>, Michal Hocko
 <mhocko@...e.com>, Nikita Kalyazin <kalyazin@...zon.com>,
 Paolo Bonzini <pbonzini@...hat.com>, Peter Xu <peterx@...hat.com>,
 Sean Christopherson <seanjc@...gle.com>, Shuah Khan <shuah@...nel.org>,
 Suren Baghdasaryan <surenb@...gle.com>, Vlastimil Babka <vbabka@...e.cz>,
 linux-kernel@...r.kernel.org, kvm@...r.kernel.org,
 linux-kselftest@...r.kernel.org
Subject: Re: [RFC PATCH 2/4] userfaultfd, shmem: use a VMA callback to handle
 UFFDIO_CONTINUE

On 17.11.25 12:46, Mike Rapoport wrote:
> From: "Mike Rapoport (Microsoft)" <rppt@...nel.org>
> 
> When userspace resolves a page fault in a shmem VMA with UFFDIO_CONTINUE
> it needs to get a folio that already exists in the pagecache backing
> that VMA.
> 
> Instead of using shmem_get_folio() for that, add a get_pagecache_folio()
> method to 'struct vm_operations_struct' that will return a folio if it
> exists in the VMA's pagecache at given pgoff.
> 
> Implement get_pagecache_folio() method for shmem and slightly refactor
> userfaultfd's mfill_atomic() and mfill_atomic_pte_continue() to support
> this new API.
> 
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@...nel.org>
> ---
>   include/linux/mm.h |  9 +++++++
>   mm/shmem.c         | 20 ++++++++++++++++
>   mm/userfaultfd.c   | 60 ++++++++++++++++++++++++++++++----------------
>   3 files changed, 69 insertions(+), 20 deletions(-)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index d16b33bacc32..c35c1e1ac4dd 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -690,6 +690,15 @@ struct vm_operations_struct {
>   	struct page *(*find_normal_page)(struct vm_area_struct *vma,
>   					 unsigned long addr);
>   #endif /* CONFIG_FIND_NORMAL_PAGE */
> +#ifdef CONFIG_USERFAULTFD
> +	/*
> +	 * Called by userfault to resolve UFFDIO_CONTINUE request.
> +	 * Should return the folio found at pgoff in the VMA's pagecache if it
> +	 * exists or ERR_PTR otherwise.
> +	 */

What are the locking +refcount rules? Without looking at the code, I 
would assume we return with a folio reference held and the folio locked?

> +	struct folio *(*get_pagecache_folio)(struct vm_area_struct *vma,
> +					     pgoff_t pgoff);


The combination of VMA + pgoff looks weird at first. Would vma + addr or 
vma+vma_offset into vma be better?

But it also makes me wonder if the callback would ever even require the 
VMA, or actually only vma->vm_file?


Thinking out loud, I wonder if one could just call that "get_folio" or 
"get_shared_folio" (IOW, never an anon folio in a MAP_PRIVATE mapping).

> +#endif
>   };
>   
>   #ifdef CONFIG_NUMA_BALANCING
> diff --git a/mm/shmem.c b/mm/shmem.c
> index b9081b817d28..4ac122284bff 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3260,6 +3260,20 @@ int shmem_mfill_atomic_pte(pmd_t *dst_pmd,
>   	shmem_inode_unacct_blocks(inode, 1);
>   	return ret;
>   }
> +
> +static struct folio *shmem_get_pagecache_folio(struct vm_area_struct *vma,
> +					       pgoff_t pgoff)
> +{
> +	struct inode *inode = file_inode(vma->vm_file);
> +	struct folio *folio;
> +	int err;
> +
> +	err = shmem_get_folio(inode, pgoff, 0, &folio, SGP_NOALLOC);
> +	if (err)
> +		return ERR_PTR(err);
> +
> +	return folio;
> +}
>   #endif /* CONFIG_USERFAULTFD */
>   
>   #ifdef CONFIG_TMPFS
> @@ -5292,6 +5306,9 @@ static const struct vm_operations_struct shmem_vm_ops = {
>   	.set_policy     = shmem_set_policy,
>   	.get_policy     = shmem_get_policy,
>   #endif
> +#ifdef CONFIG_USERFAULTFD
> +	.get_pagecache_folio	= shmem_get_pagecache_folio,
> +#endif
>   };
>   
>   static const struct vm_operations_struct shmem_anon_vm_ops = {
> @@ -5301,6 +5318,9 @@ static const struct vm_operations_struct shmem_anon_vm_ops = {
>   	.set_policy     = shmem_set_policy,
>   	.get_policy     = shmem_get_policy,
>   #endif
> +#ifdef CONFIG_USERFAULTFD
> +	.get_pagecache_folio	= shmem_get_pagecache_folio,
> +#endif
>   };
>   
>   int shmem_init_fs_context(struct fs_context *fc)
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 8dc964389b0d..60b3183a72c0 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -382,21 +382,17 @@ static int mfill_atomic_pte_continue(pmd_t *dst_pmd,
>   				     unsigned long dst_addr,
>   				     uffd_flags_t flags)
>   {
> -	struct inode *inode = file_inode(dst_vma->vm_file);
>   	pgoff_t pgoff = linear_page_index(dst_vma, dst_addr);
>   	struct folio *folio;
>   	struct page *page;
>   	int ret;
>   
> -	ret = shmem_get_folio(inode, pgoff, 0, &folio, SGP_NOALLOC);
> +	folio = dst_vma->vm_ops->get_pagecache_folio(dst_vma, pgoff);
>   	/* Our caller expects us to return -EFAULT if we failed to find folio */
> -	if (ret == -ENOENT)
> -		ret = -EFAULT;
> -	if (ret)
> -		goto out;
> -	if (!folio) {
> -		ret = -EFAULT;
> -		goto out;
> +	if (IS_ERR_OR_NULL(folio)) {
> +		if (PTR_ERR(folio) == -ENOENT || !folio)
> +			return -EFAULT;
> +		return PTR_ERR(folio);
>   	}
>   
>   	page = folio_file_page(folio, pgoff);
> @@ -411,13 +407,12 @@ static int mfill_atomic_pte_continue(pmd_t *dst_pmd,
>   		goto out_release;
>   
>   	folio_unlock(folio);
> -	ret = 0;
> -out:
> -	return ret;
> +	return 0;
> +
>   out_release:
>   	folio_unlock(folio);
>   	folio_put(folio);
> -	goto out;
> +	return ret;
>   }
>   
>   /* Handles UFFDIO_POISON for all non-hugetlb VMAs. */
> @@ -694,6 +689,22 @@ static __always_inline ssize_t mfill_atomic_pte(pmd_t *dst_pmd,
>   	return err;
>   }
>   
> +static __always_inline bool vma_can_mfill_atomic(struct vm_area_struct *vma,
> +						 uffd_flags_t flags)
> +{
> +	if (uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) {
> +		if (vma->vm_ops && vma->vm_ops->get_pagecache_folio)
> +			return true;
> +		else
> +			return false;

Probably easier to read is

	return vma->vm_ops && vma->vm_ops->get_pagecache_folio;

> +	}
> +
> +	if (vma_is_anonymous(vma) || vma_is_shmem(vma))
> +		return true;
> +
> +	return false;


Could also be simplified to:

return vma_is_anonymous(vma) || vma_is_shmem(vma);


-- 
Cheers

David

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ