Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/hugetlb: add missing hugetlb_lock in __unmap_hugepage_range()

When restoring a reservation for an anonymous page, we need to check to
freeing a surplus. However, __unmap_hugepage_range() causes data race
because it reads h->surplus_huge_pages without the protection of
hugetlb_lock.

And adjust_reservation is a boolean variable that indicates whether
reservations for anonymous pages in each folio should be restored.
Therefore, it should be initialized to false for each round of the loop.
However, this variable is not initialized to false except when defining
the current adjust_reservation variable.

This means that once adjust_reservation is set to true even once within
the loop, reservations for anonymous pages will be restored
unconditionally in all subsequent rounds, regardless of the folio's state.

To fix this, we need to add the missing hugetlb_lock, unlock the
page_table_lock earlier so that we don't lock the hugetlb_lock inside the
page_table_lock lock, and initialize adjust_reservation to false on each
round within the loop.

Link: https://lkml.kernel.org/r/20250823182115.1193563-1-aha310510@gmail.com
Fixes: df7a6d1f6405 ("mm/hugetlb: restore the reservation if needed")
Signed-off-by: Jeongjun Park <aha310510@gmail.com>
Reported-by: syzbot+417aeb05fd190f3a6da9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=417aeb05fd190f3a6da9
Reviewed-by: Sidhartha Kumar <sidhartha.kumar@oracle.com>
Cc: Breno Leitao <leitao@debian.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Jeongjun Park and committed by
Andrew Morton
21cc2b5c 669602b5

+6 -3
+6 -3
mm/hugetlb.c
··· 5851 5851 spinlock_t *ptl; 5852 5852 struct hstate *h = hstate_vma(vma); 5853 5853 unsigned long sz = huge_page_size(h); 5854 - bool adjust_reservation = false; 5854 + bool adjust_reservation; 5855 5855 unsigned long last_addr_mask; 5856 5856 bool force_flush = false; 5857 5857 ··· 5944 5944 sz); 5945 5945 hugetlb_count_sub(pages_per_huge_page(h), mm); 5946 5946 hugetlb_remove_rmap(folio); 5947 + spin_unlock(ptl); 5947 5948 5948 5949 /* 5949 5950 * Restore the reservation for anonymous page, otherwise the ··· 5952 5951 * If there we are freeing a surplus, do not set the restore 5953 5952 * reservation bit. 5954 5953 */ 5954 + adjust_reservation = false; 5955 + 5956 + spin_lock_irq(&hugetlb_lock); 5955 5957 if (!h->surplus_huge_pages && __vma_private_lock(vma) && 5956 5958 folio_test_anon(folio)) { 5957 5959 folio_set_hugetlb_restore_reserve(folio); 5958 5960 /* Reservation to be adjusted after the spin lock */ 5959 5961 adjust_reservation = true; 5960 5962 } 5961 - 5962 - spin_unlock(ptl); 5963 + spin_unlock_irq(&hugetlb_lock); 5963 5964 5964 5965 /* 5965 5966 * Adjust the reservation for the region that will have the