[PATCH] mm/shmem: fix shmem_split_large_entry()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux