Skip to content

Commit f357e5a

Browse files
author
Audra Mitchell
committed
mm/mremap: correctly handle partial mremap() of VMA starting at 0
JIRA: https://issues.redhat.com/browse/RHEL-104908 This patch is a backport of the following upstream commit: commit 937582e Author: Lorenzo Stoakes <[email protected]> Date: Mon Mar 10 20:50:34 2025 +0000 mm/mremap: correctly handle partial mremap() of VMA starting at 0 Patch series "refactor mremap and fix bug", v3. The existing mremap() logic has grown organically over a very long period of time, resulting in code that is in many parts, very difficult to follow and full of subtleties and sources of confusion. In addition, it is difficult to thread state through the operation correctly, as function arguments have expanded, some parameters are expected to be temporarily altered during the operation, others are intended to remain static and some can be overridden. This series completely refactors the mremap implementation, sensibly separating functions, adding comments to explain the more subtle aspects of the implementation and making use of small structs to thread state through everything. The reason for doing so is to lay the groundwork for planned future changes to the mremap logic, changes which require the ability to easily pass around state. Additionally, it would be unhelpful to add yet more logic to code that is already difficult to follow without first refactoring it like this. The first patch in this series additionally fixes a bug when a VMA with start address zero is partially remapped. Tested on real hardware under heavy workload and all self tests are passing. This patch (of 3): Consider the case of a partial mremap() (that results in a VMA split) of an accountable VMA (i.e. which has the VM_ACCOUNT flag set) whose start address is zero, with the MREMAP_MAYMOVE flag specified and a scenario where a move does in fact occur: addr end | | v v |-------------| | vma | |-------------| 0 This move is affected by unmapping the range [addr, end). In order to prevent an incorrect decrement of accounted memory which has already been determined, the mremap() code in move_vma() clears VM_ACCOUNT from the VMA prior to doing so, before reestablishing it in each of the VMAs post-split: addr end | | v v |---| |---| | A | | B | |---| |---| Commit 6b73cff ("mm: change munmap splitting order and move_vma()") changed this logic such as to determine whether there is a need to do so by establishing account_start and account_end and, in the instance where such an operation is required, assigning them to vma->vm_start and vma->vm_end. Later the code checks if the operation is required for 'A' referenced above thusly: if (account_start) { ... } However, if the VMA described above has vma->vm_start == 0, which is now assigned to account_start, this branch will not be executed. As a result, the VMA 'A' above will remain stripped of its VM_ACCOUNT flag, incorrectly. The fix is to simply convert these variables to booleans and set them as required. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/dc55cb6db25d97c3d9e460de4986a323fa959676.1741639347.git.lorenzo.stoakes@oracle.com Fixes: 6b73cff ("mm: change munmap splitting order and move_vma()") Signed-off-by: Lorenzo Stoakes <[email protected]> Reviewed-by: Harry Yoo <[email protected]> Reviewed-by: Liam R. Howlett <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Audra Mitchell <[email protected]>
1 parent def00a2 commit f357e5a

File tree

1 file changed

+5
-5
lines changed

1 file changed

+5
-5
lines changed

mm/mremap.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,8 +629,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
629629
unsigned long vm_flags = vma->vm_flags;
630630
unsigned long new_pgoff;
631631
unsigned long moved_len;
632-
unsigned long account_start = 0;
633-
unsigned long account_end = 0;
632+
bool account_start = false;
633+
bool account_end = false;
634634
unsigned long hiwater_vm;
635635
int err = 0;
636636
bool need_rmap_locks;
@@ -712,9 +712,9 @@ static unsigned long move_vma(struct vm_area_struct *vma,
712712
if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP)) {
713713
vm_flags_clear(vma, VM_ACCOUNT);
714714
if (vma->vm_start < old_addr)
715-
account_start = vma->vm_start;
715+
account_start = true;
716716
if (vma->vm_end > old_addr + old_len)
717-
account_end = vma->vm_end;
717+
account_end = true;
718718
}
719719

720720
/*
@@ -754,7 +754,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
754754
/* OOM: unable to split vma, just get accounts right */
755755
if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP))
756756
vm_acct_memory(old_len >> PAGE_SHIFT);
757-
account_start = account_end = 0;
757+
account_start = account_end = false;
758758
}
759759

760760
if (vm_flags & VM_LOCKED) {

0 commit comments

Comments
 (0)