]> www.infradead.org Git - users/hch/misc.git/commitdiff
hugetlbfs: move lock assertions after early returns in huge_pmd_unshare()
authorDeepanshu Kartikey <kartikey406@gmail.com>
Tue, 14 Oct 2025 11:33:44 +0000 (17:03 +0530)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 21 Oct 2025 22:46:17 +0000 (15:46 -0700)
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 approach reverts the VMA skipping logic from commit dd83609b8898
("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
while moving the assertions to avoid the assertion failure, keeping all
the logic within huge_pmd_unshare() itself and allowing page unmapping and
freeing to proceed for all VMAs.

Link: https://lkml.kernel.org/r/20251014113344.21194-1-kartikey406@gmail.com
Fixes: dd83609b8898 ("hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Reported-by: <syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com>
Reported-by: Mark Brown <broonie@kernel.org>
Closes: https://syzkaller.appspot.com/bug?extid=f26d7c75c26ec19790e7
Suggested-by: David Hildenbrand <david@redhat.com>
Suggested-by: Oscar Salvador <osalvador@suse.de>
Tested-by: <syzbot+f26d7c75c26ec19790e7@syzkaller.appspotmail.com>
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/hugetlbfs/inode.c
mm/hugetlb.c

index 9c94ed8c3ab0028772b7afb5d03a91d280c38106..f42548ee9083c6bf4b20f9a75e069e5f69fdfc3a 100644 (file)
@@ -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,6 @@ 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);
        }
 }
index 795ee393eac037a029c0c4f760c22352a81f1540..0455119716ec0c57c779bc91c2b885d095ab4aad 100644 (file)
@@ -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