Skip to content

Commit 98fdd2f

Browse files
kirylgregkh
authored andcommitted
mm/page_alloc: fix race condition in unaccepted memory handling
commit fefc075 upstream. The page allocator tracks the number of zones that have unaccepted memory using static_branch_enc/dec() and uses that static branch in hot paths to determine if it needs to deal with unaccepted memory. Borislav and Thomas pointed out that the tracking is racy: operations on static_branch are not serialized against adding/removing unaccepted pages to/from the zone. Sanity checks inside static_branch machinery detects it: WARNING: CPU: 0 PID: 10 at kernel/jump_label.c:276 __static_key_slow_dec_cpuslocked+0x8e/0xa0 The comment around the WARN() explains the problem: /* * Warn about the '-1' case though; since that means a * decrement is concurrent with a first (0->1) increment. IOW * people are trying to disable something that wasn't yet fully * enabled. This suggests an ordering problem on the user side. */ The effect of this static_branch optimization is only visible on microbenchmark. Instead of adding more complexity around it, remove it altogether. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Kirill A. Shutemov <[email protected]> Fixes: dcdfdd4 ("mm: Add support for unaccepted memory") Link: https://lore.kernel.org/all/20250506092445.GBaBnVXXyvnazly6iF@fat_crate.local Reported-by: Borislav Petkov <[email protected]> Tested-by: Borislav Petkov (AMD) <[email protected]> Reported-by: Thomas Gleixner <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Suren Baghdasaryan <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Brendan Jackman <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: <[email protected]> [6.5+] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e24073c commit 98fdd2f

File tree

1 file changed

+0
-27
lines changed

1 file changed

+0
-27
lines changed

mm/page_alloc.c

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ EXPORT_SYMBOL(nr_online_nodes);
303303
static bool page_contains_unaccepted(struct page *page, unsigned int order);
304304
static void accept_page(struct page *page, unsigned int order);
305305
static bool cond_accept_memory(struct zone *zone, unsigned int order);
306-
static inline bool has_unaccepted_memory(void);
307306
static bool __free_unaccepted(struct page *page);
308307

309308
int page_group_by_mobility_disabled __read_mostly;
@@ -6586,9 +6585,6 @@ bool has_managed_dma(void)
65866585

65876586
#ifdef CONFIG_UNACCEPTED_MEMORY
65886587

6589-
/* Counts number of zones with unaccepted pages. */
6590-
static DEFINE_STATIC_KEY_FALSE(zones_with_unaccepted_pages);
6591-
65926588
static bool lazy_accept = true;
65936589

65946590
static int __init accept_memory_parse(char *p)
@@ -6624,7 +6620,6 @@ static bool try_to_accept_memory_one(struct zone *zone)
66246620
{
66256621
unsigned long flags;
66266622
struct page *page;
6627-
bool last;
66286623

66296624
spin_lock_irqsave(&zone->lock, flags);
66306625
page = list_first_entry_or_null(&zone->unaccepted_pages,
@@ -6635,7 +6630,6 @@ static bool try_to_accept_memory_one(struct zone *zone)
66356630
}
66366631

66376632
list_del(&page->lru);
6638-
last = list_empty(&zone->unaccepted_pages);
66396633

66406634
__mod_zone_freepage_state(zone, -MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE);
66416635
__mod_zone_page_state(zone, NR_UNACCEPTED, -MAX_ORDER_NR_PAGES);
@@ -6645,9 +6639,6 @@ static bool try_to_accept_memory_one(struct zone *zone)
66456639

66466640
__free_pages_ok(page, MAX_ORDER, FPI_TO_TAIL);
66476641

6648-
if (last)
6649-
static_branch_dec(&zones_with_unaccepted_pages);
6650-
66516642
return true;
66526643
}
66536644

@@ -6656,9 +6647,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order)
66566647
long to_accept, wmark;
66576648
bool ret = false;
66586649

6659-
if (!has_unaccepted_memory())
6660-
return false;
6661-
66626650
if (list_empty(&zone->unaccepted_pages))
66636651
return false;
66646652

@@ -6688,30 +6676,20 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order)
66886676
return ret;
66896677
}
66906678

6691-
static inline bool has_unaccepted_memory(void)
6692-
{
6693-
return static_branch_unlikely(&zones_with_unaccepted_pages);
6694-
}
6695-
66966679
static bool __free_unaccepted(struct page *page)
66976680
{
66986681
struct zone *zone = page_zone(page);
66996682
unsigned long flags;
6700-
bool first = false;
67016683

67026684
if (!lazy_accept)
67036685
return false;
67046686

67056687
spin_lock_irqsave(&zone->lock, flags);
6706-
first = list_empty(&zone->unaccepted_pages);
67076688
list_add_tail(&page->lru, &zone->unaccepted_pages);
67086689
__mod_zone_freepage_state(zone, MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE);
67096690
__mod_zone_page_state(zone, NR_UNACCEPTED, MAX_ORDER_NR_PAGES);
67106691
spin_unlock_irqrestore(&zone->lock, flags);
67116692

6712-
if (first)
6713-
static_branch_inc(&zones_with_unaccepted_pages);
6714-
67156693
return true;
67166694
}
67176695

@@ -6731,11 +6709,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order)
67316709
return false;
67326710
}
67336711

6734-
static inline bool has_unaccepted_memory(void)
6735-
{
6736-
return false;
6737-
}
6738-
67396712
static bool __free_unaccepted(struct page *page)
67406713
{
67416714
BUILD_BUG();

0 commit comments

Comments
 (0)