Skip to content

Commit 0ea3356

Browse files
hygoniSasha Levin
authored andcommitted
mm/page_alloc: skip debug_check_no_{obj,locks}_freed with FPI_TRYLOCK
[ Upstream commit 338ad1e ] When CONFIG_DEBUG_OBJECTS_FREE is enabled, debug_check_no_{obj,locks}_freed() functions are called. Since both of them spin on a lock, they are not safe to be called if the FPI_TRYLOCK flag is specified. This leads to a lockdep splat: ================================ WARNING: inconsistent lock state 6.19.0-rc5-slab-for-next+ #326 Tainted: G N -------------------------------- inconsistent {INITIAL USE} -> {IN-NMI} usage. kunit_try_catch/9046 [HC2[2]:SC0[0]:HE0:SE1] takes: ffffffff84ed6bf8 (&obj_hash[i].lock){-.-.}-{2:2}, at: __debug_check_no_obj_freed+0xe0/0x300 {INITIAL USE} state was registered at: lock_acquire+0xd9/0x2f0 _raw_spin_lock_irqsave+0x4c/0x80 __debug_object_init+0x9d/0x1f0 debug_object_init+0x34/0x50 __init_work+0x28/0x40 init_cgroup_housekeeping+0x151/0x210 init_cgroup_root+0x3d/0x140 cgroup_init_early+0x30/0x240 start_kernel+0x3e/0xcd0 x86_64_start_reservations+0x18/0x30 x86_64_start_kernel+0xf3/0x140 common_startup_64+0x13e/0x148 irq event stamp: 2998 hardirqs last enabled at (2997): [<ffffffff8298b77a>] exc_nmi+0x11a/0x240 hardirqs last disabled at (2998): [<ffffffff8298b991>] sysvec_irq_work+0x11/0x110 softirqs last enabled at (1416): [<ffffffff813c1f72>] __irq_exit_rcu+0x132/0x1c0 softirqs last disabled at (1303): [<ffffffff813c1f72>] __irq_exit_rcu+0x132/0x1c0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&obj_hash[i].lock); <Interrupt> lock(&obj_hash[i].lock); *** DEADLOCK *** Rename free_pages_prepare() to __free_pages_prepare(), add an fpi_t parameter, and skip those checks if FPI_TRYLOCK is set. To keep the fpi_t definition in mm/page_alloc.c, add a wrapper function free_pages_prepare() that always passes FPI_NONE and use it in mm/compaction.c. Link: https://lkml.kernel.org/r/20260209062639.16577-1-harry.yoo@oracle.com Fixes: 8c57b68 ("mm, bpf: Introduce free_pages_nolock()") Signed-off-by: Harry Yoo <harry.yoo@oracle.com> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Acked-by: Zi Yan <ziy@nvidia.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Brendan Jackman <jackmanb@google.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Shakeel Butt <shakeel.butt@linux.dev> Cc: Suren Baghdasaryan <surenb@google.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent f055897 commit 0ea3356

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

mm/page_alloc.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,8 +1340,8 @@ static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr)
13401340

13411341
#endif /* CONFIG_MEM_ALLOC_PROFILING */
13421342

1343-
__always_inline bool free_pages_prepare(struct page *page,
1344-
unsigned int order)
1343+
__always_inline bool __free_pages_prepare(struct page *page,
1344+
unsigned int order, fpi_t fpi_flags)
13451345
{
13461346
int bad = 0;
13471347
bool skip_kasan_poison = should_skip_kasan_poison(page);
@@ -1434,7 +1434,7 @@ __always_inline bool free_pages_prepare(struct page *page,
14341434
page_table_check_free(page, order);
14351435
pgalloc_tag_sub(page, 1 << order);
14361436

1437-
if (!PageHighMem(page)) {
1437+
if (!PageHighMem(page) && !(fpi_flags & FPI_TRYLOCK)) {
14381438
debug_check_no_locks_freed(page_address(page),
14391439
PAGE_SIZE << order);
14401440
debug_check_no_obj_freed(page_address(page),
@@ -1473,6 +1473,11 @@ __always_inline bool free_pages_prepare(struct page *page,
14731473
return true;
14741474
}
14751475

1476+
bool free_pages_prepare(struct page *page, unsigned int order)
1477+
{
1478+
return __free_pages_prepare(page, order, FPI_NONE);
1479+
}
1480+
14761481
/*
14771482
* Frees a number of pages from the PCP lists
14781483
* Assumes all pages on list are in same zone.
@@ -1606,7 +1611,7 @@ static void __free_pages_ok(struct page *page, unsigned int order,
16061611
unsigned long pfn = page_to_pfn(page);
16071612
struct zone *zone = page_zone(page);
16081613

1609-
if (free_pages_prepare(page, order))
1614+
if (__free_pages_prepare(page, order, fpi_flags))
16101615
free_one_page(zone, page, pfn, order, fpi_flags);
16111616
}
16121617

@@ -2970,7 +2975,7 @@ static void __free_frozen_pages(struct page *page, unsigned int order,
29702975
return;
29712976
}
29722977

2973-
if (!free_pages_prepare(page, order))
2978+
if (!__free_pages_prepare(page, order, fpi_flags))
29742979
return;
29752980

29762981
/*
@@ -3027,7 +3032,7 @@ void free_unref_folios(struct folio_batch *folios)
30273032
unsigned long pfn = folio_pfn(folio);
30283033
unsigned int order = folio_order(folio);
30293034

3030-
if (!free_pages_prepare(&folio->page, order))
3035+
if (!__free_pages_prepare(&folio->page, order, FPI_NONE))
30313036
continue;
30323037
/*
30333038
* Free orders not handled on the PCP directly to the

0 commit comments

Comments
 (0)