All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] mm/mremap: fix accounting on a partial move
@ 2026-11-02 23:45 Josef Bacik
  2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:45 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, stable,
	Josef Bacik

v1: https://lore.kernel.org/all/20261030-b4-mremap-pre-split-v1-0-c1829811aed0@toxicpanda.com/

v1->v2:
- Dropped "mm/mremap: split first so a failed split is reported".  Every failure
  now left an unwanted split, for a benefit that only a doomed process would see
  (Lorenzo, Jose).  This is also why the series has a new subject.
- Patch 4: added vma_range_set_account() and used it on the success path too,
  shortened the comment, spelled the flag VMA_ACCOUNT_BIT in the subject and
  message (Lorenzo).
- Patch 1: dropped the comment above split_source_stays() (Lorenzo).
- Picked up the tags on patches 1, 2, 3 and 5.

--- Original email (v1) ---

Hello,

I went through the callers of __split_vma() to see who can't cope with
it failing, and mremap() is the bad one.  If you move part of a VMA we
don't split it until the very end, when we unmap the old range.  By then
the page tables have moved and there's nothing to go back to, so we fix
up the accounting and return success with the old range still mapped.

Lorenzo recently added a way to split ahead of the move for the mlock()
+ MREMAP_DONTUNMAP case.  This series uses that for every move that
unmaps its source, so a split that fails is reported before we've done
anything.

Doing that turned up a real bug in hugetlb.  We take the reservation map
away from the whole old VMA before the part that's moving is split off,
so the parts that stay never give their reservations back.  That fix is
the first patch so it can go to stable by itself, and the second patch
is a selftest for it.

The next two fix the accounting for when the unmap at the end does fail,
we either charged memory that was never accounted or lost track of the
charge for the whole VMA.  That gets a lot harder to hit with the last
patch but it's still possible.  There's also a test for an old size of
0, which nothing covered.

I tested this with the mm selftests and with a loop that fails each
allocation inside mremap() in turn and checks that we either moved or
didn't.  The numbers for moving part of a mapping don't change.  Thanks,

Josef

---
Changes in v2:
- Link to v1: https://patch.msgid.link/20261030-b4-mremap-pre-split-v1-0-c1829811aed0@toxicpanda.com

---
Josef Bacik (5):
      mm/mremap: fix hugetlb reservation leak on partial move
      selftests/mm: test a partial mremap() of hugetlb memory
      mm/mremap: reaccount on unmap failure only if accounted
      mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails
      selftests/mm: test mremap() with an old size of 0

 mm/mremap.c                                 | 69 ++++++++++++++++-------------
 tools/testing/selftests/mm/hugetlb-mremap.c | 52 +++++++++++++++++++++-
 tools/testing/selftests/mm/mremap_test.c    | 52 +++++++++++++++++++++-
 3 files changed, 139 insertions(+), 34 deletions(-)
---
base-commit: a792d9193312d7cd897391d99e4a57b25772c099
change-id: 20261030-b4-mremap-pre-split-13a3d54d6dbd



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on partial move
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
@ 2026-11-02 23:45 ` Josef Bacik
  2026-11-03 10:42   ` Jose A. Perez de Azpillaga
  2026-11-02 23:45 ` [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory Josef Bacik
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:45 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, stable,
	Josef Bacik

Moving a part of a private hugetlb mapping with mremap() leaks the huge
page reservations of the parts that stay. They are not returned when the
mapping is unmapped, when the process exits or when the pool is resized.

fixup_hugetlb_reservations() takes the reservation map away from the old
VMA while that VMA still spans its whole range, because the moved part is
only split off by the unmap at the end of the move. hugetlb_vm_op_close()
then finds no map in the parts that remain and returns nothing for them:

    mmap() of 4 pages, MAP_PRIVATE | MAP_HUGETLB    HugePages_Rsvd: 4
    mremap() of the second page to a new address    HugePages_Rsvd: 4
    munmap() of all of it                           HugePages_Rsvd: 3

The source is unmapped in this case, so the number of VMAs ends up where it
did before and the check against sysctl_max_map_count stays as it is.

Fix by splitting a hugetlb VMA in prep_move_vma() before a part of it is
moved, as commit 597e4b9ab48a ("mm/mremap: fix locked_vm leak by splitting
VMA for MREMAP_DONTUNMAP") does for an mlock()'d VMA. A backport needs that
commit, which is tagged for stable itself.

Fixes: 550a7d60bd5e ("mm, hugepages: add mremap() support for hugepage backed vma")
Cc: <stable@vger.kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 mm/mremap.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 0d06d7f37f19..5926ecdb31e9 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1038,7 +1038,7 @@ static void vrm_stat_account(struct vma_remap_struct *vrm,
 }
 
 static bool __check_map_count_against_split(struct mm_struct *mm,
-					    bool pre_split,
+					    bool source_stays,
 					    bool before_unmaps)
 {
 	const int sys_map_count = get_sysctl_max_map_count();
@@ -1092,14 +1092,14 @@ static bool __check_map_count_against_split(struct mm_struct *mm,
 	 */
 	map_count += 2;
 
-	/* If pre-split, the -1 observed above doesn't apply. */
-	if (pre_split)
+	/* If the split off source stays, the -1 observed above doesn't apply. */
+	if (source_stays)
 		map_count++;
 
 	return map_count <= sys_map_count;
 }
 
-static bool needs_pre_split(struct vma_remap_struct *vrm)
+static bool split_source_stays(struct vma_remap_struct *vrm)
 {
 	/*
 	 * An MREMAP_DONTUNMAP of a mlock()'d VMA needs to unlock the
@@ -1109,11 +1109,23 @@ static bool needs_pre_split(struct vma_remap_struct *vrm)
 		vma_test(vrm->vma, VMA_LOCKED_BIT);
 }
 
+static bool needs_pre_split(struct vma_remap_struct *vrm)
+{
+	/*
+	 * fixup_hugetlb_reservations() takes the reservations away from the
+	 * source VMA.  The parts of it that do not move have to keep theirs.
+	 */
+	if (vma_is_hugetlb(vrm->vma))
+		return true;
+
+	return split_source_stays(vrm);
+}
+
 /* Do we violate the map count limit if we split VMAs when moving the VMA? */
 static bool check_map_count_against_split(struct vma_remap_struct *vrm)
 {
 	return __check_map_count_against_split(current->mm,
-		needs_pre_split(vrm), /*before_unmaps=*/false);
+		split_source_stays(vrm), /*before_unmaps=*/false);
 }
 
 /* Do we violate the map count limit if we split VMAs prior to early unmaps? */
@@ -1162,10 +1174,7 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
 	if (err)
 		return err;
 
-	/*
-	 * To account mlock()'d pages correctly in the MREMAP_DONTUNMAP
-	 * case perform any split ahead of time for an mlock()'d VMA.
-	 */
+	/* Perform any split ahead of time if the source VMA has to be distinct. */
 	if (needs_pre_split(vrm)) {
 		VMA_ITERATOR(vmi, vma->vm_mm, old_addr);
 

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
  2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
@ 2026-11-02 23:45 ` Josef Bacik
  2026-11-03 10:48   ` Jose A. Perez de Azpillaga
  2026-11-02 23:45 ` [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted Josef Bacik
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:45 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, Josef Bacik

hugetlb-mremap only moves whole mappings, so it did not catch the
reservation leak of a partial move.

Map four private huge pages without touching them, move the second one,
unmap everything, and check that the number of reserved huge pages is back
where it was.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 tools/testing/selftests/mm/hugetlb-mremap.c | 52 +++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/mm/hugetlb-mremap.c b/tools/testing/selftests/mm/hugetlb-mremap.c
index 9b724af66e93..9f9d6905cd6d 100644
--- a/tools/testing/selftests/mm/hugetlb-mremap.c
+++ b/tools/testing/selftests/mm/hugetlb-mremap.c
@@ -95,6 +95,51 @@ static void register_region_with_uffd(char *addr, size_t len)
 	ksft_print_msg("Registered memory at address %p with userfaultfd\n", addr);
 }
 
+/*
+ * Move one page out of the middle of a private mapping that has not been
+ * touched, so that every page of it still holds its reservation.  Once all of
+ * it is unmapped, all of the reservations have to be back in the pool.
+ */
+static void test_partial_move(unsigned long hugepage_size)
+{
+	const int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB;
+	const int prot = PROT_READ | PROT_WRITE;
+	const unsigned long nr = 4;
+	unsigned long resv = hugetlb_nr_resv_pages(hugepage_size);
+	unsigned long resv_after;
+	char *src, *dst, *addr;
+
+	/* The pages of the test before this one can still be in use. */
+	if (!hugetlb_setup_default(resv + nr + 1)) {
+		ksft_test_result_skip("Partial move: not enough free huge pages\n");
+		return;
+	}
+
+	src = mmap(NULL, nr * hugepage_size, prot, flags, -1, 0);
+	if (src == MAP_FAILED)
+		ksft_exit_fail_msg("mmap src: %s\n", strerror(errno));
+
+	/* The destination has to be hugetlb-backed, mremap() replaces it. */
+	dst = mmap(NULL, hugepage_size, prot, flags, -1, 0);
+	if (dst == MAP_FAILED)
+		ksft_exit_fail_msg("mmap dst: %s\n", strerror(errno));
+
+	addr = mremap(src + hugepage_size, hugepage_size, hugepage_size,
+		      MREMAP_MAYMOVE | MREMAP_FIXED, dst);
+	if (addr == MAP_FAILED)
+		ksft_exit_fail_msg("partial mremap: %s\n", strerror(errno));
+
+	munmap(addr, hugepage_size);
+	munmap(src, nr * hugepage_size);
+
+	resv_after = hugetlb_nr_resv_pages(hugepage_size);
+	if (resv_after != resv)
+		ksft_print_msg("Reserved huge pages: %lu before, %lu after\n",
+			       resv, resv_after);
+	ksft_test_result(resv_after == resv,
+			 "Partial move returns all reservations\n");
+}
+
 int main(int argc, char *argv[])
 {
 	unsigned long hugepage_size;
@@ -102,7 +147,7 @@ int main(int argc, char *argv[])
 	size_t length = 0;
 
 	ksft_print_header();
-	ksft_set_plan(1);
+	ksft_set_plan(2);
 
 	if (argc >= 2 && !strcmp(argv[1], "-h"))
 		ksft_exit_fail_msg("Usage: %s [length_in_MB]\n", argv[0]);
@@ -170,5 +215,8 @@ int main(int argc, char *argv[])
 	close(fd);
 
 	ksft_test_result(!ret, "Read same data\n");
-	ksft_exit(!ret);
+
+	test_partial_move(hugepage_size);
+
+	ksft_finished();
 }

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
  2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
  2026-11-02 23:45 ` [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory Josef Bacik
@ 2026-11-02 23:45 ` Josef Bacik
  2026-11-03 10:53   ` Jose A. Perez de Azpillaga
  2026-11-02 23:46 ` [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails Josef Bacik
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:45 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, Josef Bacik

When the unmap of the source range fails at the end of an mremap() move,
the length of the range is charged to vm_committed_as even if the VMA was
never accounted, for example a MAP_SHARED or MAP_NORESERVE mapping. Nothing
ever uncharges these pages, so each such failure permanently inflates the
committed memory count.

This was reproduced with fault injection: each failure on a shmem mapping
left Committed_AS higher by the size of the moved range after everything
was unmapped.

Fix by charging the range again only when accountable_move is set.

Fixes: b714ccb02a76 ("mm/mremap: complete refactor of move_vma()")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 mm/mremap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 5926ecdb31e9..71c9f335bea8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1246,7 +1246,8 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
 	vrm->vmi_needs_invalidate = true;
 	if (err) {
 		/* OOM: unable to split vma, just get accounts right */
-		vm_acct_memory(len >> PAGE_SHIFT);
+		if (accountable_move)
+			vm_acct_memory(len >> PAGE_SHIFT);
 		return;
 	}
 

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
                   ` (2 preceding siblings ...)
  2026-11-02 23:45 ` [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted Josef Bacik
@ 2026-11-02 23:46 ` Josef Bacik
  2026-11-03  8:31   ` Lorenzo Stoakes (ARM)
  2026-11-03 11:08   ` Jose A. Perez de Azpillaga
  2026-11-02 23:46 ` [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0 Josef Bacik
  2026-11-03  0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Andrew Morton
  5 siblings, 2 replies; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:46 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, Josef Bacik

If the unmap at the end of an mremap() move fails, the source VMA stays
without VMA_ACCOUNT_BIT. Neither munmap() nor exit_mmap() uncharges it
then, so the charge for all of its pages stays in vm_committed_as after
the process is gone.

unmap_source_vma() clears the flag on the whole source VMA before the unmap
and sets it again on the remaining parts afterwards, but its error path
returns without doing so.

This was reproduced with fault injection: each failure on an anonymous
mapping left Committed_AS higher by the size of the whole VMA after
everything was unmapped.

Fix by setting the flag again on everything in the range of the original
VMA, on both paths, with a new helper. A failed unmap may have split the
VMA already, so the helper walks the range.

Fixes: 51df7bcb6151 ("mm/mremap: account memory on do_munmap() failure")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 mm/mremap.c | 41 +++++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 71c9f335bea8..4d1e446620e2 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1189,6 +1189,19 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
 	return 0;
 }
 
+/* Set VMA_ACCOUNT_BIT on all VMAs in the range [start, end). */
+static void vma_range_set_account(struct vma_iterator *vmi,
+				  unsigned long start, unsigned long end)
+{
+	struct vm_area_struct *vma;
+
+	vma_iter_set(vmi, start);
+	for_each_vma_range(*vmi, vma, end) {
+		vma_start_write(vma);
+		vma_set_flags(vma, VMA_ACCOUNT_BIT);
+	}
+}
+
 /*
  * Unmap source VMA for VMA move, turning it from a copy to a move, being
  * careful to ensure we do not underflow memory account while doing so if an
@@ -1246,8 +1259,10 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
 	vrm->vmi_needs_invalidate = true;
 	if (err) {
 		/* OOM: unable to split vma, just get accounts right */
-		if (accountable_move)
+		if (accountable_move) {
 			vm_acct_memory(len >> PAGE_SHIFT);
+			vma_range_set_account(&vmi, vm_start, vm_end);
+		}
 		return;
 	}
 
@@ -1271,28 +1286,10 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
 	 * | A |     | B |
 	 * |---|     |---|
 	 *
-	 * The VMI is still pointing at addr, so vma_prev() will give us A, and
-	 * a subsequent or lone vma_next() will give as B.
-	 *
-	 * do_vmi_munmap() will have restored the VMI back to addr.
+	 * So reinstate the flag on whatever is left of the range.
 	 */
-	if (accountable_move) {
-		unsigned long end = addr + len;
-
-		if (vm_start < addr) {
-			struct vm_area_struct *prev = vma_prev(&vmi);
-
-			vma_start_write(prev);
-			vma_set_flags(prev, VMA_ACCOUNT_BIT);
-		}
-
-		if (vm_end > end) {
-			struct vm_area_struct *next = vma_next(&vmi);
-
-			vma_start_write(next);
-			vma_set_flags(next, VMA_ACCOUNT_BIT);
-		}
-	}
+	if (accountable_move)
+		vma_range_set_account(&vmi, vm_start, vm_end);
 }
 
 /*

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
                   ` (3 preceding siblings ...)
  2026-11-02 23:46 ` [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails Josef Bacik
@ 2026-11-02 23:46 ` Josef Bacik
  2026-11-03 11:27   ` Jose A. Perez de Azpillaga
  2026-11-04  5:40   ` Sarthak Sharma
  2026-11-03  0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Andrew Morton
  5 siblings, 2 replies; 16+ messages in thread
From: Josef Bacik @ 2026-11-02 23:46 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, Josef Bacik

mremap() with an old size of 0 duplicates a shared mapping, and mremap_test
has no case for it.

Duplicate a shared anonymous mapping, once from its start and once from the
middle. Check that the source and the duplicate are mapped by one VMA each
and that they show the same pages.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
 tools/testing/selftests/mm/mremap_test.c | 52 +++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 31b484517bda..92960fff9537 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -603,6 +603,54 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 				      inplace ? " [inplace]" : "");
 }
 
+/*
+ * An old size of 0 duplicates a shared mapping: the pages show up at a second
+ * address, and the mapping they were taken from stays as it is.
+ */
+static void mremap_duplicate_shared(FILE *maps_fp, unsigned long page_size,
+				    unsigned long offset)
+{
+	char *test_name = "mremap duplicate shared mapping";
+	const size_t size = 3 * page_size;
+	const size_t dup_size = size - offset;
+	char *dup = MAP_FAILED;
+	bool success = false;
+	char *ptr;
+
+	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
+		   MAP_SHARED | MAP_ANON, -1, 0);
+	if (ptr == MAP_FAILED) {
+		perror("mmap");
+		goto out;
+	}
+	memset(ptr, 'a', size);
+
+	dup = mremap(ptr + offset, 0, dup_size, MREMAP_MAYMOVE);
+	if (dup == MAP_FAILED) {
+		perror("mremap");
+		goto out_unmap;
+	}
+
+	/* Both are mapped, each by a single VMA. */
+	if (!is_ptr_mapped(maps_fp, ptr, size) ||
+	    !is_ptr_mapped(maps_fp, dup, dup_size))
+		goto out_unmap;
+
+	/* They show the same pages. */
+	ptr[offset] = 'b';
+	dup[dup_size - 1] = 'c';
+	success = dup[0] == 'b' && ptr[size - 1] == 'c' && ptr[0] != 'c';
+
+out_unmap:
+	if (dup != MAP_FAILED && munmap(dup, dup_size))
+		perror("munmap dup");
+	if (munmap(ptr, size))
+		perror("munmap src");
+out:
+	ksft_test_result(success, "%s%s\n", test_name,
+			 offset ? " [from the middle]" : "");
+}
+
 static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 					    unsigned long page_size,
 					    bool dont_unmap)
@@ -1248,7 +1296,7 @@ int main(int argc, char **argv)
 	char *rand_addr;
 	size_t rand_size;
 	int num_expand_tests = 2;
-	int num_misc_tests = 9;
+	int num_misc_tests = 11;
 	struct test test_cases[MAX_TEST] = {};
 	struct test perf_test_cases[MAX_PERF_TEST];
 	int page_size;
@@ -1385,6 +1433,8 @@ int main(int argc, char **argv)
 	mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false);
 	mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true);
 	mremap_move_multi_invalid_vmas(maps_fp, page_size);
+	mremap_duplicate_shared(maps_fp, page_size, 0);
+	mremap_duplicate_shared(maps_fp, page_size, page_size);
 
 	fclose(maps_fp);
 

-- 
2.55.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 0/5] mm/mremap: fix accounting on a partial move
  2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
                   ` (4 preceding siblings ...)
  2026-11-02 23:46 ` [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0 Josef Bacik
@ 2026-11-03  0:23 ` Andrew Morton
  2026-11-04 14:32   ` Josef Bacik
  5 siblings, 1 reply; 16+ messages in thread
From: Andrew Morton @ 2026-11-03  0:23 UTC (permalink / raw)
  To: Josef Bacik
  Cc: Lorenzo Stoakes, Liam R. Howlett, David Hildenbrand,
	Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, stable

On Mon, 02 Nov 2026 23:45:56 +0000 Josef Bacik <josef@toxicpanda.com> wrote:

> I went through the callers of __split_vma() to see who can't cope with
> it failing, and mremap() is the bad one.  If you move part of a VMA we
> don't split it until the very end, when we unmap the old range.  By then
> the page tables have moved and there's nothing to go back to, so we fix
> up the accounting and return success with the old range still mapped.
> 
> Lorenzo recently added a way to split ahead of the move for the mlock()
> + MREMAP_DONTUNMAP case.  This series uses that for every move that
> unmaps its source, so a split that fails is reported before we've done
> anything.
> 
> Doing that turned up a real bug in hugetlb.  We take the reservation map
> away from the whole old VMA before the part that's moving is split off,
> so the parts that stay never give their reservations back.  That fix is
> the first patch so it can go to stable by itself, and the second patch
> is a selftest for it.
> 
> The next two fix the accounting for when the unmap at the end does fail,
> we either charged memory that was never accounted or lost track of the
> charge for the whole VMA.  That gets a lot harder to hit with the last
> patch but it's still possible.  There's also a test for an old size of
> 0, which nothing covered.

Thanks.

So we have two userspace-visible accounting fixups: htlb reservation
leak, Committed_AS if mremap's unmap failed.  Yes?

How come the first is cc:stable and the second is not?



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails
  2026-11-02 23:46 ` [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails Josef Bacik
@ 2026-11-03  8:31   ` Lorenzo Stoakes (ARM)
  2026-11-03 11:08   ` Jose A. Perez de Azpillaga
  1 sibling, 0 replies; 16+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-03  8:31 UTC (permalink / raw)
  To: Josef Bacik
  Cc: Andrew Morton, Liam R. Howlett, David Hildenbrand,
	Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm

On Mon, Nov 02, 2026 at 11:46:00PM +0000, Josef Bacik wrote:
> If the unmap at the end of an mremap() move fails, the source VMA stays
> without VMA_ACCOUNT_BIT. Neither munmap() nor exit_mmap() uncharges it
> then, so the charge for all of its pages stays in vm_committed_as after
> the process is gone.
>
> unmap_source_vma() clears the flag on the whole source VMA before the unmap
> and sets it again on the remaining parts afterwards, but its error path
> returns without doing so.
>
> This was reproduced with fault injection: each failure on an anonymous
> mapping left Committed_AS higher by the size of the whole VMA after
> everything was unmapped.
>
> Fix by setting the flag again on everything in the range of the original
> VMA, on both paths, with a new helper. A failed unmap may have split the
> VMA already, so the helper walks the range.
>
> Fixes: 51df7bcb6151 ("mm/mremap: account memory on do_munmap() failure")
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Thanks, LGTM!

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/mremap.c | 41 +++++++++++++++++++----------------------
>  1 file changed, 19 insertions(+), 22 deletions(-)

Nice diffstat :)

>
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 71c9f335bea8..4d1e446620e2 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -1189,6 +1189,19 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
>  	return 0;
>  }
>
> +/* Set VMA_ACCOUNT_BIT on all VMAs in the range [start, end). */
> +static void vma_range_set_account(struct vma_iterator *vmi,
> +				  unsigned long start, unsigned long end)
> +{
> +	struct vm_area_struct *vma;
> +
> +	vma_iter_set(vmi, start);
> +	for_each_vma_range(*vmi, vma, end) {
> +		vma_start_write(vma);
> +		vma_set_flags(vma, VMA_ACCOUNT_BIT);
> +	}
> +}
> +
>  /*
>   * Unmap source VMA for VMA move, turning it from a copy to a move, being
>   * careful to ensure we do not underflow memory account while doing so if an
> @@ -1246,8 +1259,10 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
>  	vrm->vmi_needs_invalidate = true;
>  	if (err) {
>  		/* OOM: unable to split vma, just get accounts right */
> -		if (accountable_move)
> +		if (accountable_move) {
>  			vm_acct_memory(len >> PAGE_SHIFT);
> +			vma_range_set_account(&vmi, vm_start, vm_end);
> +		}
>  		return;
>  	}
>
> @@ -1271,28 +1286,10 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
>  	 * | A |     | B |
>  	 * |---|     |---|
>  	 *
> -	 * The VMI is still pointing at addr, so vma_prev() will give us A, and
> -	 * a subsequent or lone vma_next() will give as B.
> -	 *
> -	 * do_vmi_munmap() will have restored the VMI back to addr.
> +	 * So reinstate the flag on whatever is left of the range.
>  	 */
> -	if (accountable_move) {
> -		unsigned long end = addr + len;
> -
> -		if (vm_start < addr) {
> -			struct vm_area_struct *prev = vma_prev(&vmi);
> -
> -			vma_start_write(prev);
> -			vma_set_flags(prev, VMA_ACCOUNT_BIT);
> -		}
> -
> -		if (vm_end > end) {
> -			struct vm_area_struct *next = vma_next(&vmi);
> -
> -			vma_start_write(next);
> -			vma_set_flags(next, VMA_ACCOUNT_BIT);
> -		}
> -	}
> +	if (accountable_move)
> +		vma_range_set_account(&vmi, vm_start, vm_end);
>  }
>
>  /*
>
> --
> 2.55.0
>

--
Cheers, Lorenzo


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on partial move
  2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
@ 2026-11-03 10:42   ` Jose A. Perez de Azpillaga
  0 siblings, 0 replies; 16+ messages in thread
From: Jose A. Perez de Azpillaga @ 2026-11-03 10:42 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, linux-mm, stable

On 11/3/26 12:45 AM, Josef Bacik wrote:
> Moving a part of a private hugetlb mapping with mremap() leaks the huge
> page reservations of the parts that stay. They are not returned when the
> mapping is unmapped, when the process exits or when the pool is resized.
> 
> fixup_hugetlb_reservations() takes the reservation map away from the old
> VMA while that VMA still spans its whole range, because the moved part is
> only split off by the unmap at the end of the move. hugetlb_vm_op_close()
> then finds no map in the parts that remain and returns nothing for them:
> 
>     mmap() of 4 pages, MAP_PRIVATE | MAP_HUGETLB    HugePages_Rsvd: 4
>     mremap() of the second page to a new address    HugePages_Rsvd: 4
>     munmap() of all of it                           HugePages_Rsvd: 3
> 
> The source is unmapped in this case, so the number of VMAs ends up where it
> did before and the check against sysctl_max_map_count stays as it is.
> 
> Fix by splitting a hugetlb VMA in prep_move_vma() before a part of it is
> moved, as commit 597e4b9ab48a ("mm/mremap: fix locked_vm leak by splitting
> VMA for MREMAP_DONTUNMAP") does for an mlock()'d VMA. A backport needs that
> commit, which is tagged for stable itself.
> 
> Fixes: 550a7d60bd5e ("mm, hugepages: add mremap() support for hugepage backed vma")
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> 
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
LGTM:

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory
  2026-11-02 23:45 ` [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory Josef Bacik
@ 2026-11-03 10:48   ` Jose A. Perez de Azpillaga
  0 siblings, 0 replies; 16+ messages in thread
From: Jose A. Perez de Azpillaga @ 2026-11-03 10:48 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, linux-mm

On 11/3/26 12:45 AM, Josef Bacik wrote:
> hugetlb-mremap only moves whole mappings, so it did not catch the
> reservation leak of a partial move.
> 
> Map four private huge pages without touching them, move the second one,
> unmap everything, and check that the number of reserved huge pages is back
> where it was.
> 
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> 
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
LGTM:

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted
  2026-11-02 23:45 ` [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted Josef Bacik
@ 2026-11-03 10:53   ` Jose A. Perez de Azpillaga
  0 siblings, 0 replies; 16+ messages in thread
From: Jose A. Perez de Azpillaga @ 2026-11-03 10:53 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, linux-mm

On 11/3/26 12:45 AM, Josef Bacik wrote:
> When the unmap of the source range fails at the end of an mremap() move,
> the length of the range is charged to vm_committed_as even if the VMA was
> never accounted, for example a MAP_SHARED or MAP_NORESERVE mapping. Nothing
> ever uncharges these pages, so each such failure permanently inflates the
> committed memory count.
> 
> This was reproduced with fault injection: each failure on a shmem mapping
> left Committed_AS higher by the size of the moved range after everything
> was unmapped.
> 
> Fix by charging the range again only when accountable_move is set.
> 
> Fixes: b714ccb02a76 ("mm/mremap: complete refactor of move_vma()")
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> 
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
LGTM:

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails
  2026-11-02 23:46 ` [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails Josef Bacik
  2026-11-03  8:31   ` Lorenzo Stoakes (ARM)
@ 2026-11-03 11:08   ` Jose A. Perez de Azpillaga
  1 sibling, 0 replies; 16+ messages in thread
From: Jose A. Perez de Azpillaga @ 2026-11-03 11:08 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, linux-mm

On 11/3/26 12:46 AM, Josef Bacik wrote:
> If the unmap at the end of an mremap() move fails, the source VMA stays
> without VMA_ACCOUNT_BIT. Neither munmap() nor exit_mmap() uncharges it
> then, so the charge for all of its pages stays in vm_committed_as after
> the process is gone.
> 
> unmap_source_vma() clears the flag on the whole source VMA before the unmap
> and sets it again on the remaining parts afterwards, but its error path
> returns without doing so.
> 
> This was reproduced with fault injection: each failure on an anonymous
> mapping left Committed_AS higher by the size of the whole VMA after
> everything was unmapped.
> 
> Fix by setting the flag again on everything in the range of the original
> VMA, on both paths, with a new helper. A failed unmap may have split the
> VMA already, so the helper walks the range.
> 
> Fixes: 51df7bcb6151 ("mm/mremap: account memory on do_munmap() failure")
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

nice!

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0
  2026-11-02 23:46 ` [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0 Josef Bacik
@ 2026-11-03 11:27   ` Jose A. Perez de Azpillaga
  2026-11-04  5:40   ` Sarthak Sharma
  1 sibling, 0 replies; 16+ messages in thread
From: Jose A. Perez de Azpillaga @ 2026-11-03 11:27 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, linux-mm

On 11/3/26 12:46 AM, Josef Bacik wrote:
> mremap() with an old size of 0 duplicates a shared mapping, and mremap_test
> has no case for it.
> 
> Duplicate a shared anonymous mapping, once from its start and once from the
> middle. Check that the source and the duplicate are mapped by one VMA each
> and that they show the same pages.
> 
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> 
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

LGTM:

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0
  2026-11-02 23:46 ` [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0 Josef Bacik
  2026-11-03 11:27   ` Jose A. Perez de Azpillaga
@ 2026-11-04  5:40   ` Sarthak Sharma
  1 sibling, 0 replies; 16+ messages in thread
From: Sarthak Sharma @ 2026-11-04  5:40 UTC (permalink / raw)
  To: Josef Bacik, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
	David Hildenbrand
  Cc: Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm

Hi Josef!

On 11/3/26 5:16 AM, Josef Bacik wrote:
> mremap() with an old size of 0 duplicates a shared mapping, and mremap_test
> has no case for it.
>
> Duplicate a shared anonymous mapping, once from its start and once from the
> middle. Check that the source and the duplicate are mapped by one VMA each
> and that they show the same pages.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---

I have a few nits on this patch. Since it contains some things that my
series [1] is changing, could you fold them in here?

>   tools/testing/selftests/mm/mremap_test.c | 52 +++++++++++++++++++++++++++++++-
>   1 file changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
> index 31b484517bda..92960fff9537 100644
> --- a/tools/testing/selftests/mm/mremap_test.c
> +++ b/tools/testing/selftests/mm/mremap_test.c
> @@ -603,6 +603,54 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
>                                     inplace ? " [inplace]" : "");
>   }
>
> +/*
> + * An old size of 0 duplicates a shared mapping: the pages show up at a second
> + * address, and the mapping they were taken from stays as it is.
> + */
> +static void mremap_duplicate_shared(FILE *maps_fp, unsigned long page_size,
> +                                 unsigned long offset)
> +{
> +     char *test_name = "mremap duplicate shared mapping";
> +     const size_t size = 3 * page_size;
> +     const size_t dup_size = size - offset;
> +     char *dup = MAP_FAILED;
> +     bool success = false;
> +     char *ptr;
> +
> +     ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
> +                MAP_SHARED | MAP_ANON, -1, 0);
> +     if (ptr == MAP_FAILED) {
> +             perror("mmap");

ksft_perror() here instead of perror().

> +             goto out;
> +     }
> +     memset(ptr, 'a', size);
> +
> +     dup = mremap(ptr + offset, 0, dup_size, MREMAP_MAYMOVE);
> +     if (dup == MAP_FAILED) {
> +             perror("mremap");

Same here

> +             goto out_unmap;
> +     }
> +
> +     /* Both are mapped, each by a single VMA. */
> +     if (!is_ptr_mapped(maps_fp, ptr, size) ||
> +         !is_ptr_mapped(maps_fp, dup, dup_size))
> +             goto out_unmap;
> +
> +     /* They show the same pages. */
> +     ptr[offset] = 'b';
> +     dup[dup_size - 1] = 'c';
> +     success = dup[0] == 'b' && ptr[size - 1] == 'c' && ptr[0] != 'c';
> +
> +out_unmap:
> +     if (dup != MAP_FAILED && munmap(dup, dup_size))
> +             perror("munmap dup");
> +     if (munmap(ptr, size))
> +             perror("munmap src");

There's no need to report an error if munmap fails in cleanup.

It could be something like:

        if (dup != MAP_FAILED)
                munmap(dup, dup_size);
        munmap(ptr,size);

> +out:
> +     ksft_test_result(success, "%s%s\n", test_name,
> +                      offset ? " [from the middle]" : "");
> +}
> +
>   static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
>                                           unsigned long page_size,
>                                           bool dont_unmap)
> @@ -1248,7 +1296,7 @@ int main(int argc, char **argv)
>       char *rand_addr;
>       size_t rand_size;
>       int num_expand_tests = 2;
> -     int num_misc_tests = 9;
> +     int num_misc_tests = 11;
>       struct test test_cases[MAX_TEST] = {};
>       struct test perf_test_cases[MAX_PERF_TEST];
>       int page_size;
> @@ -1385,6 +1433,8 @@ int main(int argc, char **argv)
>       mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false);
>       mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true);
>       mremap_move_multi_invalid_vmas(maps_fp, page_size);
> +     mremap_duplicate_shared(maps_fp, page_size, 0);
> +     mremap_duplicate_shared(maps_fp, page_size, page_size);
>
>       fclose(maps_fp);
>
>

[1]
https://lore.kernel.org/all/20261102100211.141831-1-sarthak.sharma@arm.com/
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 0/5] mm/mremap: fix accounting on a partial move
  2026-11-03  0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Andrew Morton
@ 2026-11-04 14:32   ` Josef Bacik
  2026-11-04 14:46     ` Lorenzo Stoakes (ARM)
  0 siblings, 1 reply; 16+ messages in thread
From: Josef Bacik @ 2026-11-04 14:32 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Lorenzo Stoakes, Liam R. Howlett, David Hildenbrand,
	Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, stable

On Mon, Nov 02, 2026 at 04:23:04PM -0800, Andrew Morton wrote:
> So we have two userspace-visible accounting fixups: htlb reservation
> leak, Committed_AS if mremap's unmap failed.  Yes?

Yes, though the Committed_AS part is two bugs, patch 3 charges memory
that was never accounted and patch 4 loses the charge for the whole VMA.

The text you quoted is the v1 cover, which I kept below the changelog.
The "last patch" it talks about is dropped in v2, so only hugetlb splits
ahead of the move now.

> How come the first is cc:stable and the second is not?

The reservation leak happens on any partial move of a private hugetlb
mapping, nothing has to go wrong, and the huge pages stay reserved after
the process exits.

The Committed_AS bugs need an allocation to fail during the unmap at the
end of the move.  mremap() checks the map count and sealing before it
gets there, so what's left is small GFP_KERNEL allocations, which in
practice means a process that is already being OOM killed.  I only hit
it with fault injection, so I left those with just Fixes and let the
stable folks decide. If you want them cc'ed it's no problem to add.
Thanks,

Josef


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 0/5] mm/mremap: fix accounting on a partial move
  2026-11-04 14:32   ` Josef Bacik
@ 2026-11-04 14:46     ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 16+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-04 14:46 UTC (permalink / raw)
  To: Josef Bacik
  Cc: Andrew Morton, Liam R. Howlett, David Hildenbrand,
	Vlastimil Babka, Jann Horn, Pedro Falcato, Muchun Song,
	Oscar Salvador, Jose A. Perez de Azpillaga, linux-mm, stable

On Wed, Nov 04, 2026 at 02:32:35PM +0000, Josef Bacik wrote:
> The Committed_AS bugs need an allocation to fail during the unmap at the
> end of the move.  mremap() checks the map count and sealing before it
> gets there, so what's left is small GFP_KERNEL allocations, which in
> practice means a process that is already being OOM killed.  I only hit
> it with fault injection, so I left those with just Fixes and let the
> stable folks decide. If you want them cc'ed it's no problem to add.

Generally would prefer the fault-injection ones _not_ to be backported,
they're essentially technical fixes since to actually hit them <4 KiB
allocs would have to fail meaning OOM + fatal signal -> process dying soon
anyway so doesn't matter.

--
Cheers, Lorenzo


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-11-04 14:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 23:45 [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Josef Bacik
2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
2026-11-03 10:42   ` Jose A. Perez de Azpillaga
2026-11-02 23:45 ` [PATCH v2 2/5] selftests/mm: test a partial mremap() of hugetlb memory Josef Bacik
2026-11-03 10:48   ` Jose A. Perez de Azpillaga
2026-11-02 23:45 ` [PATCH v2 3/5] mm/mremap: reaccount on unmap failure only if accounted Josef Bacik
2026-11-03 10:53   ` Jose A. Perez de Azpillaga
2026-11-02 23:46 ` [PATCH v2 4/5] mm/mremap: restore VMA_ACCOUNT_BIT if the unmap fails Josef Bacik
2026-11-03  8:31   ` Lorenzo Stoakes (ARM)
2026-11-03 11:08   ` Jose A. Perez de Azpillaga
2026-11-02 23:46 ` [PATCH v2 5/5] selftests/mm: test mremap() with an old size of 0 Josef Bacik
2026-11-03 11:27   ` Jose A. Perez de Azpillaga
2026-11-04  5:40   ` Sarthak Sharma
2026-11-03  0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a partial move Andrew Morton
2026-11-04 14:32   ` Josef Bacik
2026-11-04 14:46     ` Lorenzo Stoakes (ARM)

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.