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 *inode, pgoff_t index, { struct address_space *mapping = inode->i_mapping; XA_STATE_ORDER(xas, &mapping->i_pages, index, 0); - int split_order = 0; + int split_order = 0, entry_order = 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 *inode, pgoff_t index, } order = xas_get_order(&xas); + entry_order = order; /* Try to split large swap entry in pagecache */ if (order > 0) { int cur_order = order; + pgoff_t swap_index = round_down(index, 1 << order); split_order = xas_try_split_min_order(cur_order); while (cur_order > 0) { + pgoff_t aligned_index = + round_down(index, 1 << cur_order); + pgoff_t swap_offset = 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 = 0; i < 1 << cur_order; + i += (1 << split_order)) { + swp_entry_t tmp; + + tmp = 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 = split_order; split_order = 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 = 0; i < 1 << order; i++) { - pgoff_t aligned_index = round_down(index, 1 << order); - swp_entry_t tmp; - - tmp = 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 *inode, pgoff_t index, if (xas_error(&xas)) return xas_error(&xas); - return split_order; + return entry_order; } /* -- 2.47.2 Best Regards, Yan, Zi