[Devel] [PATCH RH7] mm/tswap: make tswap_delete_page handle replaced page gracefully

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Apr 26 11:40:59 MSK 2022


When we want to delete specific page from the frontswap, and it was
replaced with another page between lookup and delete while tswap_lock
had been released, just consider removal successful.

This potential call stack could've lead to the crash on BUG_ON:

THREAD 1
tswap_shrink_scan () {
        spin_lock(&tswap_lock);
        page = list_first_entry(&lru->list, struct page, lru); # gets page-1
        trylock_page(page); # locked page-1 succesfully
        get_page(page);
        spin_unlock(&tswap_lock);

			THREAD 2
			tswap_frontswap_store(page) { # store page-2 with same swap entry
				cache_page = tswap_lookup_page(entry); # gets page-1
				tswap_delete_page(entry, NULL); # locks/unlocks tswap_lock, removes page-1
				tswap_insert_page(entry, cache_page); # locks/unlocks tswap_lock, inserts page-2
			}

        tswap_evict_page(page) {
                tswap_delete_page(entry, page) {
                        spin_lock(&tswap_lock);
                        page = radix_tree_delete_item(&tswap_page_tree); # gets page-2
                        spin_unlock(&tswap_lock);
                        BUG_ON(expected && page != expected); # expected is page-1, but page is page-2
                }
        }
}

https://jira.sw.ru/browse/PSBM-139322

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 mm/tswap.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/mm/tswap.c b/mm/tswap.c
index e209654fcb4b..e4aa2854ede3 100644
--- a/mm/tswap.c
+++ b/mm/tswap.c
@@ -116,6 +116,13 @@ static struct page *tswap_delete_page(swp_entry_t entry, struct page *expected)
 	struct page *page;
 
 	spin_lock(&tswap_lock);
+	if (expected) {
+		page = radix_tree_lookup(&tswap_page_tree, entry.val);
+		if (page && page != expected) {
+			spin_unlock(&tswap_lock);
+			return expected;
+		}
+	}
 	page = radix_tree_delete_item(&tswap_page_tree, entry.val, expected);
 	if (page) {
 		tswap_lru_del(page);
@@ -328,7 +335,7 @@ static int tswap_frontswap_store(unsigned type, pgoff_t offset,
 		/* If type of page has not changed, just reuse it */
 		if (zero_filled == (cache_page == ZERO_PAGE(0)))
 			goto copy;
-		tswap_delete_page(entry, NULL);
+		tswap_delete_page(entry, cache_page);
 		put_page(cache_page);
 	}
 
-- 
2.35.1



More information about the Devel mailing list