[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20231113130601.3350915-1-hezhongkun.hzk@bytedance.com>
Date: Mon, 13 Nov 2023 21:06:01 +0800
From: Zhongkun He <hezhongkun.hzk@...edance.com>
To: akpm@...ux-foundation.org
Cc: hannes@...xchg.org, yosryahmed@...gle.com, nphamcs@...il.com,
sjenning@...hat.com, ddstreet@...e.org, vitaly.wool@...sulko.com,
linux-mm@...ck.org, linux-kernel@...r.kernel.org,
Zhongkun He <hezhongkun.hzk@...edance.com>
Subject: [PATCH] mm:zswap: fix zswap entry reclamation failure in two scenarios
I recently found two scenarios where zswap entry could not be
released, which will cause shrink_worker and active recycling
to fail.
1)The swap entry has been freed, but cached in swap_slots_cache,
no swap cache and swapcount=0.
2)When the option zswap_exclusive_loads_enabled disabled and
zswap_load completed(page in swap_cache and swapcount = 0).
The above two cases need to be determined by swapcount=0,
fix it.
Signed-off-by: Zhongkun He <hezhongkun.hzk@...edance.com>
---
mm/zswap.c | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/mm/zswap.c b/mm/zswap.c
index 74411dfdad92..db95491bcdd5 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1063,11 +1063,12 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
struct mempolicy *mpol;
struct scatterlist input, output;
struct crypto_acomp_ctx *acomp_ctx;
+ struct swap_info_struct *si;
struct zpool *pool = zswap_find_zpool(entry);
bool page_was_allocated;
u8 *src, *tmp = NULL;
unsigned int dlen;
- int ret;
+ int ret = 0;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_NONE,
};
@@ -1082,16 +1083,30 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
mpol = get_task_policy(current);
page = __read_swap_cache_async(swpentry, GFP_KERNEL, mpol,
NO_INTERLEAVE_INDEX, &page_was_allocated);
- if (!page) {
+ if (!page)
ret = -ENOMEM;
- goto fail;
- }
-
- /* Found an existing page, we raced with load/swapin */
- if (!page_was_allocated) {
+ else if (!page_was_allocated) {
+ /* Found an existing page, we raced with load/swapin */
put_page(page);
ret = -EEXIST;
- goto fail;
+ }
+
+ if (ret) {
+ si = get_swap_device(swpentry);
+ if (!si)
+ goto out;
+
+ /* Two cases to directly release zswap_entry.
+ * 1) -ENOMEM,if the swpentry has been freed, but cached in
+ * swap_slots_cache(no page and swapcount = 0).
+ * 2) -EEXIST, option zswap_exclusive_loads_enabled disabled and
+ * zswap_load completed(page in swap_cache and swapcount = 0).
+ */
+ if (!swap_swapcount(si, swpentry))
+ ret = 0;
+
+ put_swap_device(si);
+ goto out;
}
/*
@@ -1106,7 +1121,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
spin_unlock(&tree->lock);
delete_from_swap_cache(page_folio(page));
ret = -ENOMEM;
- goto fail;
+ goto out;
}
spin_unlock(&tree->lock);
@@ -1151,7 +1166,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
return ret;
-fail:
+out:
if (!zpool_can_sleep_mapped(pool))
kfree(tmp);
--
2.25.1
Powered by blists - more mailing lists