Skip to content

Commit 1bfd188

Browse files
ryncsngregkh
authored andcommitted
mm/shmem, swap: avoid redundant Xarray lookup during swapin
commit 0cfc0e7 upstream. Currently shmem calls xa_get_order to get the swap radix entry order, requiring a full tree walk. This can be easily combined with the swap entry value checking (shmem_confirm_swap) to avoid the duplicated lookup and abort early if the entry is gone already. Which should improve the performance. Link: https://lkml.kernel.org/r/20250728075306.12704-1-ryncsn@gmail.com Link: https://lkml.kernel.org/r/20250728075306.12704-3-ryncsn@gmail.com Signed-off-by: Kairui Song <kasong@tencent.com> Reviewed-by: Kemeng Shi <shikemeng@huaweicloud.com> Reviewed-by: Dev Jain <dev.jain@arm.com> Reviewed-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: Hugh Dickins <hughd@google.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Nhat Pham <nphamcs@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Stable-dep-of: 8a1968b ("mm/shmem, swap: fix race of truncate and swap entry split") [ hughd: removed series cover letter and skip_swapcache dependencies ] Signed-off-by: Hugh Dickins <hughd@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 62414ee commit 1bfd188

1 file changed

Lines changed: 25 additions & 9 deletions

File tree

mm/shmem.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -499,15 +499,27 @@ static int shmem_replace_entry(struct address_space *mapping,
499499

500500
/*
501501
* Sometimes, before we decide whether to proceed or to fail, we must check
502-
* that an entry was not already brought back from swap by a racing thread.
502+
* that an entry was not already brought back or split by a racing thread.
503503
*
504504
* Checking folio is not enough: by the time a swapcache folio is locked, it
505505
* might be reused, and again be swapcache, using the same swap as before.
506+
* Returns the swap entry's order if it still presents, else returns -1.
506507
*/
507-
static bool shmem_confirm_swap(struct address_space *mapping,
508-
pgoff_t index, swp_entry_t swap)
508+
static int shmem_confirm_swap(struct address_space *mapping, pgoff_t index,
509+
swp_entry_t swap)
509510
{
510-
return xa_load(&mapping->i_pages, index) == swp_to_radix_entry(swap);
511+
XA_STATE(xas, &mapping->i_pages, index);
512+
int ret = -1;
513+
void *entry;
514+
515+
rcu_read_lock();
516+
do {
517+
entry = xas_load(&xas);
518+
if (entry == swp_to_radix_entry(swap))
519+
ret = xas_get_order(&xas);
520+
} while (xas_retry(&xas, entry));
521+
rcu_read_unlock();
522+
return ret;
511523
}
512524

513525
/*
@@ -2155,16 +2167,20 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
21552167
return -EIO;
21562168

21572169
si = get_swap_device(swap);
2158-
if (!si) {
2159-
if (!shmem_confirm_swap(mapping, index, swap))
2170+
order = shmem_confirm_swap(mapping, index, swap);
2171+
if (unlikely(!si)) {
2172+
if (order < 0)
21602173
return -EEXIST;
21612174
else
21622175
return -EINVAL;
21632176
}
2177+
if (unlikely(order < 0)) {
2178+
put_swap_device(si);
2179+
return -EEXIST;
2180+
}
21642181

21652182
/* Look it up and read it in.. */
21662183
folio = swap_cache_get_folio(swap, NULL, 0);
2167-
order = xa_get_order(&mapping->i_pages, index);
21682184
if (!folio) {
21692185

21702186
/* Or update major stats only when swapin succeeds?? */
@@ -2241,7 +2257,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
22412257
*/
22422258
folio_lock(folio);
22432259
if (!folio_test_swapcache(folio) ||
2244-
!shmem_confirm_swap(mapping, index, swap) ||
2260+
shmem_confirm_swap(mapping, index, swap) < 0 ||
22452261
folio->swap.val != swap.val) {
22462262
error = -EEXIST;
22472263
goto unlock;
@@ -2284,7 +2300,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
22842300
*foliop = folio;
22852301
return 0;
22862302
failed:
2287-
if (!shmem_confirm_swap(mapping, index, swap))
2303+
if (shmem_confirm_swap(mapping, index, swap) < 0)
22882304
error = -EEXIST;
22892305
if (error == -EIO)
22902306
shmem_set_folio_swapin_error(inode, index, folio, swap);

0 commit comments

Comments
 (0)