Commit 42b2eb69 authored by Usama Arif's avatar Usama Arif Committed by Andrew Morton
Browse files

mm: convert partially_mapped set/clear operations to be atomic

Other page flags in the 2nd page, like PG_hwpoison and PG_anon_exclusive
can get modified concurrently.  Changes to other page flags might be lost
if they are happening at the same time as non-atomic partially_mapped
operations.  Hence, make partially_mapped operations atomic.

Link: https://lkml.kernel.org/r/20241212183351.1345389-1-usamaarif642@gmail.com


Fixes: 8422acdc ("mm: introduce a pageflag for partially mapped folios")
Reported-by: default avatarDavid Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/all/e53b04ad-1827-43a2-a1ab-864c7efecf6e@redhat.com/


Signed-off-by: default avatarUsama Arif <usamaarif642@gmail.com>
Acked-by: default avatarDavid Hildenbrand <david@redhat.com>
Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
Acked-by: default avatarRoman Gushchin <roman.gushchin@linux.dev>
Cc: Barry Song <baohua@kernel.org>
Cc: Domenico Cerasuolo <cerasuolodomenico@gmail.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Yu Zhao <yuzhao@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 6309b8ce
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -862,18 +862,10 @@ static inline void ClearPageCompound(struct page *page)
	ClearPageHead(page);
}
FOLIO_FLAG(large_rmappable, FOLIO_SECOND_PAGE)
FOLIO_TEST_FLAG(partially_mapped, FOLIO_SECOND_PAGE)
/*
 * PG_partially_mapped is protected by deferred_split split_queue_lock,
 * so its safe to use non-atomic set/clear.
 */
__FOLIO_SET_FLAG(partially_mapped, FOLIO_SECOND_PAGE)
__FOLIO_CLEAR_FLAG(partially_mapped, FOLIO_SECOND_PAGE)
FOLIO_FLAG(partially_mapped, FOLIO_SECOND_PAGE)
#else
FOLIO_FLAG_FALSE(large_rmappable)
FOLIO_TEST_FLAG_FALSE(partially_mapped)
__FOLIO_SET_FLAG_NOOP(partially_mapped)
__FOLIO_CLEAR_FLAG_NOOP(partially_mapped)
FOLIO_FLAG_FALSE(partially_mapped)
#endif

#define PG_head_mask ((1UL << PG_head))
+4 −4
Original line number Diff line number Diff line
@@ -3577,7 +3577,7 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
		    !list_empty(&folio->_deferred_list)) {
			ds_queue->split_queue_len--;
			if (folio_test_partially_mapped(folio)) {
				__folio_clear_partially_mapped(folio);
				folio_clear_partially_mapped(folio);
				mod_mthp_stat(folio_order(folio),
					      MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1);
			}
@@ -3689,7 +3689,7 @@ bool __folio_unqueue_deferred_split(struct folio *folio)
	if (!list_empty(&folio->_deferred_list)) {
		ds_queue->split_queue_len--;
		if (folio_test_partially_mapped(folio)) {
			__folio_clear_partially_mapped(folio);
			folio_clear_partially_mapped(folio);
			mod_mthp_stat(folio_order(folio),
				      MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1);
		}
@@ -3733,7 +3733,7 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
	spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
	if (partially_mapped) {
		if (!folio_test_partially_mapped(folio)) {
			__folio_set_partially_mapped(folio);
			folio_set_partially_mapped(folio);
			if (folio_test_pmd_mappable(folio))
				count_vm_event(THP_DEFERRED_SPLIT_PAGE);
			count_mthp_stat(folio_order(folio), MTHP_STAT_SPLIT_DEFERRED);
@@ -3826,7 +3826,7 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
		} else {
			/* We lost race with folio_put() */
			if (folio_test_partially_mapped(folio)) {
				__folio_clear_partially_mapped(folio);
				folio_clear_partially_mapped(folio);
				mod_mthp_stat(folio_order(folio),
					      MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1);
			}