* [PATCH V2 0/3] mm/hugetlb: fix mremap bugs
@ 2026-10-19 11:30 Li Zhe
2026-10-19 11:30 ` [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation Li Zhe
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Li Zhe @ 2026-10-19 11:30 UTC (permalink / raw)
To: muchun.song, osalvador, david, akpm, rppt, peterx
Cc: linux-mm, linux-kernel, Li Zhe
This series fixes a few hugetlb mremap bugs.
Patch 1 fixes the return type of move_hugetlb_page_tables(), so large
hugetlb moves cannot be truncated when reported back to the generic
mremap code.
Patch 2 disables hugetlb PMD sharing for UFFD missing mode, because
UFFDIO_POISON can install PTE markers that must not become shared PMD
page-table state.
Patch 3 fixes the recursive i_mmap_rwsem deadlock in the hugetlb mremap
path by avoiding the destination PMD sharing allocation path while the
mapping lock is already held for write.
David Hildenbrand (Arm) (1):
mm/hugetlb: disable PMD sharing for UFFD missing mode
Li Zhe (2):
mm/hugetlb: fix mremap move length truncation
mm/hugetlb: fix mremap deadlock when PMD sharing is possible
include/linux/hugetlb.h | 18 +++++------
include/linux/userfaultfd_k.h | 13 +++++---
mm/hugetlb.c | 56 ++++++++++++++++++++++++++---------
3 files changed, 60 insertions(+), 27 deletions(-)
---
v1: https://lore.kernel.org/all/20260930064308.58159-1-lizhe.67@bytedance.com/
ChangeLogs:
v1->v2:
- Add a fix for the newly discovered move_hugetlb_page_tables()
return type issue.
- Disable hugetlb PMD sharing for UFFD missing mode.
- Rework the mremap deadlock fix to zap the source range and let the
destination fault path populate or share the PMD lazily, as suggested
by David.
--
2.20.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation
2026-10-19 11:30 [PATCH V2 0/3] mm/hugetlb: fix mremap bugs Li Zhe
@ 2026-10-19 11:30 ` Li Zhe
2026-10-20 8:18 ` David Hildenbrand (Arm)
2026-10-19 11:30 ` [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode Li Zhe
2026-10-19 11:30 ` [PATCH V2 3/3] mm/hugetlb: fix mremap deadlock when PMD sharing is possible Li Zhe
2 siblings, 1 reply; 7+ messages in thread
From: Li Zhe @ 2026-10-19 11:30 UTC (permalink / raw)
To: muchun.song, osalvador, david, akpm, rppt, peterx
Cc: linux-mm, linux-kernel, Li Zhe
move_hugetlb_page_tables() returns the number of bytes moved, but
its return type is int while the generic move_page_tables() path uses
unsigned long lengths.
A hugetlb mremap() move length above INT_MAX can therefore be
misreported to copy_vma_and_data(). The out-of-range conversion to int
is implementation-defined; on common 64-bit builds, for example, a
4 GiB move can be reported as zero, making the caller treat the move as
a failure and use the wrong length for rollback.
Return unsigned long from move_hugetlb_page_tables(), matching
move_page_tables() and preserving the full byte count.
Fixes: 550a7d60bd5e ("mm, hugepages: add mremap() support for hugepage backed vma")
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
---
include/linux/hugetlb.h | 18 +++++++++---------
mm/hugetlb.c | 8 ++++----
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 16c4c4caa126..cc12040e4032 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -121,10 +121,10 @@ void hugepage_put_subpool(struct hugepage_subpool *spool);
void hugetlb_dup_vma_private(struct vm_area_struct *vma);
void clear_vma_resv_huge_pages(struct vm_area_struct *vma);
-int move_hugetlb_page_tables(struct vm_area_struct *vma,
- struct vm_area_struct *new_vma,
- unsigned long old_addr, unsigned long new_addr,
- unsigned long len);
+unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
+ struct vm_area_struct *new_vma,
+ unsigned long old_addr, unsigned long new_addr,
+ unsigned long len);
int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *,
struct vm_area_struct *, struct vm_area_struct *);
void unmap_hugepage_range(struct vm_area_struct *,
@@ -339,11 +339,11 @@ static inline int copy_hugetlb_page_range(struct mm_struct *dst,
return 0;
}
-static inline int move_hugetlb_page_tables(struct vm_area_struct *vma,
- struct vm_area_struct *new_vma,
- unsigned long old_addr,
- unsigned long new_addr,
- unsigned long len)
+static inline unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
+ struct vm_area_struct *new_vma,
+ unsigned long old_addr,
+ unsigned long new_addr,
+ unsigned long len)
{
BUG();
return 0;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index cea25773a6c9..2c64ca985dfa 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5139,10 +5139,10 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
spin_unlock(dst_ptl);
}
-int move_hugetlb_page_tables(struct vm_area_struct *vma,
- struct vm_area_struct *new_vma,
- unsigned long old_addr, unsigned long new_addr,
- unsigned long len)
+unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
+ struct vm_area_struct *new_vma,
+ unsigned long old_addr, unsigned long new_addr,
+ unsigned long len)
{
struct hstate *h = hstate_vma(vma);
struct address_space *mapping = vma->vm_file->f_mapping;
--
2.20.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode
2026-10-19 11:30 [PATCH V2 0/3] mm/hugetlb: fix mremap bugs Li Zhe
2026-10-19 11:30 ` [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation Li Zhe
@ 2026-10-19 11:30 ` Li Zhe
2026-10-20 10:11 ` Mike Rapoport
2026-10-19 11:30 ` [PATCH V2 3/3] mm/hugetlb: fix mremap deadlock when PMD sharing is possible Li Zhe
2 siblings, 1 reply; 7+ messages in thread
From: Li Zhe @ 2026-10-19 11:30 UTC (permalink / raw)
To: muchun.song, osalvador, david, akpm, rppt, peterx
Cc: linux-mm, linux-kernel, Li Zhe
From: "David Hildenbrand (Arm)" <david@kernel.org>
For UFFDIO_POISON to install a poison marker in a hugetlb mapping, it is
sufficient to have the VMA registered for missing mode.
However, UFFD missing mode does currently not block PMD table sharing, so
installing the marker will be visible to everyone using the shared PMD
table, which is wrong as UFFDIO_POISON must stay local to the process.
To fix it, include VM_UFFD_MISSING in uffd_disable_huge_pmd_share(). Add
a debug check on the marker installation path.
The existing registration path will then unshare PMD tables, and
subsequent faults will not share them while the mapping remains
registered.
The alternative would be to unshare PMD tables selectively when
installing poison markers, which results in way more complexity. Or
alternatively, simply failing the marker installation, which might break
some use cases.
This effectively disables PMD sharing for missing-mode registrations
that never use UFFDIO_POISON.
Suggested-by: Li Zhe <lizhe.67@bytedance.com>
Fixes: 8a13897fb0da ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
---
include/linux/userfaultfd_k.h | 13 +++++++++----
mm/hugetlb.c | 1 +
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index a4351cffc60c..fe78ba14dc68 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -169,7 +169,10 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
}
/*
- * Never enable huge pmd sharing on some uffd registered vmas:
+ * Never enable huge pmd sharing on the following VMAs:
+ *
+ * - VM_UFFD_MISSING VMAs, because UFFDIO_POISON may install markers and we
+ * want PMD tables to be unshared when installing these markers already.
*
* - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
* tracking information is per pgtable entry.
@@ -182,9 +185,11 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
*/
static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma,
- mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
- VMA_UFFD_MINOR));
+ const vma_flags_t uffd_flags =
+ mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP,
+ VMA_UFFD_RWP, VMA_UFFD_MINOR);
+
+ return vma_test_any_mask(vma, uffd_flags);
}
/*
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 2c64ca985dfa..fdd65e019a55 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -6304,6 +6304,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
return -EEXIST;
}
+ VM_WARN_ON_ONCE(size == PMD_SIZE && hugetlb_pmd_shared(dst_pte));
_dst_pte = make_pte_marker(PTE_MARKER_POISONED);
set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte, size);
--
2.20.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH V2 3/3] mm/hugetlb: fix mremap deadlock when PMD sharing is possible
2026-10-19 11:30 [PATCH V2 0/3] mm/hugetlb: fix mremap bugs Li Zhe
2026-10-19 11:30 ` [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation Li Zhe
2026-10-19 11:30 ` [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode Li Zhe
@ 2026-10-19 11:30 ` Li Zhe
2 siblings, 0 replies; 7+ messages in thread
From: Li Zhe @ 2026-10-19 11:30 UTC (permalink / raw)
To: muchun.song, osalvador, david, akpm, rppt, peterx
Cc: linux-mm, linux-kernel, Li Zhe, stable
move_hugetlb_page_tables() holds the mapping's i_mmap_rwsem for
write while moving hugetlb PTEs. This prevents races with truncation
and protects huge_pmd_unshare(), but the move loop must not call
helpers that can acquire the same rwsem for read.
huge_pte_alloc() can do that when the destination can use PMD
sharing: it may call huge_pmd_share(), which takes i_mmap_rwsem for
read while searching for a shareable PMD table. Calling it while the
move path already holds i_mmap_rwsem for write can deadlock.
Avoid that path for PMD-sized hugetlb mappings that can use PMD
sharing. Instead of allocating or sharing the destination page table
while moving, zap the source range and let the destination fault path
populate or share the PMD lazily.
Reuse the hugetlb unmap logic for the source-side zap by splitting
the core loop out of __unmap_hugepage_range(). The wrapper keeps the
existing tlb_start_vma(), tlb_end_vma() and huge_pmd_unshare_flush()
behavior, while move_hugetlb_page_tables() can reuse the unmap loop
with its existing mmu_gather.
Fixes: 550a7d60bd5e ("mm, hugepages: add mremap() support for hugepage backed vma")
Cc: stable@vger.kernel.org
Co-developed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
---
mm/hugetlb.c | 47 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index fdd65e019a55..46a2a9b9222b 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -124,6 +124,10 @@ static int __huge_pmd_unshare(struct mmu_gather *tlb,
bool check_locks);
static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
unsigned long start, unsigned long end, bool take_locks);
+static void hugetlb_unmap_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, struct folio *folio,
+ zap_flags_t zap_flags);
static struct resv_map *vma_resv_map(struct vm_area_struct *vma);
static inline bool subpool_is_free(struct hugepage_subpool *spool)
@@ -5172,6 +5176,8 @@ unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
for (; old_addr < old_end; old_addr += sz, new_addr += sz) {
const unsigned long offset_to_last_entry =
(old_addr | last_addr_mask) - old_addr;
+ const unsigned long offset_to_last_dst_entry =
+ (new_addr | last_addr_mask) - new_addr;
src_pte = hugetlb_walk(vma, old_addr, sz);
if (!src_pte) {
@@ -5188,6 +5194,24 @@ unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
continue;
}
+ /*
+ * Avoid entering the destination PMD sharing path while holding
+ * i_mmap_rwsem for write. Leave destination page table
+ * population to the fault path, which can share the PMD lazily.
+ */
+ if (sz == PMD_SIZE && want_pmd_share(new_vma, new_addr)) {
+ const unsigned long unmap_size =
+ min(old_end - old_addr,
+ offset_to_last_dst_entry + sz);
+
+ hugetlb_unmap_range(&tlb, vma, old_addr,
+ old_addr + unmap_size, NULL,
+ ZAP_FLAG_DROP_MARKER);
+ old_addr += unmap_size - sz;
+ new_addr += unmap_size - sz;
+ continue;
+ }
+
dst_pte = huge_pte_alloc(mm, new_vma, new_addr, sz);
if (!dst_pte)
break;
@@ -5207,9 +5231,10 @@ unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
return len + old_addr - old_end;
}
-void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
- unsigned long start, unsigned long end,
- struct folio *folio, zap_flags_t zap_flags)
+static void hugetlb_unmap_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, struct folio *folio,
+ zap_flags_t zap_flags)
{
struct mm_struct *mm = vma->vm_mm;
const bool folio_provided = !!folio;
@@ -5227,13 +5252,6 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
BUG_ON(start & ~huge_page_mask(h));
BUG_ON(end & ~huge_page_mask(h));
- /*
- * This is a hugetlb vma, all the pte entries should point
- * to huge page.
- */
- tlb_change_page_size(tlb, sz);
- tlb_start_vma(tlb, vma);
-
last_addr_mask = hugetlb_mask_last_page(h);
address = start;
for (; address < end; address += sz) {
@@ -5362,6 +5380,15 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
if (folio_provided)
break;
}
+}
+
+void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end,
+ struct folio *folio, zap_flags_t zap_flags)
+{
+ tlb_change_page_size(tlb, huge_page_size(hstate_vma(vma)));
+ tlb_start_vma(tlb, vma);
+ hugetlb_unmap_range(tlb, vma, start, end, folio, zap_flags);
tlb_end_vma(tlb, vma);
huge_pmd_unshare_flush(tlb, vma);
--
2.20.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation
2026-10-19 11:30 ` [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation Li Zhe
@ 2026-10-20 8:18 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 7+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-20 8:18 UTC (permalink / raw)
To: Li Zhe, muchun.song, osalvador, akpm, rppt, peterx; +Cc: linux-mm, linux-kernel
On 10/19/26 13:30, Li Zhe wrote:
> move_hugetlb_page_tables() returns the number of bytes moved, but
> its return type is int while the generic move_page_tables() path uses
> unsigned long lengths.
>
> A hugetlb mremap() move length above INT_MAX can therefore be
> misreported to copy_vma_and_data(). The out-of-range conversion to int
> is implementation-defined; on common 64-bit builds, for example, a
> 4 GiB move can be reported as zero, making the caller treat the move as
> a failure and use the wrong length for rollback.
Sounds like we want to CC stable here, right?
>
> Return unsigned long from move_hugetlb_page_tables(), matching
> move_page_tables() and preserving the full byte count.
>
> Fixes: 550a7d60bd5e ("mm, hugepages: add mremap() support for hugepage backed vma")
> Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
> ---
> include/linux/hugetlb.h | 18 +++++++++---------
> mm/hugetlb.c | 8 ++++----
> 2 files changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 16c4c4caa126..cc12040e4032 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -121,10 +121,10 @@ void hugepage_put_subpool(struct hugepage_subpool *spool);
>
> void hugetlb_dup_vma_private(struct vm_area_struct *vma);
> void clear_vma_resv_huge_pages(struct vm_area_struct *vma);
> -int move_hugetlb_page_tables(struct vm_area_struct *vma,
> - struct vm_area_struct *new_vma,
> - unsigned long old_addr, unsigned long new_addr,
> - unsigned long len);
> +unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
> + struct vm_area_struct *new_vma,
> + unsigned long old_addr, unsigned long new_addr,
> + unsigned long len);
While at it, can you convert all these to use double tab indent instead?
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode
2026-10-19 11:30 ` [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode Li Zhe
@ 2026-10-20 10:11 ` Mike Rapoport
2026-10-20 10:33 ` David Hildenbrand (Arm)
0 siblings, 1 reply; 7+ messages in thread
From: Mike Rapoport @ 2026-10-20 10:11 UTC (permalink / raw)
To: Li Zhe; +Cc: muchun.song, osalvador, david, akpm, peterx, linux-mm,
linux-kernel
On Mon, Oct 19, 2026 at 07:30:33PM +0800, Li Zhe wrote:
> From: "David Hildenbrand (Arm)" <david@kernel.org>
>
> For UFFDIO_POISON to install a poison marker in a hugetlb mapping, it is
> sufficient to have the VMA registered for missing mode.
>
> However, UFFD missing mode does currently not block PMD table sharing, so
> installing the marker will be visible to everyone using the shared PMD
> table, which is wrong as UFFDIO_POISON must stay local to the process.
>
> To fix it, include VM_UFFD_MISSING in uffd_disable_huge_pmd_share(). Add
> a debug check on the marker installation path.
>
> The existing registration path will then unshare PMD tables, and
> subsequent faults will not share them while the mapping remains
> registered.
>
> The alternative would be to unshare PMD tables selectively when
> installing poison markers, which results in way more complexity. Or
> alternatively, simply failing the marker installation, which might break
> some use cases.
>
> This effectively disables PMD sharing for missing-mode registrations
> that never use UFFDIO_POISON.
>
> Suggested-by: Li Zhe <lizhe.67@bytedance.com>
> Fixes: 8a13897fb0da ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs")
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
> ---
> include/linux/userfaultfd_k.h | 13 +++++++++----
> mm/hugetlb.c | 1 +
> 2 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index a4351cffc60c..fe78ba14dc68 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -169,7 +169,10 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> }
>
> /*
> - * Never enable huge pmd sharing on some uffd registered vmas:
> + * Never enable huge pmd sharing on the following VMAs:
> + *
> + * - VM_UFFD_MISSING VMAs, because UFFDIO_POISON may install markers and we
> + * want PMD tables to be unshared when installing these markers already.
> *
> * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
> * tracking information is per pgtable entry.
> @@ -182,9 +185,11 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> */
> static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> {
> - return vma_test_any_mask(vma,
> - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
> - VMA_UFFD_MINOR));
> + const vma_flags_t uffd_flags =
> + mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP,
> + VMA_UFFD_RWP, VMA_UFFD_MINOR);
Since this essentially disable pmd sharing for any uffd mode, maybe replace
the flags check with the check for non-NULL userfaultfd_ctx?
> +
> + return vma_test_any_mask(vma, uffd_flags);
> }
>
> /*
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 2c64ca985dfa..fdd65e019a55 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -6304,6 +6304,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
> return -EEXIST;
> }
>
> + VM_WARN_ON_ONCE(size == PMD_SIZE && hugetlb_pmd_shared(dst_pte));
> _dst_pte = make_pte_marker(PTE_MARKER_POISONED);
> set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte, size);
>
> --
> 2.20.1
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode
2026-10-20 10:11 ` Mike Rapoport
@ 2026-10-20 10:33 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 7+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-20 10:33 UTC (permalink / raw)
To: Mike Rapoport, Li Zhe
Cc: muchun.song, osalvador, akpm, peterx, linux-mm, linux-kernel
On 10/20/26 12:11, Mike Rapoport wrote:
> On Mon, Oct 19, 2026 at 07:30:33PM +0800, Li Zhe wrote:
>> From: "David Hildenbrand (Arm)" <david@kernel.org>
>>
>> For UFFDIO_POISON to install a poison marker in a hugetlb mapping, it is
>> sufficient to have the VMA registered for missing mode.
>>
>> However, UFFD missing mode does currently not block PMD table sharing, so
>> installing the marker will be visible to everyone using the shared PMD
>> table, which is wrong as UFFDIO_POISON must stay local to the process.
>>
>> To fix it, include VM_UFFD_MISSING in uffd_disable_huge_pmd_share(). Add
>> a debug check on the marker installation path.
>>
>> The existing registration path will then unshare PMD tables, and
>> subsequent faults will not share them while the mapping remains
>> registered.
>>
>> The alternative would be to unshare PMD tables selectively when
>> installing poison markers, which results in way more complexity. Or
>> alternatively, simply failing the marker installation, which might break
>> some use cases.
>>
>> This effectively disables PMD sharing for missing-mode registrations
>> that never use UFFDIO_POISON.
>>
>> Suggested-by: Li Zhe <lizhe.67@bytedance.com>
>> Fixes: 8a13897fb0da ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs")
>> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
>> Signed-off-by: Li Zhe <lizhe.67@bytedance.com>
>> ---
>> include/linux/userfaultfd_k.h | 13 +++++++++----
>> mm/hugetlb.c | 1 +
>> 2 files changed, 10 insertions(+), 4 deletions(-)
>>
>> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
>> index a4351cffc60c..fe78ba14dc68 100644
>> --- a/include/linux/userfaultfd_k.h
>> +++ b/include/linux/userfaultfd_k.h
>> @@ -169,7 +169,10 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
>> }
>>
>> /*
>> - * Never enable huge pmd sharing on some uffd registered vmas:
>> + * Never enable huge pmd sharing on the following VMAs:
>> + *
>> + * - VM_UFFD_MISSING VMAs, because UFFDIO_POISON may install markers and we
>> + * want PMD tables to be unshared when installing these markers already.
>> *
>> * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
>> * tracking information is per pgtable entry.
>> @@ -182,9 +185,11 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
>> */
>> static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
>> {
>> - return vma_test_any_mask(vma,
>> - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
>> - VMA_UFFD_MINOR));
>> + const vma_flags_t uffd_flags =
>> + mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP,
>> + VMA_UFFD_RWP, VMA_UFFD_MINOR);
>
> Since this essentially disable pmd sharing for any uffd mode, maybe replace
> the flags check with the check for non-NULL userfaultfd_ctx?
That would likely even better and we can just simplify the comments as well.
--
Cheers,
David
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-20 10:33 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 11:30 [PATCH V2 0/3] mm/hugetlb: fix mremap bugs Li Zhe
2026-10-19 11:30 ` [PATCH V2 1/3] mm/hugetlb: fix mremap move length truncation Li Zhe
2026-10-20 8:18 ` David Hildenbrand (Arm)
2026-10-19 11:30 ` [PATCH V2 2/3] mm/hugetlb: disable PMD sharing for UFFD missing mode Li Zhe
2026-10-20 10:11 ` Mike Rapoport
2026-10-20 10:33 ` David Hildenbrand (Arm)
2026-10-19 11:30 ` [PATCH V2 3/3] mm/hugetlb: fix mremap deadlock when PMD sharing is possible Li Zhe
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.