[PATCH] mm/shmem: fix shmem_split_large_entry()

From: Zi Yan
Date: Tue Feb 25 2025 - 12:03:34 EST


the swap entry offset was updated incorrectly. fix it.

Signed-off-by: Zi Yan <ziy@xxxxxxxxxx>
---
mm/shmem.c | 41 ++++++++++++++++++++++++++---------------
1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index 48caa16e8971..f4e58611899f 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2153,7 +2153,7 @@ static int shmem_split_large_entry(struct inode *inod=
e, pgoff_t index,
{
struct address_space *mapping =3D inode->i_mapping;
XA_STATE_ORDER(xas, &mapping->i_pages, index, 0);
- int split_order =3D 0;
+ int split_order =3D 0, entry_order =3D 0;
int i;

/* Convert user data gfp flags to xarray node gfp flags */
@@ -2171,35 +2171,46 @@ static int shmem_split_large_entry(struct inode *in=
ode, pgoff_t index,
}

order =3D xas_get_order(&xas);
+ entry_order =3D order;

/* Try to split large swap entry in pagecache */
if (order > 0) {
int cur_order =3D order;
+ pgoff_t swap_index =3D round_down(index, 1 << order);

split_order =3D xas_try_split_min_order(cur_order);

while (cur_order > 0) {
+ pgoff_t aligned_index =3D
+ round_down(index, 1 << cur_order);
+ pgoff_t swap_offset =3D aligned_index - swap_index;
+
xas_set_order(&xas, index, split_order);
xas_try_split(&xas, old, cur_order, GFP_NOWAIT);
if (xas_error(&xas))
goto unlock;
+
+ /*
+ * Re-set the swap entry after splitting, and
+ * the swap offset of the original large entry
+ * must be continuous.
+ */
+ for (i =3D 0; i < 1 << cur_order;
+ i +=3D (1 << split_order)) {
+ swp_entry_t tmp;
+
+ tmp =3D swp_entry(swp_type(swap),
+ swp_offset(swap) +
+ swap_offset +
+ i);
+ __xa_store(&mapping->i_pages,
+ aligned_index + i,
+ swp_to_radix_entry(tmp), 0);
+ }
cur_order =3D split_order;
split_order =3D
xas_try_split_min_order(split_order);
}
-
- /*
- * Re-set the swap entry after splitting, and the swap
- * offset of the original large entry must be continuous.
- */
- for (i =3D 0; i < 1 << order; i++) {
- pgoff_t aligned_index =3D round_down(index, 1 << order);
- swp_entry_t tmp;
-
- tmp =3D swp_entry(swp_type(swap), swp_offset(swap) + i);
- __xa_store(&mapping->i_pages, aligned_index + i,
- swp_to_radix_entry(tmp), 0);
- }
}

unlock:
@@ -2212,7 +2223,7 @@ static int shmem_split_large_entry(struct inode *inod=
e, pgoff_t index,
if (xas_error(&xas))
return xas_error(&xas);

- return split_order;
+ return entry_order;
}

/*
--=20
2.47.2



Best Regards,
Yan, Zi