Skip to content

Commit 6a50c9b

Browse files
ranxiaokaiakpm00
authored andcommitted
mm: huge_memory: fix misused mapping_large_folio_support() for anon folios
When I did a large folios split test, a WARNING "[ 5059.122759][ T166] Cannot split file folio to non-0 order" was triggered. But the test cases are only for anonmous folios. while mapping_large_folio_support() is only reasonable for page cache folios. In split_huge_page_to_list_to_order(), the folio passed to mapping_large_folio_support() maybe anonmous folio. The folio_test_anon() check is missing. So the split of the anonmous THP is failed. This is also the same for shmem_mapping(). We'd better add a check for both. But the shmem_mapping() in __split_huge_page() is not involved, as for anonmous folios, the end parameter is set to -1, so (head[i].index >= end) is always false. shmem_mapping() is not called. Also add a VM_WARN_ON_ONCE() in mapping_large_folio_support() for anon mapping, So we can detect the wrong use more easily. THP folios maybe exist in the pagecache even the file system doesn't support large folio, it is because when CONFIG_TRANSPARENT_HUGEPAGE is enabled, khugepaged will try to collapse read-only file-backed pages to THP. But the mapping does not actually support multi order large folios properly. Using /sys/kernel/debug/split_huge_pages to verify this, with this patch, large anon THP is successfully split and the warning is ceased. Link: https://lkml.kernel.org/r/[email protected] Fixes: c010d47 ("mm: thp: split huge page to any lower order pages") Reviewed-by: Barry Song <[email protected]> Reviewed-by: Zi Yan <[email protected]> Acked-by: David Hildenbrand <[email protected]> Signed-off-by: Ran Xiaokai <[email protected]> Cc: Michal Hocko <[email protected]> Cc: xu xin <[email protected]> Cc: Yang Yang <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent a273559 commit 6a50c9b

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

include/linux/pagemap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ static inline void mapping_set_large_folios(struct address_space *mapping)
381381
*/
382382
static inline bool mapping_large_folio_support(struct address_space *mapping)
383383
{
384+
/* AS_LARGE_FOLIO_SUPPORT is only reasonable for pagecache folios */
385+
VM_WARN_ONCE((unsigned long)mapping & PAGE_MAPPING_ANON,
386+
"Anonymous mapping always supports large folio");
387+
384388
return IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
385389
test_bit(AS_LARGE_FOLIO_SUPPORT, &mapping->flags);
386390
}

mm/huge_memory.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,30 +3009,36 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
30093009
if (new_order >= folio_order(folio))
30103010
return -EINVAL;
30113011

3012-
/* Cannot split anonymous THP to order-1 */
3013-
if (new_order == 1 && folio_test_anon(folio)) {
3014-
VM_WARN_ONCE(1, "Cannot split to order-1 folio");
3015-
return -EINVAL;
3016-
}
3017-
3018-
if (new_order) {
3019-
/* Only swapping a whole PMD-mapped folio is supported */
3020-
if (folio_test_swapcache(folio))
3012+
if (folio_test_anon(folio)) {
3013+
/* order-1 is not supported for anonymous THP. */
3014+
if (new_order == 1) {
3015+
VM_WARN_ONCE(1, "Cannot split to order-1 folio");
30213016
return -EINVAL;
3017+
}
3018+
} else if (new_order) {
30223019
/* Split shmem folio to non-zero order not supported */
30233020
if (shmem_mapping(folio->mapping)) {
30243021
VM_WARN_ONCE(1,
30253022
"Cannot split shmem folio to non-0 order");
30263023
return -EINVAL;
30273024
}
3028-
/* No split if the file system does not support large folio */
3029-
if (!mapping_large_folio_support(folio->mapping)) {
3025+
/*
3026+
* No split if the file system does not support large folio.
3027+
* Note that we might still have THPs in such mappings due to
3028+
* CONFIG_READ_ONLY_THP_FOR_FS. But in that case, the mapping
3029+
* does not actually support large folios properly.
3030+
*/
3031+
if (IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) &&
3032+
!mapping_large_folio_support(folio->mapping)) {
30303033
VM_WARN_ONCE(1,
30313034
"Cannot split file folio to non-0 order");
30323035
return -EINVAL;
30333036
}
30343037
}
30353038

3039+
/* Only swapping a whole PMD-mapped folio is supported */
3040+
if (folio_test_swapcache(folio) && new_order)
3041+
return -EINVAL;
30363042

30373043
is_hzp = is_huge_zero_folio(folio);
30383044
if (is_hzp) {

0 commit comments

Comments
 (0)