[Devel] [PATCH RHEL7 COMMIT] mm/tswap: make tswap_delete_page handle replaced page gracefully
Konstantin Khorenko
khorenko at virtuozzo.com
Tue Apr 26 16:36:56 MSK 2022
The commit is pushed to "branch-rh7-3.10.0-1160.59.1.vz7.186.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.59.1.vz7.186.2
------>
commit 16d1499c3c62982b837429a11c5aa7be5e17a474
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date: Tue Apr 26 11:40:59 2022 +0300
mm/tswap: make tswap_delete_page handle replaced page gracefully
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 | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/mm/tswap.c b/mm/tswap.c
index e209654fcb4b..07d92a0c86cc 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);
More information about the Devel
mailing list