[PATCH 1/3] mm/huge_memory: allow splitting mappingless swapcache folios

Shivam Kalra via B4 Relay <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <[email protected]>
From: Shivam Kalra <[email protected]>

A shmem folio is removed from its page cache when it is written to swap.
While it remains in the swap cache, it has no address_space mapping, so
folio_check_splittable() mistakes it for a truncated folio and rejects the
split with -EBUSY.

Allow a mappingless folio when it is in the swap cache. Initialize the
XArray state without an address-space mapping, then assign the XArray only
for mapped file folios. The split path already replaces each split folio
in the swap cache while holding the swap-cluster lock.

Signed-off-by: Shivam Kalra <[email protected]>
---
 mm/huge_memory.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 804b8f6aa557..ecfe40b1400b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3882,12 +3882,10 @@ int folio_check_splittable(struct folio *folio, unsigned int new_order,
 	VM_WARN_ON_FOLIO(!folio_test_locked(folio), folio);
 	/*
 	 * Folios that just got truncated cannot get split. Signal to the
-	 * caller that there was a race.
-	 *
-	 * TODO: this will also currently refuse folios without a mapping in the
-	 * swapcache (shmem or to-be-anon folios).
+	 * caller that there was a race. A mappingless swapcache folio can be
+	 * either shmem or not yet associated with an anon_vma, and is valid.
 	 */
-	if (!folio->mapping && !folio_test_anon(folio))
+	if (!folio->mapping && !folio_test_swapcache(folio))
 		return -EBUSY;
 
 	/* order-1 is not supported for anonymous THP. */
@@ -4022,10 +4020,7 @@ static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int n
 			if (do_lru)
 				lru_add_split_folio(folio, new_folio, lruvec, list);
 
-			/*
-			 * Anonymous folio with swap cache.
-			 * NOTE: shmem in swap cache is not supported yet.
-			 */
+			/* Folio in the swap cache. */
 			if (ci) {
 				__swap_cache_replace_folio(ci, folio, new_folio);
 				continue;
@@ -4103,7 +4098,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
 		struct page *split_at, struct page *lock_at,
 		struct list_head *list, enum split_type split_type)
 {
-	XA_STATE(xas, &folio->mapping->i_pages, folio->index);
+	XA_STATE(xas, NULL, folio->index);
 	struct folio *end_folio = folio_next(folio);
 	bool is_anon = folio_test_anon(folio);
 	struct mem_cgroup *memcg, *old_memcg;
@@ -4158,11 +4153,12 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
 		}
 		anon_vma_lock_write(anon_vma);
 		mapping = NULL;
-	} else {
+	} else if (folio->mapping) {
 		unsigned int min_order;
 		gfp_t gfp;
 
 		mapping = folio->mapping;
+		xas.xa = &mapping->i_pages;
 		min_order = mapping_min_folio_order(mapping);
 		if (new_order < min_order) {
 			ret = -EINVAL;

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.