Hi Zi, kernel test robot noticed the following build warnings: [auto build test WARNING on akpm-mm/mm-everything] [also build test WARNING on next-20241029] [cannot apply to linus/master v6.12-rc5] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Zi-Yan/mm-huge_memory-buddy-allocator-like-folio_split/20241029-021200 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20241028180932.1319265-2-ziy%40nvidia.com patch subject: [PATCH v1 1/3] mm/huge_memory: buddy allocator like folio_split() config: x86_64-kexec (https://download.01.org/0day-ci/archive/20241029/202410291853.lBOeTPTK-lkp@xxxxxxxxx/config) compiler: clang version 19.1.2 (https://github.com/llvm/llvm-project 7ba7d8e2f7b6445b60679da826210cdde29eaf8b) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241029/202410291853.lBOeTPTK-lkp@xxxxxxxxx/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@xxxxxxxxx> | Closes: https://lore.kernel.org/oe-kbuild-all/202410291853.lBOeTPTK-lkp@xxxxxxxxx/ All warnings (new ones prefixed by >>): In file included from mm/huge_memory.c:8: In file included from include/linux/mm.h:2213: include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion] 504 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~ ^ 505 | item]; | ~~~~ include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion] 511 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~ ^ 512 | NR_VM_NUMA_EVENT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~~ include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion] 518 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_" | ~~~~~~~~~~~ ^ ~~~ include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion] 524 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~ ^ 525 | NR_VM_NUMA_EVENT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~~ In file included from mm/huge_memory.c:18: include/linux/mm_inline.h:47:41: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion] 47 | __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); | ~~~~~~~~~~~ ^ ~~~ include/linux/mm_inline.h:49:22: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum lru_list') [-Wenum-enum-conversion] 49 | NR_ZONE_LRU_BASE + lru, nr_pages); | ~~~~~~~~~~~~~~~~ ^ ~~~ >> mm/huge_memory.c:3342:6: warning: variable 'nr_dropped' set but not used [-Wunused-but-set-variable] 3342 | int nr_dropped = 0; | ^ mm/huge_memory.c:3806:12: warning: unused function 'folio_split' [-Wunused-function] 3806 | static int folio_split(struct folio *folio, unsigned int new_order, | ^~~~~~~~~~~ 8 warnings generated. vim +/nr_dropped +3342 mm/huge_memory.c 3292 3293 #define for_each_folio_until_end_safe(iter, iter2, start, end) \ 3294 for (iter = start, iter2 = folio_next(start); \ 3295 iter != end; \ 3296 iter = iter2, iter2 = folio_next(iter2)) 3297 3298 /* 3299 * It splits a @folio (without mapping) to lower order smaller folios in two 3300 * ways. 3301 * 1. uniform split: the given @folio into multiple @new_order small folios, 3302 * where all small folios have the same order. This is done when 3303 * uniform_split is true. 3304 * 2. buddy allocator like split: the given @folio is split into half and one 3305 * of the half (containing the given page) is split into half until the 3306 * given @page's order becomes @new_order. This is done when uniform_split is 3307 * false. 3308 * 3309 * The high level flow for these two methods are: 3310 * 1. uniform split: a single __split_folio_to_order() is called to split the 3311 * @folio into @new_order, then we traverse all the resulting folios one by 3312 * one in PFN ascending order and perform stats, unfreeze, adding to list, 3313 * and file mapping index operations. 3314 * 2. buddy allocator like split: in general, folio_order - @new_order calls to 3315 * __split_folio_to_order() are called in the for loop to split the @folio 3316 * to one lower order at a time. The resulting small folios are processed 3317 * like what is done during the traversal in 1, except the one containing 3318 * @page, which is split in next for loop. 3319 * 3320 * After splitting, the caller's folio reference will be transferred to the 3321 * folio containing @page. The other folios may be freed if they are not mapped. 3322 * 3323 * In terms of locking, after splitting, 3324 * 1. uniform split leaves @page (or the folio contains it) locked; 3325 * 2. buddy allocator like split leaves @folio locked. 3326 * 3327 * If @list is null, tail pages will be added to LRU list, otherwise, to @list. 3328 */ 3329 static int __folio_split_without_mapping(struct folio *folio, int new_order, 3330 struct page *page, struct list_head *list, pgoff_t end, 3331 struct xa_state *xas, struct address_space *mapping, 3332 bool uniform_split) 3333 { 3334 struct lruvec *lruvec; 3335 struct address_space *swap_cache = NULL; 3336 struct folio *origin_folio = folio; 3337 struct folio *next_folio = folio_next(folio); 3338 struct folio *new_folio; 3339 struct folio *next; 3340 int order = folio_order(folio); 3341 int split_order = order - 1; > 3342 int nr_dropped = 0; 3343 3344 if (folio_test_anon(folio) && folio_test_swapcache(folio)) { 3345 if (!uniform_split) 3346 return -EINVAL; 3347 3348 swap_cache = swap_address_space(folio->swap); 3349 xa_lock(&swap_cache->i_pages); 3350 } 3351 3352 if (folio_test_anon(folio)) 3353 mod_mthp_stat(order, MTHP_STAT_NR_ANON, -1); 3354 3355 /* lock lru list/PageCompound, ref frozen by page_ref_freeze */ 3356 lruvec = folio_lruvec_lock(folio); 3357 3358 /* 3359 * split to new_order one order at a time. For uniform split, 3360 * intermediate orders are skipped 3361 */ 3362 for (split_order = order - 1; split_order >= new_order; split_order--) { 3363 int old_order = folio_order(folio); 3364 struct folio *release; 3365 struct folio *end_folio = folio_next(folio); 3366 int status; 3367 3368 if (folio_test_anon(folio) && split_order == 1) 3369 continue; 3370 if (uniform_split && split_order != new_order) 3371 continue; 3372 3373 if (mapping) { 3374 /* 3375 * uniform split has xas_split_alloc() called before 3376 * irq is disabled, since xas_nomem() might not be 3377 * able to allocate enough memory. 3378 */ 3379 if (uniform_split) 3380 xas_split(xas, folio, old_order); 3381 else { 3382 xas_set_order(xas, folio->index, split_order); 3383 xas_set_err(xas, -ENOMEM); 3384 if (xas_nomem(xas, 0)) 3385 xas_split(xas, folio, old_order); 3386 else 3387 return -ENOMEM; 3388 } 3389 } 3390 3391 split_page_memcg(&folio->page, old_order, split_order); 3392 split_page_owner(&folio->page, old_order, split_order); 3393 pgalloc_tag_split(folio, old_order, split_order); 3394 3395 status = __split_folio_to_order(folio, split_order); 3396 3397 if (status < 0) 3398 return status; 3399 3400 /* 3401 * Iterate through after-split folios and perform related 3402 * operations. But in buddy allocator like split, the folio 3403 * containing the specified page is skipped until its order 3404 * is new_order, since the folio will be worked on in next 3405 * iteration. 3406 */ 3407 for_each_folio_until_end_safe(release, next, folio, end_folio) { 3408 if (page_in_folio_offset(page, release) >= 0) { 3409 folio = release; 3410 if (split_order != new_order) 3411 continue; 3412 } 3413 if (folio_test_anon(release)) 3414 mod_mthp_stat(folio_order(release), 3415 MTHP_STAT_NR_ANON, 1); 3416 3417 /* 3418 * Unfreeze refcount first. Additional reference from 3419 * page cache. 3420 */ 3421 folio_ref_unfreeze(release, 3422 1 + ((!folio_test_anon(origin_folio) || 3423 folio_test_swapcache(origin_folio)) ? 3424 folio_nr_pages(release) : 0)); 3425 3426 if (release != origin_folio) 3427 lru_add_page_tail(origin_folio, &release->page, 3428 lruvec, list); 3429 3430 /* Some pages can be beyond EOF: drop them from page cache */ 3431 if (release->index >= end) { 3432 if (shmem_mapping(origin_folio->mapping)) 3433 nr_dropped++; 3434 else if (folio_test_clear_dirty(release)) 3435 folio_account_cleaned(release, 3436 inode_to_wb(origin_folio->mapping->host)); 3437 __filemap_remove_folio(release, NULL); 3438 folio_put(release); 3439 } else if (!folio_test_anon(release)) { 3440 __xa_store(&origin_folio->mapping->i_pages, 3441 release->index, &release->page, 0); 3442 } else if (swap_cache) { 3443 __xa_store(&swap_cache->i_pages, 3444 swap_cache_index(release->swap), 3445 &release->page, 0); 3446 } 3447 } 3448 } 3449 3450 unlock_page_lruvec(lruvec); 3451 3452 if (folio_test_anon(origin_folio)) { 3453 if (folio_test_swapcache(origin_folio)) 3454 xa_unlock(&swap_cache->i_pages); 3455 } else 3456 xa_unlock(&mapping->i_pages); 3457 3458 /* Caller disabled irqs, so they are still disabled here */ 3459 local_irq_enable(); 3460 3461 remap_page(origin_folio, 1 << order, 3462 folio_test_anon(origin_folio) ? 3463 RMP_USE_SHARED_ZEROPAGE : 0); 3464 3465 /* 3466 * At this point, folio should contain the specified page, so that it 3467 * will be left to the caller to unlock it. 3468 */ 3469 for_each_folio_until_end_safe(new_folio, next, origin_folio, next_folio) { 3470 if (uniform_split && new_folio == folio) 3471 continue; 3472 if (!uniform_split && new_folio == origin_folio) 3473 continue; 3474 3475 folio_unlock(new_folio); 3476 /* 3477 * Subpages may be freed if there wasn't any mapping 3478 * like if add_to_swap() is running on a lru page that 3479 * had its mapping zapped. And freeing these pages 3480 * requires taking the lru_lock so we do the put_page 3481 * of the tail pages after the split is complete. 3482 */ 3483 free_page_and_swap_cache(&new_folio->page); 3484 } 3485 return 0; 3486 } 3487 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki