* [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation
@ 2026-05-07 11:48 Jill Ravaliya
2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Jill Ravaliya @ 2026-05-07 11:48 UTC (permalink / raw)
To: akpm, urezki; +Cc: linux-mm, linux-kernel, Jill Ravaliya
vrealloc() shrink path zeros unused memory and updates
vm->requested_size, but never frees the physical pages,
removes page table mappings, or flushes the TLB for the
unused range.
When a caller shrinks a vmalloc allocation, physical pages
backing the unused portion remain allocated until vfree()
is eventually called, wasting real RAM.
Fix this by unmapping the unused virtual range using
vunmap_range() which also flushes the TLB, freeing each
unused physical page back to the buddy allocator, and
updating vm->nr_pages to reflect the new page count.
Signed-off-by: Jill Ravaliya <jillravaliya@gmail.com>
---
mm/vmalloc.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index aa08651ec..a8cedfc5d 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4336,6 +4336,27 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align
memset((void *)p + size, 0, old_size - size);
vm->requested_size = size;
kasan_vrealloc(p, old_size, size);
+
+ /* Shrink the vm_area: unmap and free unused pages. */
+ if (size < alloced_size) {
+ unsigned long new_nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ unsigned long i;
+
+ /* Unmap unused virtual range and flush TLB. */
+ vunmap_range((unsigned long)p + PAGE_ALIGN(size),
+ (unsigned long)p + alloced_size);
+
+ /* Free unused physical pages back to buddy allocator. */
+ for (i = new_nr_pages; i < vm->nr_pages; i++) {
+ mod_lruvec_page_state(vm->pages[i],
+ NR_VMALLOC, -1);
+ __free_page(vm->pages[i]);
+ vm->pages[i] = NULL;
+ }
+
+ vm->nr_pages = new_nr_pages;
+ }
+
return (void *)p;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing 2026-05-07 11:48 [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Jill Ravaliya @ 2026-05-07 11:48 ` Jill Ravaliya 2026-05-23 13:34 ` kernel test robot 2026-05-23 16:20 ` Uladzislau Rezki 2026-05-07 17:17 ` [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Uladzislau Rezki 2026-05-07 20:26 ` [syzbot ci] " syzbot ci 2 siblings, 2 replies; 7+ messages in thread From: Jill Ravaliya @ 2026-05-07 11:48 UTC (permalink / raw) To: akpm, urezki; +Cc: linux-mm, linux-kernel, Jill Ravaliya Add a selftest that verifies vrealloc() frees physical pages when shrinking an allocation. The test loads a kernel module that: 1. Allocates 10MB with vmalloc() 2. Touches all pages to force physical allocation 3. Shrinks to 2MB with vrealloc() 4. Verifies free page count increased after shrink Without the fix, the test fails because no pages are freed. With the fix applied, the test passes confirming ~2048 pages are returned to the system after shrinking from 10MB to 2MB. Tested on kernel 7.0.0 in QEMU. Signed-off-by: Jill Ravaliya <jillravaliya@gmail.com> --- tools/testing/selftests/mm/Makefile | 5 ++ .../selftests/mm/vrealloc_shrink_test.c | 65 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tools/testing/selftests/mm/vrealloc_shrink_test.c diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index cd24596cd..4eab7c76c 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -104,6 +104,7 @@ TEST_GEN_FILES += hugetlb_dio TEST_GEN_FILES += droppable TEST_GEN_FILES += guard-regions TEST_GEN_FILES += merge +TEST_GEN_FILES += vrealloc_shrink_test TEST_GEN_FILES += rmap TEST_GEN_FILES += folio_split_race_test @@ -282,3 +283,7 @@ warn_missing_page_frag: echo "Warning: $(PAGE_FRAG_WARNING). page_frag test will be skipped." ; \ echo endif + +# vrealloc shrink test module +vrealloc_shrink_mod.ko: vrealloc_shrink_mod.c + $(MAKE) -C $(KDIR) M=$(PWD) modules diff --git a/tools/testing/selftests/mm/vrealloc_shrink_test.c b/tools/testing/selftests/mm/vrealloc_shrink_test.c new file mode 100644 index 000000000..cf4263074 --- /dev/null +++ b/tools/testing/selftests/mm/vrealloc_shrink_test.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test that vrealloc() frees physical pages when shrinking. + * + * vrealloc() shrink path previously zeroed unused memory and updated + * vm->requested_size, but never freed the physical pages backing the + * unused portion of the allocation. This test verifies the fix by + * loading a kernel module that directly measures nr_pages before and + * after vrealloc() shrink. + * + * Copyright (C) 2026 Jill Ravaliya + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "../kselftest.h" + +#define MODULE_NAME "vrealloc_shrink_mod" +#define DMESG_PASS "vrealloc_shrink: PASS" +#define DMESG_FAIL "vrealloc_shrink: FAIL" + +static int run_cmd(const char *cmd) +{ + return system(cmd); +} + +static int check_dmesg_for(const char *pattern) +{ + char cmd[256]; + snprintf(cmd, sizeof(cmd), + "dmesg | grep -q '%s'", pattern); + return system(cmd) == 0; +} + +int main(void) +{ + ksft_print_header(); + ksft_set_plan(1); + + /* Insert the test module */ + if (run_cmd("insmod " MODULE_NAME ".ko") != 0) { + ksft_test_result_skip( + "could not load %s.ko - is it built?\n", + MODULE_NAME); + ksft_finished(); + } + + /* Check dmesg for pass/fail */ + if (check_dmesg_for(DMESG_PASS)) { + ksft_test_result_pass( + "vrealloc shrink frees physical pages\n"); + } else if (check_dmesg_for(DMESG_FAIL)) { + ksft_test_result_fail( + "vrealloc shrink did NOT free physical pages\n"); + } else { + ksft_test_result_fail( + "could not find test result in dmesg\n"); + } + + run_cmd("rmmod " MODULE_NAME); + ksft_finished(); +} -- 2.43.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing 2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya @ 2026-05-23 13:34 ` kernel test robot 2026-05-23 16:20 ` Uladzislau Rezki 1 sibling, 0 replies; 7+ messages in thread From: kernel test robot @ 2026-05-23 13:34 UTC (permalink / raw) To: Jill Ravaliya Cc: oe-lkp, lkp, linux-mm, akpm, urezki, linux-kernel, Jill Ravaliya Hello, kernel test robot noticed "kernel_BUG_at_mm/vmalloc.c" on: commit: 7a2723bc6f2ec12f6e8bfccdf20c09b84f721993 ("[PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing") url: https://github.com/intel-lab-lkp/linux/commits/Jill-Ravaliya/selftests-mm-add-test-for-vrealloc-shrink-page-freeing/20260511-181706 base: https://git.kernel.org/cgit/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/all/20260507114854.41117-2-jillravaliya@gmail.com/ patch subject: [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing in testcase: boot config: x86_64-kexec compiler: clang-20 test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 32G (please refer to attached dmesg/kmsg for entire log/backtrace) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <oliver.sang@intel.com> | Closes: https://lore.kernel.org/oe-lkp/202605231524.731e5313-lkp@intel.com [ 3.859842][ T1] ------------[ cut here ]------------ [ 3.860491][ T1] kernel BUG at mm/vmalloc.c:488! [ 3.861026][ T1] Oops: invalid opcode: 0000 [#1] SMP PTI [ 3.861616][ T1] CPU: 0 UID: 0 PID: 1 Comm: systemd Not tainted 7.1.0-rc1-00283-g7a2723bc6f2e #1 PREEMPT(lazy) [ 3.862702][ T1] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 3.863724][ T1] RIP: 0010:__vunmap_range_noflush (vmalloc.c:501) [ 3.864346][ T1] Code: 7c 24 10 48 83 c4 58 5b 41 5c 41 5d 41 5e 41 5f 5d e9 7c 9d d2 ff 48 83 c4 58 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc <0f> 0b 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 All code ======== 0: 7c 24 jl 0x26 2: 10 48 83 adc %cl,-0x7d(%rax) 5: c4 (bad) 6: 58 pop %rax 7: 5b pop %rbx 8: 41 5c pop %r12 a: 41 5d pop %r13 c: 41 5e pop %r14 e: 41 5f pop %r15 10: 5d pop %rbp 11: e9 7c 9d d2 ff jmp 0xffffffffffd29d92 16: 48 83 c4 58 add $0x58,%rsp 1a: 5b pop %rbx 1b: 41 5c pop %r12 1d: 41 5d pop %r13 1f: 41 5e pop %r14 21: 41 5f pop %r15 23: 5d pop %rbp 24: c3 ret 25: cc int3 26: cc int3 27: cc int3 28: cc int3 29: cc int3 2a:* 0f 0b ud2 <-- trapping instruction 2c: 66 66 66 66 66 66 2e data16 data16 data16 data16 data16 cs nopw 0x0(%rax,%rax,1) 33: 0f 1f 84 00 00 00 00 3a: 00 3b: 0f .byte 0xf 3c: 1f (bad) 3d: 80 00 00 addb $0x0,(%rax) Code starting with the faulting instruction =========================================== 0: 0f 0b ud2 2: 66 66 66 66 66 66 2e data16 data16 data16 data16 data16 cs nopw 0x0(%rax,%rax,1) 9: 0f 1f 84 00 00 00 00 10: 00 11: 0f .byte 0xf 12: 1f (bad) 13: 80 00 00 addb $0x0,(%rax) [ 3.866197][ T1] RSP: 0018:ffffc90000013a70 EFLAGS: 00010246 [ 3.866816][ T1] RAX: ffffc90000035990 RBX: ffffc90000035000 RCX: 0000000000000000 [ 3.867632][ T1] RDX: 0000000000000000 RSI: ffffc90000036000 RDI: ffffc90000036000 [ 3.868442][ T1] RBP: 0000000000400dc0 R08: 00000000ffffffff R09: 0000000000000000 [ 3.869260][ T1] R10: ffffc90000035990 R11: ffffffff8215b050 R12: ffffc90000036000 [ 3.870088][ T1] R13: ffffc90000036000 R14: 0000000000000001 R15: ffff88810f5e18a0 [ 3.870907][ T1] FS: 00007f356fcade40(0000) GS:ffff88889c100000(0000) knlGS:0000000000000000 [ 3.871802][ T1] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3.872461][ T1] CR2: 00007f3570966000 CR3: 000000010c872000 CR4: 00000000000406f0 [ 3.873270][ T1] Call Trace: [ 3.873666][ T1] <TASK> [ 3.874083][ T1] ? krealloc_node_align_noprof (slub.c:?) [ 3.874811][ T1] ? find_instance (bpf/liveness.c:66) [ 3.875300][ T1] vrealloc_node_align_noprof (vmalloc.c:506 vmalloc.c:521 vmalloc.c:4345) [ 3.875883][ T1] bpf_patch_insn_data (bpf/fixups.c:254) [ 3.876410][ T1] bpf_convert_ctx_accesses (bpf/fixups.c:974) [ 3.876975][ T1] bpf_check (bpf/verifier.c:20094) [ 3.877441][ T1] bpf_prog_load (bpf/syscall.c:3082) [ 3.877951][ T1] __sys_bpf (bpf/syscall.c:6248) [ 3.878419][ T1] __x64_sys_bpf (bpf/syscall.c:6361 bpf/syscall.c:6359 bpf/syscall.c:6359) [ 3.878891][ T1] do_syscall_64 (x86/entry/syscall_64.c:63 x86/entry/syscall_64.c:94) [ 3.879373][ T1] entry_SYSCALL_64_after_hwframe (x86/entry/entry_64.S:121) [ 3.879974][ T1] RIP: 0033:0x7f3570834779 [ 3.880451][ T1] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 4f 86 0d 00 f7 d8 64 89 01 48 All code ======== 0: ff c3 inc %ebx 2: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1) 9: 00 00 00 c: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 11: 48 89 f8 mov %rdi,%rax 14: 48 89 f7 mov %rsi,%rdi 17: 48 89 d6 mov %rdx,%rsi 1a: 48 89 ca mov %rcx,%rdx 1d: 4d 89 c2 mov %r8,%r10 20: 4d 89 c8 mov %r9,%r8 23: 4c 8b 4c 24 08 mov 0x8(%rsp),%r9 28: 0f 05 syscall 2a:* 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax <-- trapping instruction 30: 73 01 jae 0x33 32: c3 ret 33: 48 8b 0d 4f 86 0d 00 mov 0xd864f(%rip),%rcx # 0xd8689 3a: f7 d8 neg %eax 3c: 64 89 01 mov %eax,%fs:(%rcx) 3f: 48 rex.W Code starting with the faulting instruction =========================================== 0: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax 6: 73 01 jae 0x9 8: c3 ret 9: 48 8b 0d 4f 86 0d 00 mov 0xd864f(%rip),%rcx # 0xd865f 10: f7 d8 neg %eax 12: 64 89 01 mov %eax,%fs:(%rcx) 15: 48 rex.W [ 3.882300][ T1] RSP: 002b:00007ffcd8cbbc88 EFLAGS: 00000246 ORIG_RAX: 0000000000000141 [ 3.883149][ T1] RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 00007f3570834779 [ 3.883966][ T1] RDX: 0000000000000094 RSI: 00007ffcd8cbbd10 RDI: 0000000000000005 [ 3.884774][ T1] RBP: 0000000000000013 R08: 00007ffcd8cbbe40 R09: 0000559a2fc27b30 [ 3.885594][ T1] R10: 0000000000000013 R11: 0000000000000246 R12: 0000000000000094 [ 3.886456][ T1] R13: 00007ffcd8cbbd10 R14: 00007ffcd8cbbd10 R15: 0000000000000008 [ 3.887273][ T1] </TASK> [ 3.887627][ T1] Modules linked in: [ 3.888071][ T1] ---[ end trace 0000000000000000 ]--- [ 3.888642][ T1] RIP: 0010:__vunmap_range_noflush (vmalloc.c:501) [ 3.889273][ T1] Code: 7c 24 10 48 83 c4 58 5b 41 5c 41 5d 41 5e 41 5f 5d e9 7c 9d d2 ff 48 83 c4 58 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc <0f> 0b 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 All code ======== 0: 7c 24 jl 0x26 2: 10 48 83 adc %cl,-0x7d(%rax) 5: c4 (bad) 6: 58 pop %rax 7: 5b pop %rbx 8: 41 5c pop %r12 a: 41 5d pop %r13 c: 41 5e pop %r14 e: 41 5f pop %r15 10: 5d pop %rbp 11: e9 7c 9d d2 ff jmp 0xffffffffffd29d92 16: 48 83 c4 58 add $0x58,%rsp 1a: 5b pop %rbx 1b: 41 5c pop %r12 1d: 41 5d pop %r13 1f: 41 5e pop %r14 21: 41 5f pop %r15 23: 5d pop %rbp 24: c3 ret 25: cc int3 26: cc int3 27: cc int3 28: cc int3 29: cc int3 2a:* 0f 0b ud2 <-- trapping instruction 2c: 66 66 66 66 66 66 2e data16 data16 data16 data16 data16 cs nopw 0x0(%rax,%rax,1) 33: 0f 1f 84 00 00 00 00 3a: 00 3b: 0f .byte 0xf 3c: 1f (bad) 3d: 80 00 00 addb $0x0,(%rax) Code starting with the faulting instruction =========================================== 0: 0f 0b ud2 2: 66 66 66 66 66 66 2e data16 data16 data16 data16 data16 cs nopw 0x0(%rax,%rax,1) 9: 0f 1f 84 00 00 00 00 10: 00 11: 0f .byte 0xf 12: 1f (bad) 13: 80 00 00 addb $0x0,(%rax) The kernel config and materials to reproduce are available at: https://download.01.org/0day-ci/archive/20260523/202605231524.731e5313-lkp@intel.com -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing 2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya 2026-05-23 13:34 ` kernel test robot @ 2026-05-23 16:20 ` Uladzislau Rezki 2026-05-24 2:53 ` Jill Ravaliya 1 sibling, 1 reply; 7+ messages in thread From: Uladzislau Rezki @ 2026-05-23 16:20 UTC (permalink / raw) To: Jill Ravaliya; +Cc: akpm, urezki, linux-mm, linux-kernel On Thu, May 07, 2026 at 05:18:54PM +0530, Jill Ravaliya wrote: > Add a selftest that verifies vrealloc() frees physical pages > when shrinking an allocation. > > The test loads a kernel module that: > 1. Allocates 10MB with vmalloc() > 2. Touches all pages to force physical allocation > 3. Shrinks to 2MB with vrealloc() > 4. Verifies free page count increased after shrink > > Without the fix, the test fails because no pages are freed. > With the fix applied, the test passes confirming ~2048 pages > are returned to the system after shrinking from 10MB to 2MB. > > Tested on kernel 7.0.0 in QEMU. > > Signed-off-by: Jill Ravaliya <jillravaliya@gmail.com> > --- > tools/testing/selftests/mm/Makefile | 5 ++ > .../selftests/mm/vrealloc_shrink_test.c | 65 +++++++++++++++++++ > 2 files changed, 70 insertions(+) > create mode 100644 tools/testing/selftests/mm/vrealloc_shrink_test.c > > diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile > index cd24596cd..4eab7c76c 100644 > --- a/tools/testing/selftests/mm/Makefile > +++ b/tools/testing/selftests/mm/Makefile > @@ -104,6 +104,7 @@ TEST_GEN_FILES += hugetlb_dio > TEST_GEN_FILES += droppable > TEST_GEN_FILES += guard-regions > TEST_GEN_FILES += merge > +TEST_GEN_FILES += vrealloc_shrink_test > TEST_GEN_FILES += rmap > TEST_GEN_FILES += folio_split_race_test > > @@ -282,3 +283,7 @@ warn_missing_page_frag: > echo "Warning: $(PAGE_FRAG_WARNING). page_frag test will be skipped." ; \ > echo > endif > + > +# vrealloc shrink test module > +vrealloc_shrink_mod.ko: vrealloc_shrink_mod.c > + $(MAKE) -C $(KDIR) M=$(PWD) modules > diff --git a/tools/testing/selftests/mm/vrealloc_shrink_test.c b/tools/testing/selftests/mm/vrealloc_shrink_test.c > new file mode 100644 > index 000000000..cf4263074 > --- /dev/null > +++ b/tools/testing/selftests/mm/vrealloc_shrink_test.c > @@ -0,0 +1,65 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Test that vrealloc() frees physical pages when shrinking. > + * > + * vrealloc() shrink path previously zeroed unused memory and updated > + * vm->requested_size, but never freed the physical pages backing the > + * unused portion of the allocation. This test verifies the fix by > + * loading a kernel module that directly measures nr_pages before and > + * after vrealloc() shrink. > + * > + * Copyright (C) 2026 Jill Ravaliya > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <fcntl.h> > +#include "../kselftest.h" > + > +#define MODULE_NAME "vrealloc_shrink_mod" > +#define DMESG_PASS "vrealloc_shrink: PASS" > +#define DMESG_FAIL "vrealloc_shrink: FAIL" > + > +static int run_cmd(const char *cmd) > +{ > + return system(cmd); > +} > + > +static int check_dmesg_for(const char *pattern) > +{ > + char cmd[256]; > + snprintf(cmd, sizeof(cmd), > + "dmesg | grep -q '%s'", pattern); > + return system(cmd) == 0; > +} > + > +int main(void) > +{ > + ksft_print_header(); > + ksft_set_plan(1); > + > + /* Insert the test module */ > + if (run_cmd("insmod " MODULE_NAME ".ko") != 0) { > + ksft_test_result_skip( > + "could not load %s.ko - is it built?\n", > + MODULE_NAME); > + ksft_finished(); > + } > + > + /* Check dmesg for pass/fail */ > + if (check_dmesg_for(DMESG_PASS)) { > + ksft_test_result_pass( > + "vrealloc shrink frees physical pages\n"); > + } else if (check_dmesg_for(DMESG_FAIL)) { > + ksft_test_result_fail( > + "vrealloc shrink did NOT free physical pages\n"); > + } else { > + ksft_test_result_fail( > + "could not find test result in dmesg\n"); > + } > + > + run_cmd("rmmod " MODULE_NAME); > + ksft_finished(); > +} > -- > 2.43.0 > We have a test case that covers vrealloc() functionality. See test_vmalloc.c file. -- Uladzislau Rezki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing 2026-05-23 16:20 ` Uladzislau Rezki @ 2026-05-24 2:53 ` Jill Ravaliya 0 siblings, 0 replies; 7+ messages in thread From: Jill Ravaliya @ 2026-05-24 2:53 UTC (permalink / raw) To: Uladzislau Rezki; +Cc: akpm, linux-mm, linux-kernel Hey Uladzislau, Thanks for pointing that out. I'll check test_vmalloc.c right away. Jill On Sat, May 23, 2026 at 9:50 PM Uladzislau Rezki <urezki@gmail.com> wrote: > > On Thu, May 07, 2026 at 05:18:54PM +0530, Jill Ravaliya wrote: > > Add a selftest that verifies vrealloc() frees physical pages > > when shrinking an allocation. > > > > The test loads a kernel module that: > > 1. Allocates 10MB with vmalloc() > > 2. Touches all pages to force physical allocation > > 3. Shrinks to 2MB with vrealloc() > > 4. Verifies free page count increased after shrink > > > > Without the fix, the test fails because no pages are freed. > > With the fix applied, the test passes confirming ~2048 pages > > are returned to the system after shrinking from 10MB to 2MB. > > > > Tested on kernel 7.0.0 in QEMU. > > > > Signed-off-by: Jill Ravaliya <jillravaliya@gmail.com> > > --- > > tools/testing/selftests/mm/Makefile | 5 ++ > > .../selftests/mm/vrealloc_shrink_test.c | 65 +++++++++++++++++++ > > 2 files changed, 70 insertions(+) > > create mode 100644 tools/testing/selftests/mm/vrealloc_shrink_test.c > > > > diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile > > index cd24596cd..4eab7c76c 100644 > > --- a/tools/testing/selftests/mm/Makefile > > +++ b/tools/testing/selftests/mm/Makefile > > @@ -104,6 +104,7 @@ TEST_GEN_FILES += hugetlb_dio > > TEST_GEN_FILES += droppable > > TEST_GEN_FILES += guard-regions > > TEST_GEN_FILES += merge > > +TEST_GEN_FILES += vrealloc_shrink_test > > TEST_GEN_FILES += rmap > > TEST_GEN_FILES += folio_split_race_test > > > > @@ -282,3 +283,7 @@ warn_missing_page_frag: > > echo "Warning: $(PAGE_FRAG_WARNING). page_frag test will be skipped." ; \ > > echo > > endif > > + > > +# vrealloc shrink test module > > +vrealloc_shrink_mod.ko: vrealloc_shrink_mod.c > > + $(MAKE) -C $(KDIR) M=$(PWD) modules > > diff --git a/tools/testing/selftests/mm/vrealloc_shrink_test.c b/tools/testing/selftests/mm/vrealloc_shrink_test.c > > new file mode 100644 > > index 000000000..cf4263074 > > --- /dev/null > > +++ b/tools/testing/selftests/mm/vrealloc_shrink_test.c > > @@ -0,0 +1,65 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Test that vrealloc() frees physical pages when shrinking. > > + * > > + * vrealloc() shrink path previously zeroed unused memory and updated > > + * vm->requested_size, but never freed the physical pages backing the > > + * unused portion of the allocation. This test verifies the fix by > > + * loading a kernel module that directly measures nr_pages before and > > + * after vrealloc() shrink. > > + * > > + * Copyright (C) 2026 Jill Ravaliya > > + */ > > + > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > +#include "../kselftest.h" > > + > > +#define MODULE_NAME "vrealloc_shrink_mod" > > +#define DMESG_PASS "vrealloc_shrink: PASS" > > +#define DMESG_FAIL "vrealloc_shrink: FAIL" > > + > > +static int run_cmd(const char *cmd) > > +{ > > + return system(cmd); > > +} > > + > > +static int check_dmesg_for(const char *pattern) > > +{ > > + char cmd[256]; > > + snprintf(cmd, sizeof(cmd), > > + "dmesg | grep -q '%s'", pattern); > > + return system(cmd) == 0; > > +} > > + > > +int main(void) > > +{ > > + ksft_print_header(); > > + ksft_set_plan(1); > > + > > + /* Insert the test module */ > > + if (run_cmd("insmod " MODULE_NAME ".ko") != 0) { > > + ksft_test_result_skip( > > + "could not load %s.ko - is it built?\n", > > + MODULE_NAME); > > + ksft_finished(); > > + } > > + > > + /* Check dmesg for pass/fail */ > > + if (check_dmesg_for(DMESG_PASS)) { > > + ksft_test_result_pass( > > + "vrealloc shrink frees physical pages\n"); > > + } else if (check_dmesg_for(DMESG_FAIL)) { > > + ksft_test_result_fail( > > + "vrealloc shrink did NOT free physical pages\n"); > > + } else { > > + ksft_test_result_fail( > > + "could not find test result in dmesg\n"); > > + } > > + > > + run_cmd("rmmod " MODULE_NAME); > > + ksft_finished(); > > +} > > -- > > 2.43.0 > > > We have a test case that covers vrealloc() functionality. See test_vmalloc.c > file. > > -- > Uladzislau Rezki ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation 2026-05-07 11:48 [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Jill Ravaliya 2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya @ 2026-05-07 17:17 ` Uladzislau Rezki 2026-05-07 20:26 ` [syzbot ci] " syzbot ci 2 siblings, 0 replies; 7+ messages in thread From: Uladzislau Rezki @ 2026-05-07 17:17 UTC (permalink / raw) To: Jill Ravaliya; +Cc: akpm, urezki, linux-mm, linux-kernel, Shivam Kalra On Thu, May 07, 2026 at 05:18:53PM +0530, Jill Ravaliya wrote: > vrealloc() shrink path zeros unused memory and updates > vm->requested_size, but never frees the physical pages, > removes page table mappings, or flushes the TLB for the > unused range. > > When a caller shrinks a vmalloc allocation, physical pages > backing the unused portion remain allocated until vfree() > is eventually called, wasting real RAM. > > Fix this by unmapping the unused virtual range using > vunmap_range() which also flushes the TLB, freeing each > unused physical page back to the buddy allocator, and > updating vm->nr_pages to reflect the new page count. > > Signed-off-by: Jill Ravaliya <jillravaliya@gmail.com> > --- > mm/vmalloc.c | 21 +++++++++++++++++++++ > 1 file changed, 21 insertions(+) > > diff --git a/mm/vmalloc.c b/mm/vmalloc.c > index aa08651ec..a8cedfc5d 100644 > --- a/mm/vmalloc.c > +++ b/mm/vmalloc.c > @@ -4336,6 +4336,27 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align > memset((void *)p + size, 0, old_size - size); > vm->requested_size = size; > kasan_vrealloc(p, old_size, size); > + > + /* Shrink the vm_area: unmap and free unused pages. */ > + if (size < alloced_size) { > + unsigned long new_nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; > + unsigned long i; > + > + /* Unmap unused virtual range and flush TLB. */ > + vunmap_range((unsigned long)p + PAGE_ALIGN(size), > + (unsigned long)p + alloced_size); > + > + /* Free unused physical pages back to buddy allocator. */ > + for (i = new_nr_pages; i < vm->nr_pages; i++) { > + mod_lruvec_page_state(vm->pages[i], > + NR_VMALLOC, -1); > + __free_page(vm->pages[i]); > + vm->pages[i] = NULL; > + } > + > + vm->nr_pages = new_nr_pages; > + } > + > return (void *)p; > } > > -- > 2.43.0 > There is already work to address this: https://lore.kernel.org/all/20260428-vmalloc-shrink-v12-0-3c18c9172eb1@zohomail.in/ -- Uladzislau Rezki ^ permalink raw reply [flat|nested] 7+ messages in thread
* [syzbot ci] Re: mm/vmalloc: free unused pages when shrinking vrealloc() allocation 2026-05-07 11:48 [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Jill Ravaliya 2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya 2026-05-07 17:17 ` [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Uladzislau Rezki @ 2026-05-07 20:26 ` syzbot ci 2 siblings, 0 replies; 7+ messages in thread From: syzbot ci @ 2026-05-07 20:26 UTC (permalink / raw) To: akpm, jillravaliya, linux-kernel, linux-mm, urezki; +Cc: syzbot, syzkaller-bugs syzbot ci has tested the following series [v1] mm/vmalloc: free unused pages when shrinking vrealloc() allocation https://lore.kernel.org/all/20260507114854.41117-1-jillravaliya@gmail.com * [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation * [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing and found the following issue: kernel BUG in __vunmap_range_noflush Full report is available here: https://ci.syzbot.org/series/13b0874e-a9f8-4992-be93-e93cc88e5e44 *** kernel BUG in __vunmap_range_noflush tree: torvalds URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux base: 2c340aab5485ebe9e33c01437dd4815ef33c8df5 arch: amd64 compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8 config: https://ci.syzbot.org/builds/625f7138-9b20-4205-b0e7-02ed1219bd31/config syz repro: https://ci.syzbot.org/findings/13e8dc07-d697-4345-a27f-319e9c1fe3d6/syz_repro ------------[ cut here ]------------ kernel BUG at mm/vmalloc.c:488! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 1 UID: 0 PID: 5824 Comm: syz.2.19 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 RIP: 0010:__vunmap_range_noflush+0xb4d/0xb70 mm/vmalloc.c:488 Code: 00 e9 64 f5 ff ff e8 12 8d a6 ff 48 c7 c7 a0 0e a8 8e 48 8b 74 24 48 48 89 da e8 0e c5 cf 02 e9 67 f5 ff ff e8 f4 8c a6 ff 90 <0f> 0b e8 ec 8c a6 ff e9 53 ff ff ff e8 e2 8c a6 ff bb 02 00 00 00 RSP: 0018:ffffc90003b575e0 EFLAGS: 00010293 RAX: ffffffff821f16bc RBX: ffffc900036fa000 RCX: ffff8881072a1d80 RDX: 0000000000000000 RSI: ffffc900036fa000 RDI: ffffc900036fa000 RBP: ffff88816ebb3980 R08: ffff88810007f1bb R09: 0000000000000000 R10: ffffc900036f9bb0 R11: ffffed102000fe38 R12: 0000000000000001 R13: ffffc900036fa000 R14: ffffc900036fa000 R15: dffffc0000000000 FS: 00007f4d6b8c46c0(0000) GS:ffff8882a9293000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055924f0dd8c0 CR3: 00000001057f2000 CR4: 00000000000006f0 Call Trace: <TASK> vunmap_range_noflush mm/vmalloc.c:506 [inline] vunmap_range mm/vmalloc.c:521 [inline] vrealloc_node_align_noprof+0x4fc/0x880 mm/vmalloc.c:4346 bpf_patch_insn_data+0xeb/0x10a0 kernel/bpf/fixups.c:254 bpf_convert_ctx_accesses+0x213f/0x2d70 kernel/bpf/fixups.c:974 bpf_check+0x2b8e/0x49f0 kernel/bpf/verifier.c:20094 bpf_prog_load+0x1406/0x1a10 kernel/bpf/syscall.c:3082 __sys_bpf+0x618/0x950 kernel/bpf/syscall.c:6248 __do_sys_bpf kernel/bpf/syscall.c:6361 [inline] __se_sys_bpf kernel/bpf/syscall.c:6359 [inline] __x64_sys_bpf+0x7c/0x90 kernel/bpf/syscall.c:6359 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f4d6a99cdd9 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f4d6b8c4028 EFLAGS: 00000246 ORIG_RAX: 0000000000000141 RAX: ffffffffffffffda RBX: 00007f4d6ac15fa0 RCX: 00007f4d6a99cdd9 RDX: 0000000000000048 RSI: 00002000000054c0 RDI: 0000000000000005 RBP: 00007f4d6aa32d69 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f4d6ac16038 R14: 00007f4d6ac15fa0 R15: 00007ffff714fc08 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:__vunmap_range_noflush+0xb4d/0xb70 mm/vmalloc.c:488 Code: 00 e9 64 f5 ff ff e8 12 8d a6 ff 48 c7 c7 a0 0e a8 8e 48 8b 74 24 48 48 89 da e8 0e c5 cf 02 e9 67 f5 ff ff e8 f4 8c a6 ff 90 <0f> 0b e8 ec 8c a6 ff e9 53 ff ff ff e8 e2 8c a6 ff bb 02 00 00 00 RSP: 0018:ffffc90003b575e0 EFLAGS: 00010293 RAX: ffffffff821f16bc RBX: ffffc900036fa000 RCX: ffff8881072a1d80 RDX: 0000000000000000 RSI: ffffc900036fa000 RDI: ffffc900036fa000 RBP: ffff88816ebb3980 R08: ffff88810007f1bb R09: 0000000000000000 R10: ffffc900036f9bb0 R11: ffffed102000fe38 R12: 0000000000000001 R13: ffffc900036fa000 R14: ffffc900036fa000 R15: dffffc0000000000 FS: 00007f4d6b8c46c0(0000) GS:ffff8882a9293000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ffdaf55afd8 CR3: 00000001057f2000 CR4: 00000000000006f0 *** If these findings have caused you to resend the series or submit a separate fix, please add the following tag to your commit message: Tested-by: syzbot@syzkaller.appspotmail.com --- This report is generated by a bot. It may contain errors. syzbot ci engineers can be reached at syzkaller@googlegroups.com. To test a patch for this bug, please reply with `#syz test` (should be on a separate line). The patch should be attached to the email. Note: arguments like custom git repos and branches are not supported. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-24 2:53 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-07 11:48 [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Jill Ravaliya 2026-05-07 11:48 ` [PATCH 2/2] selftests/mm: add test for vrealloc() shrink page freeing Jill Ravaliya 2026-05-23 13:34 ` kernel test robot 2026-05-23 16:20 ` Uladzislau Rezki 2026-05-24 2:53 ` Jill Ravaliya 2026-05-07 17:17 ` [PATCH 1/2] mm/vmalloc: free unused pages when shrinking vrealloc() allocation Uladzislau Rezki 2026-05-07 20:26 ` [syzbot ci] " syzbot ci
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox