* [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
2026-11-03 0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a " Andrew Morton
0 siblings, 2 replies; 6+ 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] 6+ 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-03 0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a " Andrew Morton
1 sibling, 1 reply; 6+ 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] 6+ 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
2026-11-02 23:45 ` [PATCH v2 1/5] mm/mremap: fix hugetlb reservation leak on " Josef Bacik
@ 2026-11-03 0:23 ` Andrew Morton
2026-11-04 14:32 ` Josef Bacik
1 sibling, 1 reply; 6+ 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] 6+ 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; 6+ 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] 6+ 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 " Andrew Morton
@ 2026-11-04 14:32 ` Josef Bacik
2026-11-04 14:46 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 6+ 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] 6+ 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; 6+ 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] 6+ messages in thread
end of thread, other threads:[~2026-11-04 14:46 UTC | newest]
Thread overview: 6+ 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-03 0:23 ` [PATCH v2 0/5] mm/mremap: fix accounting on a " Andrew Morton
2026-11-04 14:32 ` Josef Bacik
2026-11-04 14:46 ` Lorenzo Stoakes (ARM)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox