Skip to content

Commit 2f78910

Browse files
x-y-zakpm00
authored andcommitted
mm/huge_memory: make min_order_for_split() always return an order
min_order_for_split() returns -EBUSY when the folio is truncated and cannot be split. In commit 77008e1 ("mm/huge_memory: do not change split_huge_page*() target order silently"), memory_failure() does not handle it and pass -EBUSY to try_to_split_thp_page() directly. try_to_split_thp_page() returns -EINVAL since -EBUSY becomes 0xfffffff0 as new_order is unsigned int in __folio_split() and this large new_order is rejected as an invalid input. The code does not cause a bug. soft_offline_in_use_page() also uses min_order_for_split() but it always passes 0 as new_order for split. Fix it by making min_order_for_split() always return an order. When the given folio is truncated, namely folio->mapping == NULL, return 0 and let a subsequent split function handle the situation and return -EBUSY. Add kernel-doc to min_order_for_split() to clarify its use. Link: https://lkml.kernel.org/r/20251126210618.1971206-4-ziy@nvidia.com Signed-off-by: Zi Yan <ziy@nvidia.com> Reviewed-by: Wei Yang <richard.weiyang@gmail.com> Acked-by: David Hildenbrand (Red Hat) <david@kernel.org> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Balbir Singh <balbirs@nvidia.com> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Barry Song <baohua@kernel.org> Cc: Dev Jain <dev.jain@arm.com> Cc: Lance Yang <lance.yang@linux.dev> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Miaohe Lin <linmiaohe@huawei.com> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: Nico Pache <npache@redhat.com> Cc: Ryan Roberts <ryan.roberts@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 5842bcb commit 2f78910

2 files changed

Lines changed: 22 additions & 9 deletions

File tree

include/linux/huge_mm.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ enum split_type {
372372
int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
373373
unsigned int new_order);
374374
int folio_split_unmapped(struct folio *folio, unsigned int new_order);
375-
int min_order_for_split(struct folio *folio);
375+
unsigned int min_order_for_split(struct folio *folio);
376376
int split_folio_to_list(struct folio *folio, struct list_head *list);
377377
int folio_check_splittable(struct folio *folio, unsigned int new_order,
378378
enum split_type split_type);
@@ -630,10 +630,10 @@ static inline int split_huge_page(struct page *page)
630630
return -EINVAL;
631631
}
632632

633-
static inline int min_order_for_split(struct folio *folio)
633+
static inline unsigned int min_order_for_split(struct folio *folio)
634634
{
635635
VM_WARN_ON_ONCE_FOLIO(1, folio);
636-
return -EINVAL;
636+
return 0;
637637
}
638638

639639
static inline int split_folio_to_list(struct folio *folio, struct list_head *list)

mm/huge_memory.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4219,16 +4219,29 @@ int folio_split(struct folio *folio, unsigned int new_order,
42194219
SPLIT_TYPE_NON_UNIFORM);
42204220
}
42214221

4222-
int min_order_for_split(struct folio *folio)
4222+
/**
4223+
* min_order_for_split() - get the minimum order @folio can be split to
4224+
* @folio: folio to split
4225+
*
4226+
* min_order_for_split() tells the minimum order @folio can be split to.
4227+
* If a file-backed folio is truncated, 0 will be returned. Any subsequent
4228+
* split attempt should get -EBUSY from split checking code.
4229+
*
4230+
* Return: @folio's minimum order for split
4231+
*/
4232+
unsigned int min_order_for_split(struct folio *folio)
42234233
{
42244234
if (folio_test_anon(folio))
42254235
return 0;
42264236

4227-
if (!folio->mapping) {
4228-
if (folio_test_pmd_mappable(folio))
4229-
count_vm_event(THP_SPLIT_PAGE_FAILED);
4230-
return -EBUSY;
4231-
}
4237+
/*
4238+
* If the folio got truncated, we don't know the previous mapping and
4239+
* consequently the old min order. But it doesn't matter, as any split
4240+
* attempt will immediately fail with -EBUSY as the folio cannot get
4241+
* split until freed.
4242+
*/
4243+
if (!folio->mapping)
4244+
return 0;
42324245

42334246
return mapping_min_folio_order(folio->mapping);
42344247
}

0 commit comments

Comments
 (0)