mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v1] mm/mremap: do not charge a shrinking move twice
@ 2026-10-17 23:35 Nickolai Zeldovich
  2026-10-18  1:04 ` Andrew Morton
  0 siblings, 1 reply; 3+ messages in thread
From: Nickolai Zeldovich @ 2026-10-17 23:35 UTC (permalink / raw)
  To: Andrew Morton, Lorenzo Stoakes
  Cc: Liam R. Howlett, Vlastimil Babka, Jann Horn, Pedro Falcato,
	linux-mm, linux-kernel, Nickolai Zeldovich

Since v6.15 every mremap() that shrinks an accounted mapping and moves
it with MREMAP_MAYMOVE | MREMAP_FIXED leaves old_len - new_len bytes
charged to vm_committed_as for good.  An unprivileged process that
repeats such a call keeps raising Committed_AS in /proc/meminfo; with
vm.overcommit_memory=2 it reaches CommitLimit, after which every
accounted allocation in the system (private writable mmap(), brk(),
fork()) fails with ENOMEM until reboot.  A loop of 1000 calls moving a
2 MiB private anonymous mapping to a 1 MiB fixed destination raises
Committed_AS by 1 GiB.

mremap_to() first unmaps the tail of the source with shrink_vma(),
which uncharges it, and then sets old_len to new_len so that the move
looks like a same-size one.  vrm->delta, the absolute difference of the
two lengths computed in do_mremap(), is not updated, and
vrm_calc_charge() charges delta pages for the move.  For a move that
does not unmap the source the charge only has to cover the growth from
old_len to new_len, which here is zero; nothing ever releases the extra
charge.  Before the vma_remap_struct conversion move_vma() charged
new_len - old_len with the updated old_len.

Recompute delta after the shrink.

Tested with the program in the notes under QEMU (x86_64 defconfig):
Committed_AS grows by about 1 GiB per run without this patch and stays
flat with it.

Fixes: b714ccb02a76 ("mm/mremap: complete refactor of move_vma()")
Assisted-by: LLM
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
---

Notes:
    Reproducer (any accounted private mapping; watch Committed_AS):
    
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <sys/mman.h>
    
    static long committed_kb(void)
    {
    	char line[128];
    	long kb = -1;
    	FILE *f = fopen("/proc/meminfo", "r");
    
    	while (f && fgets(line, sizeof(line), f))
    		if (sscanf(line, "Committed_AS: %ld kB", &kb) == 1)
    			break;
    	if (f)
    		fclose(f);
    	return kb;
    }
    
    int main(void)
    {
    	const size_t old_len = 2 << 20, new_len = 1 << 20;
    	long before = committed_kb();
    
    	for (int i = 0; i < 1000; i++) {
    		char *src = mmap(NULL, old_len, PROT_READ | PROT_WRITE,
    				 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    		char *dst = mmap(NULL, new_len, PROT_NONE,
    				 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    
    		if (mremap(src, old_len, new_len, MREMAP_MAYMOVE | MREMAP_FIXED,
    			   dst) != dst)
    			return perror("mremap"), 1;
    		munmap(dst, new_len);
    	}
    	printf("leaked %ld kB\n", committed_kb() - before);
    	return 0;
    }
    
    $ gcc -O2 -o mremap-shrink-charge mremap-shrink-charge.c && ./mremap-shrink-charge
    before: leaked 1024000 kB   (every run; Committed_AS 3744 -> 1027744 -> 2051744 kB)
    after:  leaked 0 kB

 mm/mremap.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/mm/mremap.c b/mm/mremap.c
index 444f37d7cd28..2dd41c611fdd 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1523,6 +1523,7 @@ static unsigned long mremap_to(struct vma_remap_struct *vrm)
 
 		/* Set up for the move now shrink has been executed. */
 		vrm->old_len = vrm->new_len;
+		vrm_set_delta(vrm);
 	}
 
 	/* MREMAP_DONTUNMAP expands by old_len since old_len == new_len */

base-commit: 70dd4ee72eb2d5793c62e71c14e3aba78e5a4e56
-- 
2.53.0


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

end of thread, other threads:[~2026-10-18  1:50 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-17 23:35 [PATCH v1] mm/mremap: do not charge a shrinking move twice Nickolai Zeldovich
2026-10-18  1:04 ` Andrew Morton
2026-10-18  1:50   ` [PATCH v2] " Nickolai Zeldovich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®