[Devel] [PATCH RHEL9 COMMIT] mm: migrate page private for high-order folios in swap cache correctly

Konstantin Khorenko khorenko at virtuozzo.com
Fri Mar 8 19:09:01 MSK 2024


The commit is pushed to "branch-rh9-5.14.0-362.8.1.vz9.35.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh9-5.14.0-362.8.1.vz9.35.14
------>
commit 6ceb6de48cca9eeb7de349aabd4ef62b31169610
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Wed Mar 6 16:36:04 2024 +0800

    mm: migrate page private for high-order folios in swap cache correctly
    
    We have a check in do_swap_page that page from lookup_swap_cache should
    have private field equal to the swapcache index we searched it at
    (page_private(page) != entry.val). So folio_migrate_mapping should
    preserve page private for each page of a huge folio to satisfy this
    check else we get infinite loop in:
    
      +-> mmap_read_lock
      +-> __get_user_pages_locked
        +-> for-loop # taken once
          +-> __get_user_pages
            +-> retry-loop # constantly spinning
              +-> faultin_page # return 0 to trigger retry
                +-> handle_mm_fault
                  +-> __handle_mm_fault
                    +-> handle_pte_fault
                      +-> do_swap_page
                        +-> lookup_swap_cache # returns non-NULL
                        +-> if (swapcache)
                          +-> if (!folio_test_swapcache || page_private(page) != entry.val)
                            +-> goto out_page
                              +-> return 0
    
    And this loop is under mmap_lock so we have secondary problem of
    multiple processes hanging on attempt to take mmap_lock.
    
    Note: We don't need this after we stop using private in this ms patch:
    cfeed8ffe55b ("mm/swap: stop using page->private on tail pages for THP_SWAP")
    
    https://virtuozzo.atlassian.net/browse/PSBM-153264
    Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
    
    Feature: fix mm
---
 mm/huge_memory.c | 5 +++++
 mm/migrate.c     | 4 ++++
 2 files changed, 9 insertions(+)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index f893ede92e7d..c48202dc239c 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2523,6 +2523,11 @@ static void __split_huge_page_tail(struct page *head, int tail,
 	 * page->private should not be set in tail pages with the exception
 	 * of swap cache pages that store the swp_entry_t in tail pages.
 	 * Fix up and warn once if private is unexpectedly set.
+	 *
+	 * NOTE: drop the patch ("mm: migrate page private for high-order
+	 * folios in swap cache correctly") once ms commit cfeed8ffe55b
+	 * ("mm/swap: stop using page->private on tail pages for THP_SWAP")
+	 * is applied.
 	 */
 	if (!folio_test_swapcache(page_folio(head))) {
 		VM_WARN_ON_ONCE_PAGE(page_tail->private != 0, page_tail);
diff --git a/mm/migrate.c b/mm/migrate.c
index d950f42c0708..357a0a4c59e6 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -424,6 +424,10 @@ int folio_migrate_mapping(struct address_space *mapping,
 		if (folio_test_swapcache(folio)) {
 			folio_set_swapcache(newfolio);
 			newfolio->private = folio_get_private(folio);
+
+			/* Swap cache needs private for each page of huge page */
+			for (i = 1; i < nr; i++)
+				set_page_private(folio_page(newfolio, i), folio_page(folio, i)->private);
 		}
 		entries = nr;
 	} else {


More information about the Devel mailing list