From: Xueyuan Chen get_huge_zero_folio() uses huge_zero_refcount as the publication gate for lockless users. However, it publishes huge_zero_folio with cmpxchg() before storing huge_zero_pfn and initializes the refcount with an unordered atomic_set(). On weakly ordered systems, a racing atomic_inc_not_zero() can observe the nonzero refcount without observing the huge_zero_pfn store. is_huge_zero_pmd() can then misidentify a huge zero PMD as a regular anonymous THP. The write-protect fault path may consequently mark the global huge zero folio anonymous, exclusive and writable. Use atomic_set_release() to publish the initialized folio and PFN. A successful atomic_inc_not_zero() is fully ordered, so a reader that obtains a reference also observes the state published before the refcount became nonzero. Fixes: 97ae17497e99 ("thp: implement refcounting for huge zero page") Cc: stable@vger.kernel.org Signed-off-by: Xueyuan Chen --- mm/huge_memory.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 032702a4637b..6c74d0375377 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -245,8 +245,11 @@ static bool get_huge_zero_folio(void) } WRITE_ONCE(huge_zero_pfn, folio_pfn(zero_folio)); - /* We take additional reference here. It will be put back by shrinker */ - atomic_set(&huge_zero_refcount, 2); + /* + * Publish the folio and PFN before making them available to lockless + * users. Pairs with a successful atomic_inc_not_zero() above. + */ + atomic_set_release(&huge_zero_refcount, 2); preempt_enable(); count_vm_event(THP_ZERO_PAGE_ALLOC); return true; -- 2.47.3