Skip to content

Commit 91ab656

Browse files
ryncsnakpm00
authored andcommitted
mm/shmem, swap: tidy up swap entry splitting
Instead of keeping different paths of splitting the entry before the swap in start, move the entry splitting after the swapin has put the folio in swap cache (or set the SWAP_HAS_CACHE bit). This way we only need one place and one unified way to split the large entry. Whenever swapin brought in a folio smaller than the shmem swap entry, split the entry and recalculate the entry and index for verification. This removes duplicated codes and function calls, reduces LOC, and the split is less racy as it's guarded by swap cache now. So it will have a lower chance of repeated faults due to raced split. The compiler is also able to optimize the coder further: bloat-o-meter results with GCC 14: With DEBUG_SECTION_MISMATCH (-fno-inline-functions-called-once): ./scripts/bloat-o-meter mm/shmem.o.old mm/shmem.o add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-143 (-143) Function old new delta shmem_swapin_folio 2358 2215 -143 Total: Before=32933, After=32790, chg -0.43% With !DEBUG_SECTION_MISMATCH: add/remove: 0/1 grow/shrink: 1/0 up/down: 1069/-749 (320) Function old new delta shmem_swapin_folio 2871 3940 +1069 shmem_split_large_entry.isra 749 - -749 Total: Before=32806, After=33126, chg +0.98% Since shmem_split_large_entry is only called in one place now. The compiler will either generate more compact code, or inlined it for better performance. Link: https://lkml.kernel.org/r/20250728075306.12704-5-ryncsn@gmail.com Signed-off-by: Kairui Song <kasong@tencent.com> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> Tested-by: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Baoquan He <bhe@redhat.com> Cc: Barry Song <baohua@kernel.org> Cc: Chris Li <chrisl@kernel.org> Cc: Dev Jain <dev.jain@arm.com> Cc: Hugh Dickins <hughd@google.com> Cc: Kemeng Shi <shikemeng@huaweicloud.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Nhat Pham <nphamcs@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent c262ffd commit 91ab656

1 file changed

Lines changed: 23 additions & 33 deletions

File tree

mm/shmem.c

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,14 +2303,16 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
23032303
struct address_space *mapping = inode->i_mapping;
23042304
struct mm_struct *fault_mm = vma ? vma->vm_mm : NULL;
23052305
struct shmem_inode_info *info = SHMEM_I(inode);
2306+
swp_entry_t swap, index_entry;
23062307
struct swap_info_struct *si;
23072308
struct folio *folio = NULL;
23082309
bool skip_swapcache = false;
2309-
swp_entry_t swap;
23102310
int error, nr_pages, order, split_order;
2311+
pgoff_t offset;
23112312

23122313
VM_BUG_ON(!*foliop || !xa_is_value(*foliop));
2313-
swap = radix_to_swp_entry(*foliop);
2314+
index_entry = radix_to_swp_entry(*foliop);
2315+
swap = index_entry;
23142316
*foliop = NULL;
23152317

23162318
if (is_poisoned_swp_entry(swap))
@@ -2358,46 +2360,35 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
23582360
}
23592361

23602362
/*
2361-
* Now swap device can only swap in order 0 folio, then we
2362-
* should split the large swap entry stored in the pagecache
2363-
* if necessary.
2364-
*/
2365-
split_order = shmem_split_large_entry(inode, index, swap, gfp);
2366-
if (split_order < 0) {
2367-
error = split_order;
2368-
goto failed;
2369-
}
2370-
2371-
/*
2372-
* If the large swap entry has already been split, it is
2363+
* Now swap device can only swap in order 0 folio, it is
23732364
* necessary to recalculate the new swap entry based on
2374-
* the old order alignment.
2365+
* the offset, as the swapin index might be unalgined.
23752366
*/
2376-
if (split_order > 0) {
2377-
pgoff_t offset = index - round_down(index, 1 << split_order);
2378-
2367+
if (order) {
2368+
offset = index - round_down(index, 1 << order);
23792369
swap = swp_entry(swp_type(swap), swp_offset(swap) + offset);
23802370
}
23812371

2382-
/* Here we actually start the io */
23832372
folio = shmem_swapin_cluster(swap, gfp, info, index);
23842373
if (!folio) {
23852374
error = -ENOMEM;
23862375
goto failed;
23872376
}
2388-
} else if (order > folio_order(folio)) {
2377+
}
2378+
alloced:
2379+
if (order > folio_order(folio)) {
23892380
/*
2390-
* Swap readahead may swap in order 0 folios into swapcache
2381+
* Swapin may get smaller folios due to various reasons:
2382+
* It may fallback to order 0 due to memory pressure or race,
2383+
* swap readahead may swap in order 0 folios into swapcache
23912384
* asynchronously, while the shmem mapping can still stores
23922385
* large swap entries. In such cases, we should split the
23932386
* large swap entry to prevent possible data corruption.
23942387
*/
2395-
split_order = shmem_split_large_entry(inode, index, swap, gfp);
2388+
split_order = shmem_split_large_entry(inode, index, index_entry, gfp);
23962389
if (split_order < 0) {
2397-
folio_put(folio);
2398-
folio = NULL;
23992390
error = split_order;
2400-
goto failed;
2391+
goto failed_nolock;
24012392
}
24022393

24032394
/*
@@ -2406,16 +2397,14 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
24062397
* the old order alignment.
24072398
*/
24082399
if (split_order > 0) {
2409-
pgoff_t offset = index - round_down(index, 1 << split_order);
2410-
2411-
swap = swp_entry(swp_type(swap), swp_offset(swap) + offset);
2400+
offset = index - round_down(index, 1 << split_order);
2401+
swap = swp_entry(swp_type(swap), swp_offset(index_entry) + offset);
24122402
}
24132403
} else if (order < folio_order(folio)) {
24142404
swap.val = round_down(swap.val, 1 << folio_order(folio));
24152405
index = round_down(index, 1 << folio_order(folio));
24162406
}
24172407

2418-
alloced:
24192408
/*
24202409
* We have to do this with the folio locked to prevent races.
24212410
* The shmem_confirm_swap below only checks if the first swap
@@ -2479,12 +2468,13 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
24792468
shmem_set_folio_swapin_error(inode, index, folio, swap,
24802469
skip_swapcache);
24812470
unlock:
2482-
if (skip_swapcache)
2483-
swapcache_clear(si, swap, folio_nr_pages(folio));
2484-
if (folio) {
2471+
if (folio)
24852472
folio_unlock(folio);
2473+
failed_nolock:
2474+
if (skip_swapcache)
2475+
swapcache_clear(si, folio->swap, folio_nr_pages(folio));
2476+
if (folio)
24862477
folio_put(folio);
2487-
}
24882478
put_swap_device(si);
24892479

24902480
return error;

0 commit comments

Comments
 (0)