* Forwarded: [PATCH] hugetlbfs: skip VMAs without locks in hugetlb_vmdelete_list
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
@ 2025-09-25 10:40 ` syzbot
2025-09-25 13:43 ` Forwarded: [PATCH] hugetlbfs: skip non-shareable VMAs " syzbot
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-09-25 10:40 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] hugetlbfs: skip VMAs without locks in hugetlb_vmdelete_list
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
hugetlb_vmdelete_list() can call unmap_hugepage_range() on VMAs that
have no associated lock, causing assertion failures in huge_pmd_unshare().
The function hugetlb_vma_trylock_write() returns 1 (success) even when
a VMA has neither a shareable lock nor a private lock. This allows
processing to continue, but when unmap_hugepage_range() is called, it
eventually reaches huge_pmd_unshare() which calls hugetlb_vma_assert_locked()
to verify a lock is held. The assertion fails because no lock was actually
acquired.
This results in a kernel panic:
WARNING: CPU: 1 PID: 6594 Comm: syz.0.28 Not tainted
Call Trace:
hugetlb_vma_assert_locked+0x1dd/0x250
huge_pmd_unshare+0x2c8/0x540
__unmap_hugepage_range+0x6e3/0x1aa0
unmap_hugepage_range+0x32e/0x410
hugetlb_vmdelete_list+0x189/0x1f0
Fix by skipping VMAs that have no lock before calling unmap_hugepage_range(),
as the unmap operation requires lock protection.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/hugetlbfs/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9e0625167517..d2ecd83848e5 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -487,7 +487,8 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
if (!hugetlb_vma_trylock_write(vma))
continue;
-
+ if (!__vma_shareable_lock(vma) && !__vma_private_lock(vma))
+ continue;
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH] hugetlbfs: skip non-shareable VMAs in hugetlb_vmdelete_list
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
2025-09-25 10:40 ` Forwarded: [PATCH] hugetlbfs: skip VMAs without locks in hugetlb_vmdelete_list syzbot
@ 2025-09-25 13:43 ` syzbot
2025-09-25 23:19 ` Forwarded: [PATCH v2] hugetlbfs: skip VMAs without shareable locks " syzbot
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-09-25 13:43 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] hugetlbfs: skip non-shareable VMAs in hugetlb_vmdelete_list
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
hugetlb_vmdelete_list() processes VMAs from the i_mmap interval tree
during truncate operations. This tree should only contain shareable
(VM_MAYSHARE) mappings, as private mappings are handled through
different code paths.
However, VMAs without shareable locks can incorrectly appear in this
path, causing assertion failures in huge_pmd_unshare() when it calls
hugetlb_vma_assert_locked(). The assertion expects a lock to be held
for the VMA being processed.
When hugetlb_vma_trylock_write() succeeds but the VMA has no shareable
lock (__vma_shareable_lock returns false), the code proceeds to call
unmap_hugepage_range(). Inside this function, huge_pmd_unshare() calls
hugetlb_vma_assert_locked() which fails because no lock is actually held,
resulting in a kernel panic:
WARNING: CPU: 1 PID: 6594 Comm: syz.0.28 Not tainted
Call Trace:
hugetlb_vma_assert_locked+0x1dd/0x250
huge_pmd_unshare+0x2c8/0x540
__unmap_hugepage_range+0x6e3/0x1aa0
unmap_hugepage_range+0x32e/0x410
hugetlb_vmdelete_list+0x189/0x1f0
Fix by skipping VMAs that don't have a shareable lock. These VMAs
should not be in the shared mapping deletion path and are handled
by separate code paths for private mappings.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/hugetlbfs/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9e0625167517..9ba98cab3388 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -487,7 +487,8 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
if (!hugetlb_vma_trylock_write(vma))
continue;
-
+ if (!__vma_shareable_lock(vma))
+ continue;
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
2025-09-25 10:40 ` Forwarded: [PATCH] hugetlbfs: skip VMAs without locks in hugetlb_vmdelete_list syzbot
2025-09-25 13:43 ` Forwarded: [PATCH] hugetlbfs: skip non-shareable VMAs " syzbot
@ 2025-09-25 23:19 ` syzbot
2025-09-25 23:19 ` syzbot
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-09-25 23:19 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
hugetlb_vmdelete_list() uses trylock to acquire VMA locks during truncate
operations. As per the original design in commit 40549ba8f8e0 ("hugetlb:
use new vma_lock for pmd sharing synchronization"), if the trylock fails
or the VMA has no lock, it should skip that VMA. Any remaining mapped
pages are handled by remove_inode_hugepages() which is called after
hugetlb_vmdelete_list() and uses proper lock ordering to guarantee
unmapping success.
Currently, when hugetlb_vma_trylock_write() returns success (1) for VMAs
without shareable locks, the code proceeds to call unmap_hugepage_range().
This causes assertion failures in huge_pmd_unshare() → hugetlb_vma_assert_locked()
because no lock is actually held:
WARNING: CPU: 1 PID: 6594 Comm: syz.0.28 Not tainted
Call Trace:
hugetlb_vma_assert_locked+0x1dd/0x250
huge_pmd_unshare+0x2c8/0x540
__unmap_hugepage_range+0x6e3/0x1aa0
unmap_hugepage_range+0x32e/0x410
hugetlb_vmdelete_list+0x189/0x1f0
Fix by checking for shareable lock before attempting trylock, avoiding
both the assertion failure and potential lock leaks from skipping VMAs
after locks are acquired.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: 40549ba8f8e0 ("hugetlb: use new vma_lock for pmd sharing synchronization")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v2:
- Check for shareable lock before trylock to avoid lock leaks (Andrew Morton)
- Add comment explaining why non-shareable VMAs are skipped (Andrew Morton)
---
fs/hugetlbfs/inode.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9e0625167517..44943e97adb0 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -484,6 +484,13 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
vma_interval_tree_foreach(vma, root, start, end ? end - 1 : ULONG_MAX) {
unsigned long v_start;
unsigned long v_end;
+ /*
+ * Skip VMAs without shareable locks. Per the design in commit
+ * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
+ * called after this function with proper locking.
+ */
+ if (!__vma_shareable_lock(vma))
+ continue;
if (!hugetlb_vma_trylock_write(vma))
continue;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (2 preceding siblings ...)
2025-09-25 23:19 ` Forwarded: [PATCH v2] hugetlbfs: skip VMAs without shareable locks " syzbot
@ 2025-09-25 23:19 ` syzbot
2025-09-26 0:32 ` syzbot
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-09-25 23:19 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
hugetlb_vmdelete_list() uses trylock to acquire VMA locks during truncate
operations. As per the original design in commit 40549ba8f8e0 ("hugetlb:
use new vma_lock for pmd sharing synchronization"), if the trylock fails
or the VMA has no lock, it should skip that VMA. Any remaining mapped
pages are handled by remove_inode_hugepages() which is called after
hugetlb_vmdelete_list() and uses proper lock ordering to guarantee
unmapping success.
Currently, when hugetlb_vma_trylock_write() returns success (1) for VMAs
without shareable locks, the code proceeds to call unmap_hugepage_range().
This causes assertion failures in huge_pmd_unshare() → hugetlb_vma_assert_locked()
because no lock is actually held:
WARNING: CPU: 1 PID: 6594 Comm: syz.0.28 Not tainted
Call Trace:
hugetlb_vma_assert_locked+0x1dd/0x250
huge_pmd_unshare+0x2c8/0x540
__unmap_hugepage_range+0x6e3/0x1aa0
unmap_hugepage_range+0x32e/0x410
hugetlb_vmdelete_list+0x189/0x1f0
Fix by checking for shareable lock before attempting trylock, avoiding
both the assertion failure and potential lock leaks from skipping VMAs
after locks are acquired.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: 40549ba8f8e0 ("hugetlb: use new vma_lock for pmd sharing synchronization")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v2:
- Check for shareable lock before trylock to avoid lock leaks (Andrew Morton)
- Add comment explaining why non-shareable VMAs are skipped (Andrew Morton)
---
fs/hugetlbfs/inode.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9e0625167517..44943e97adb0 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -484,6 +484,13 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
vma_interval_tree_foreach(vma, root, start, end ? end - 1 : ULONG_MAX) {
unsigned long v_start;
unsigned long v_end;
+ /*
+ * Skip VMAs without shareable locks. Per the design in commit
+ * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
+ * called after this function with proper locking.
+ */
+ if (!__vma_shareable_lock(vma))
+ continue;
if (!hugetlb_vma_trylock_write(vma))
continue;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (3 preceding siblings ...)
2025-09-25 23:19 ` syzbot
@ 2025-09-26 0:32 ` syzbot
2025-10-03 16:11 ` Forwarded: [PATCH] hugetlbfs: skip PMD unsharing when shareable lock unavailable syzbot
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-09-26 0:32 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v2] hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
hugetlb_vmdelete_list() uses trylock to acquire VMA locks during truncate
operations. As per the original design in commit 40549ba8f8e0 ("hugetlb:
use new vma_lock for pmd sharing synchronization"), if the trylock fails
or the VMA has no lock, it should skip that VMA. Any remaining mapped
pages are handled by remove_inode_hugepages() which is called after
hugetlb_vmdelete_list() and uses proper lock ordering to guarantee
unmapping success.
Currently, when hugetlb_vma_trylock_write() returns success (1) for VMAs
without shareable locks, the code proceeds to call unmap_hugepage_range().
This causes assertion failures in huge_pmd_unshare() → hugetlb_vma_assert_locked()
because no lock is actually held:
WARNING: CPU: 1 PID: 6594 Comm: syz.0.28 Not tainted
Call Trace:
hugetlb_vma_assert_locked+0x1dd/0x250
huge_pmd_unshare+0x2c8/0x540
__unmap_hugepage_range+0x6e3/0x1aa0
unmap_hugepage_range+0x32e/0x410
hugetlb_vmdelete_list+0x189/0x1f0
Fix by using goto to ensure locks acquired by trylock are always released, even
when skipping VMAs without shareable locks.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: 40549ba8f8e0 ("hugetlb: use new vma_lock for pmd sharing synchronization")
Suggested-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v2:
- Use goto to unlock after trylock, avoiding lock leaks (Andrew Morton)
- Add comment explaining why non-shareable VMAs are skipped (Andrew Morton)
---
fs/hugetlbfs/inode.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9e0625167517..9fa7c72ac1a6 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -488,6 +488,14 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
if (!hugetlb_vma_trylock_write(vma))
continue;
+ /*
+ * Skip VMAs without shareable locks. Per the design in commit
+ * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
+ * called after this function with proper locking.
+ */
+ if (!__vma_shareable_lock(vma))
+ goto skip;
+
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
@@ -498,7 +506,8 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
* vmas. Therefore, lock is not held when calling
* unmap_hugepage_range for private vmas.
*/
- hugetlb_vma_unlock_write(vma);
+skip:
+ hugetlb_vma_unlock_write(vma);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH] hugetlbfs: skip PMD unsharing when shareable lock unavailable
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (4 preceding siblings ...)
2025-09-26 0:32 ` syzbot
@ 2025-10-03 16:11 ` syzbot
2025-10-07 6:01 ` Forwarded: [PATCH v4] hugetlbfs: check for shareable lock before calling huge_pmd_unshare() syzbot
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-10-03 16:11 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] hugetlbfs: skip PMD unsharing when shareable lock unavailable
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
When hugetlb_vmdelete_list() cannot acquire the shareable lock for a VMA,
the original code skipped the entire VMA, leaving pages unmapped. This
caused a regression where pages were not freed during fallocate(PUNCH_HOLE)
operations, as reported by Mark Brown.
The issue occurs because:
1. hugetlb_vmdelete_list() tries to acquire the VMA lock
2. For shareable VMAs, this includes the shareable lock via
hugetlb_vma_trylock_write()
3. If successful and VMA is shareable type, we have the shareable lock
4. huge_pmd_unshare() requires this lock and asserts it is held
The previous fix (dd83609b8898) avoided the assertion by skipping entire
VMAs without shareable locks, but this prevented pages from being unmapped
and freed, breaking PUNCH_HOLE behavior.
This fix takes a different approach: instead of skipping the VMA entirely,
we skip only the PMD unsharing operation when we don't have the required
lock, while still proceeding with page unmapping. This is safe because:
- PMD unsharing is an optimization to reduce shared page table overhead
- Page unmapping can proceed safely with just the VMA write lock
- Pages get freed immediately as expected by PUNCH_HOLE callers
We add a new ZAP_FLAG_NO_UNSHARE flag to communicate to
__unmap_hugepage_range() that it should skip huge_pmd_unshare() while
still clearing page table entries and freeing pages.
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Reported-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/all/20251003150956.2870745-1-kartikey406@gmail.com/T/
Signed-off-by: Deepanshu Kartikey <Kartikey406@gmail.com>
---
fs/hugetlbfs/inode.c | 22 ++++++++++++----------
include/linux/mm.h | 2 ++
mm/hugetlb.c | 3 ++-
3 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9c94ed8c3ab0..519497bc1045 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -474,29 +474,31 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
vma_interval_tree_foreach(vma, root, start, end ? end - 1 : ULONG_MAX) {
unsigned long v_start;
unsigned long v_end;
+ bool have_shareable_lock;
+ zap_flags_t local_flags = zap_flags;
if (!hugetlb_vma_trylock_write(vma))
continue;
-
+
+ have_shareable_lock = __vma_shareable_lock(vma);
+
/*
- * Skip VMAs without shareable locks. Per the design in commit
- * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
- * called after this function with proper locking.
+ * If we can't get the shareable lock, set ZAP_FLAG_NO_UNSHARE
+ * to skip PMD unsharing. We still proceed with unmapping to
+ * ensure pages are properly freed, which is critical for punch
+ * hole operations that expect immediate page freeing.
*/
- if (!__vma_shareable_lock(vma))
- goto skip;
-
+ if (!have_shareable_lock)
+ local_flags |= ZAP_FLAG_NO_UNSHARE;
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
- unmap_hugepage_range(vma, v_start, v_end, NULL, zap_flags);
-
+ unmap_hugepage_range(vma, v_start, v_end, NULL, local_flags);
/*
* Note that vma lock only exists for shared/non-private
* vmas. Therefore, lock is not held when calling
* unmap_hugepage_range for private vmas.
*/
-skip:
hugetlb_vma_unlock_write(vma);
}
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 06978b4dbeb8..9126ab44320d 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2395,6 +2395,8 @@ struct zap_details {
#define ZAP_FLAG_DROP_MARKER ((__force zap_flags_t) BIT(0))
/* Set in unmap_vmas() to indicate a final unmap call. Only used by hugetlb */
#define ZAP_FLAG_UNMAP ((__force zap_flags_t) BIT(1))
+/* Skip PMD unsharing when unmapping hugetlb ranges without shareable lock */
+#define ZAP_FLAG_NO_UNSHARE ((__force zap_flags_t) BIT(2))
#ifdef CONFIG_SCHED_MM_CID
void sched_mm_cid_before_execve(struct task_struct *t);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6cac826cb61f..c4257aa568fe 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5885,7 +5885,8 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
}
ptl = huge_pte_lock(h, mm, ptep);
- if (huge_pmd_unshare(mm, vma, address, ptep)) {
+ if (!(zap_flags & ZAP_FLAG_NO_UNSHARE) &&
+ huge_pmd_unshare(mm, vma, address, ptep)) {
spin_unlock(ptl);
tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
force_flush = true;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v4] hugetlbfs: check for shareable lock before calling huge_pmd_unshare()
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (5 preceding siblings ...)
2025-10-03 16:11 ` Forwarded: [PATCH] hugetlbfs: skip PMD unsharing when shareable lock unavailable syzbot
@ 2025-10-07 6:01 ` syzbot
2025-10-14 0:40 ` Forwarded: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare() syzbot
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-10-07 6:01 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v4] hugetlbfs: check for shareable lock before calling huge_pmd_unshare()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
When hugetlb_vmdelete_list() processes VMAs during truncate operations,
it may encounter VMAs where huge_pmd_unshare() is called without the
required shareable lock. This triggers an assertion failure in
hugetlb_vma_assert_locked().
The previous fix in commit dd83609b8898 ("hugetlbfs: skip VMAs without
shareable locks in hugetlb_vmdelete_list") skipped entire VMAs without
shareable locks to avoid the assertion. However, this prevented pages
from being unmapped and freed, causing a regression in fallocate(PUNCH_HOLE)
operations where pages were not freed immediately, as reported by Mark Brown.
Instead of skipping VMAs or adding new flags, check __vma_shareable_lock()
directly in __unmap_hugepage_range() right before calling huge_pmd_unshare().
This ensures PMD unsharing only happens when the VMA has a shareable lock
structure, while still allowing page unmapping and freeing to proceed for
all VMAs.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Reported-by: Mark Brown <broonie@kernel.org>
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Suggested-by: Oscar Salvador <osalvador@suse.de>
Suggested-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/mm-commits/20250925203504.7BE02C4CEF7@smtp.kernel.org/ [v1]
Link: https://lore.kernel.org/mm-commits/20250928185232.BEDB6C4CEF0@smtp.kernel.org/ [v2]
Link: https://lore.kernel.org/linux-mm/20251003174553.3078839-1-kartikey406@gmail.com/ [v3]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v4:
- Simplified approach per Oscar's suggestion: check __vma_shareable_lock()
directly in __unmap_hugepage_range() before calling huge_pmd_unshare()
- Removed ZAP_FLAG_NO_UNSHARE flag per David's feedback to avoid polluting
generic mm.h header
- Reverted hugetlb_vmdelete_list() to not skip VMAs
Changes in v3:
- Added ZAP_FLAG_NO_UNSHARE to skip only PMD unsharing, not entire VMA
Changes in v2:
- Skip entire VMAs without shareable locks in hugetlb_vmdelete_list()
(caused PUNCH_HOLE regression)
Changes in v1:
- Initial fix attempt
---
fs/hugetlbfs/inode.c | 10 +---------
mm/hugetlb.c | 2 +-
2 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9c94ed8c3ab0..1e040db18b20 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -478,14 +478,6 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
if (!hugetlb_vma_trylock_write(vma))
continue;
- /*
- * Skip VMAs without shareable locks. Per the design in commit
- * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
- * called after this function with proper locking.
- */
- if (!__vma_shareable_lock(vma))
- goto skip;
-
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
@@ -496,7 +488,7 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
* vmas. Therefore, lock is not held when calling
* unmap_hugepage_range for private vmas.
*/
-skip:
+
hugetlb_vma_unlock_write(vma);
}
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6cac826cb61f..9ed85ab8420e 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5885,7 +5885,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
}
ptl = huge_pte_lock(h, mm, ptep);
- if (huge_pmd_unshare(mm, vma, address, ptep)) {
+ if (__vma_shareable_lock(vma) && huge_pmd_unshare(mm, vma, address, ptep)) {
spin_unlock(ptl);
tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
force_flush = true;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (6 preceding siblings ...)
2025-10-07 6:01 ` Forwarded: [PATCH v4] hugetlbfs: check for shareable lock before calling huge_pmd_unshare() syzbot
@ 2025-10-14 0:40 ` syzbot
2025-10-14 3:35 ` syzbot
2025-10-14 4:14 ` Forwarded: [PATCH v6] " syzbot
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-10-14 0:40 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
When hugetlb_vmdelete_list() processes VMAs during truncate operations,
it may encounter VMAs where huge_pmd_unshare() is called without the
required shareable lock. This triggers an assertion failure in
hugetlb_vma_assert_locked().
The previous fix in commit dd83609b8898 ("hugetlbfs: skip VMAs without
shareable locks in hugetlb_vmdelete_list") skipped entire VMAs without
shareable locks to avoid the assertion. However, this prevented pages
from being unmapped and freed, causing a regression in fallocate(PUNCH_HOLE)
operations where pages were not freed immediately, as reported by Mark Brown.
Instead of checking locks in the caller or skipping VMAs, move the lock
assertions in huge_pmd_unshare() to after the early return checks. The
assertions are only needed when actual PMD unsharing work will be performed.
If the function returns early because sz != PMD_SIZE or the PMD is not
shared, no locks are required and assertions should not fire.
This is cleaner than previous approaches because it keeps all the logic
within huge_pmd_unshare() itself, while still allowing page unmapping and
freeing to proceed for all VMAs.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Link: https://lore.kernel.org/mm-commits/20250925203504.7BE02C4CEF7@smtp.kernel.org/ [v1]
Link: https://lore.kernel.org/mm-commits/20250928185232.BEDB6C4CEF0@smtp.kernel.org/ [v2]
Link: https://lore.kernel.org/linux-mm/20251003174553.3078839-1-kartikey406@gmail.com/ [v3]
Link: https://lore.kernel.org/linux-mm/20251008052759.469714-1-kartikey406@gmail.com/ [v4]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v5:
- Move lock assertions after early return checks in huge_pmd_unshare()
per David's suggestion - cleaner approach that keeps logic within the
function itself
- Revert all previous approaches (VMA skipping, flag additions, caller checks)
Changes in v4:
- Check __vma_shareable_lock() in __unmap_hugepage_range() before calling
huge_pmd_unshare() per Oscar's suggestion
- Remove ZAP_FLAG_NO_UNSHARE flag per David's feedback
Changes in v3:
- Add ZAP_FLAG_NO_UNSHARE to skip only PMD unsharing, not entire VMA
Changes in v2:
- Skip entire VMAs without shareable locks (caused PUNCH_HOLE regression)
Changes in v1:
- Initial fix attempt
---
mm/hugetlb.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 795ee393eac0..0455119716ec 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -7614,13 +7614,12 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
- i_mmap_assert_write_locked(vma->vm_file->f_mapping);
- hugetlb_vma_assert_locked(vma);
if (sz != PMD_SIZE)
return 0;
if (!ptdesc_pmd_is_shared(virt_to_ptdesc(ptep)))
return 0;
-
+ i_mmap_assert_write_locked(vma->vm_file->f_mapping);
+ hugetlb_vma_assert_locked(vma);
pud_clear(pud);
/*
* Once our caller drops the rmap lock, some other process might be
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (7 preceding siblings ...)
2025-10-14 0:40 ` Forwarded: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare() syzbot
@ 2025-10-14 3:35 ` syzbot
2025-10-14 4:14 ` Forwarded: [PATCH v6] " syzbot
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-10-14 3:35 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v5] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
When hugetlb_vmdelete_list() processes VMAs during truncate operations,
it may encounter VMAs where huge_pmd_unshare() is called without the
required shareable lock. This triggers an assertion failure in
hugetlb_vma_assert_locked().
The previous fix in commit dd83609b8898 ("hugetlbfs: skip VMAs without
shareable locks in hugetlb_vmdelete_list") skipped entire VMAs without
shareable locks to avoid the assertion. However, this prevented pages
from being unmapped and freed, causing a regression in fallocate(PUNCH_HOLE)
operations where pages were not freed immediately, as reported by Mark Brown.
Instead of checking locks in the caller or skipping VMAs, move the lock
assertions in huge_pmd_unshare() to after the early return checks. The
assertions are only needed when actual PMD unsharing work will be performed.
If the function returns early because sz != PMD_SIZE or the PMD is not
shared, no locks are required and assertions should not fire.
This is cleaner than previous approaches because it keeps all the logic
within huge_pmd_unshare() itself, while still allowing page unmapping and
freeing to proceed for all VMAs.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Link: https://lore.kernel.org/mm-commits/20250925203504.7BE02C4CEF7@smtp.kernel.org/ [v1]
Link: https://lore.kernel.org/mm-commits/20250928185232.BEDB6C4CEF0@smtp.kernel.org/ [v2]
Link: https://lore.kernel.org/linux-mm/20251003174553.3078839-1-kartikey406@gmail.com/ [v3]
Link: https://lore.kernel.org/linux-mm/20251008052759.469714-1-kartikey406@gmail.com/ [v4]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v5:
- Move lock assertions after early return checks in huge_pmd_unshare()
per David's suggestion - cleaner approach that keeps logic within the
function itself
- Revert all previous approaches (VMA skipping, flag additions, caller checks)
Changes in v4:
- Check __vma_shareable_lock() in __unmap_hugepage_range() before calling
huge_pmd_unshare() per Oscar's suggestion
- Remove ZAP_FLAG_NO_UNSHARE flag per David's feedback
Changes in v3:
- Add ZAP_FLAG_NO_UNSHARE to skip only PMD unsharing, not entire VMA
Changes in v2:
- Skip entire VMAs without shareable locks (caused PUNCH_HOLE regression)
Changes in v1:
- Initial fix attempt
---
fs/hugetlbfs/inode.c | 10 +---------
mm/hugetlb.c | 5 ++---
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9c94ed8c3ab0..1e040db18b20 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -478,14 +478,6 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
if (!hugetlb_vma_trylock_write(vma))
continue;
- /*
- * Skip VMAs without shareable locks. Per the design in commit
- * 40549ba8f8e0, these will be handled by remove_inode_hugepages()
- * called after this function with proper locking.
- */
- if (!__vma_shareable_lock(vma))
- goto skip;
-
v_start = vma_offset_start(vma, start);
v_end = vma_offset_end(vma, end);
@@ -496,7 +488,7 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end,
* vmas. Therefore, lock is not held when calling
* unmap_hugepage_range for private vmas.
*/
-skip:
+
hugetlb_vma_unlock_write(vma);
}
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 795ee393eac0..0455119716ec 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -7614,13 +7614,12 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
- i_mmap_assert_write_locked(vma->vm_file->f_mapping);
- hugetlb_vma_assert_locked(vma);
if (sz != PMD_SIZE)
return 0;
if (!ptdesc_pmd_is_shared(virt_to_ptdesc(ptep)))
return 0;
-
+ i_mmap_assert_write_locked(vma->vm_file->f_mapping);
+ hugetlb_vma_assert_locked(vma);
pud_clear(pud);
/*
* Once our caller drops the rmap lock, some other process might be
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* Forwarded: [PATCH v6] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
2025-09-23 9:03 [syzbot] [mm?] WARNING in hugetlb_vma_assert_locked syzbot
` (8 preceding siblings ...)
2025-10-14 3:35 ` syzbot
@ 2025-10-14 4:14 ` syzbot
9 siblings, 0 replies; 11+ messages in thread
From: syzbot @ 2025-10-14 4:14 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v6] hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
When hugetlb_vmdelete_list() processes VMAs during truncate operations,
it may encounter VMAs where huge_pmd_unshare() is called without the
required shareable lock. This triggers an assertion failure in
hugetlb_vma_assert_locked().
The previous fix in commit dd83609b8898 ("hugetlbfs: skip VMAs without
shareable locks in hugetlb_vmdelete_list") skipped entire VMAs without
shareable locks to avoid the assertion. However, this prevented pages
from being unmapped and freed, causing a regression in fallocate(PUNCH_HOLE)
operations where pages were not freed immediately, as reported by Mark Brown.
A subsequent fix in commit 06e8ca1b3dca ("hugetlbfs: check for shareable
lock before calling huge_pmd_unshare()") addressed this by checking
__vma_shareable_lock() in the caller before calling huge_pmd_unshare().
However, a cleaner approach is to move the lock assertions in
huge_pmd_unshare() itself to after the early return checks. The assertions
are only needed when actual PMD unsharing work will be performed. If the
function returns early because sz != PMD_SIZE or the PMD is not shared,
no locks are required.
This patch removes the check added in commit 06e8ca1b3dca ("hugetlbfs:
check for shareable lock before calling huge_pmd_unshare()") and instead
moves the assertions inside huge_pmd_unshare(), keeping all the logic
within the function itself.
Reported-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Tested-by: syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com
Link: https://lore.kernel.org/mm-commits/20250925203504.7BE02C4CEF7@smtp.kernel.org/ [v1]
Link: https://lore.kernel.org/mm-commits/20250928185232.BEDB6C4CEF0@smtp.kernel.org/ [v2]
Link: https://lore.kernel.org/linux-mm/20251003174553.3078839-1-kartikey406@gmail.com/ [v3]
Link: https://lore.kernel.org/linux-mm/20251008052759.469714-1-kartikey406@gmail.com/ [v4]
Link: https://lore.kernel.org/linux-mm/CADhLXY72yEVDjXWfxBUXfXhNfb8MWqwJmcb1daEHmDeFW+DRGw@mail.gmail.com/ [v5]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v6:
- Remove __vma_shareable_lock() check from __unmap_hugepage_range()
that was added in v4 (commit 06e8ca1b3dca)
- Move lock assertions after early returns in huge_pmd_unshare()
- Complete implementation of David's cleaner approach
Changes in v5:
- Incomplete: only moved assertions, forgot to remove v4 check
Changes in v4:
- Check __vma_shareable_lock() in __unmap_hugepage_range() before calling
huge_pmd_unshare() per Oscar's suggestion
Changes in v3:
- Add ZAP_FLAG_NO_UNSHARE to skip only PMD unsharing
Changes in v2:
- Skip entire VMAs without shareable locks (caused PUNCH_HOLE regression)
Changes in v1:
- Initial fix attempt
---
mm/hugetlb.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 85b2dac79d25..0455119716ec 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5885,7 +5885,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
}
ptl = huge_pte_lock(h, mm, ptep);
- if (__vma_shareable_lock(vma) && huge_pmd_unshare(mm, vma, address, ptep)) {
+ if (huge_pmd_unshare(mm, vma, address, ptep)) {
spin_unlock(ptl);
tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
force_flush = true;
@@ -7614,13 +7614,12 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
- i_mmap_assert_write_locked(vma->vm_file->f_mapping);
- hugetlb_vma_assert_locked(vma);
if (sz != PMD_SIZE)
return 0;
if (!ptdesc_pmd_is_shared(virt_to_ptdesc(ptep)))
return 0;
-
+ i_mmap_assert_write_locked(vma->vm_file->f_mapping);
+ hugetlb_vma_assert_locked(vma);
pud_clear(pud);
/*
* Once our caller drops the rmap lock, some other process might be
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread