From: Baoquan He <baoquan.he@linux.dev>
To: linux-mm@kvack.org
Cc: chrisl@kernel.org, nphamcs@gmail.com, kasong@tencent.com,
baohua@kernel.org, youngjun.park@lge.com, hannes@cmpxchg.org,
yosry@kernel.org, david@kernel.org, shikemeng@huaweicloud.com,
chengming.zhou@linux.dev, linux-kernel@vger.kernel.org,
Baoquan He <baoquan.he@linux.dev>
Subject: [RFC PATCH v2 10/10] mm, swap: defer xswap shrink to workqueue to avoid lock recursion
Date: Wed, 5 Aug 2026 15:53:33 +0800 [thread overview]
Message-ID: <20260805075336.3579395-11-baoquan.he@linux.dev> (raw)
In-Reply-To: <20260805075336.3579395-1-baoquan.he@linux.dev>
xswap_try_shrink() was called directly from __free_cluster() while
holding ci->lock. The shrink path calls xswap_unmap_clusters()
which unmaps vmalloc pages backing cluster_info, and on return
swap_cache_del_folio() tries swap_cluster_unlock(ci) on the now-
unmapped address — crashing on a not-present page.
Replace direct calls with schedule_work() so shrink runs in an
independent workqueue context where no cluster locks are held.
Use cancel_work_sync() during swapoff to ensure no pending shrink
work races with the VM area teardown.
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
include/linux/swap.h | 1 +
mm/swapfile.c | 19 +++++++++++++------
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 4f4583f9a4e5..a5b323374769 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -255,6 +255,7 @@ struct swap_info_struct {
unsigned long nr_clusters_mapped; /* currently mapped cluster count */
unsigned long nr_free_tail; /* contiguous free clusters at tail */
struct dentry *debugfs_entry; /* debugfs: type<N>_max_clusters */
+ struct work_struct xswap_shrink_work; /* deferred shrink trigger */
struct mutex xswap_lock; /* serialize map/unmap operations */
#endif
struct list_head free_clusters; /* free clusters list */
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 265f2bac1a12..ca406556626e 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -127,11 +127,8 @@ static ssize_t xswap_max_clusters_write(struct file *file,
spin_unlock(&swap_lock);
}
- /*
- * Lowering the ceiling may make tail clusters eligible for
- * shrinking. Trigger an immediate check.
- */
- xswap_try_shrink(si);
+ /* Shrink trigger: lowering the ceiling may free tail clusters. */
+ schedule_work(&si->xswap_shrink_work);
return count;
}
@@ -726,7 +723,7 @@ static void __free_cluster(struct swap_info_struct *si, struct swap_cluster_info
ci->order = 0;
#ifdef CONFIG_XSWAP
xswap_update_free_tail(si, ci - si->cluster_info);
- xswap_try_shrink(si);
+ schedule_work(&si->xswap_shrink_work);
#endif
}
@@ -3236,6 +3233,7 @@ static void free_swap_cluster_info(struct swap_info_struct *si)
#ifdef CONFIG_XSWAP
if (si->flags & SWP_XSWAP) {
xswap_debugfs_del(si);
+ cancel_work_sync(&si->xswap_shrink_work);
/* Unmap all mapped clusters and free the VM_SPARSE area */
if (si->nr_clusters_mapped > 0)
xswap_unmap_clusters(si, 0, si->nr_clusters_mapped);
@@ -4057,6 +4055,13 @@ static void xswap_trim_free_tail(struct swap_info_struct *si, unsigned long idx)
WRITE_ONCE(si->nr_free_tail, nr_mapped - idx - 1);
}
+static void xswap_shrink_work_fn(struct work_struct *work)
+{
+ struct swap_info_struct *si = container_of(work,
+ struct swap_info_struct, xswap_shrink_work);
+ xswap_try_shrink(si);
+}
+
/*
* Try to shrink the cluster_info tail. Uses si->nr_free_tail which
* is maintained incrementally during alloc/free — no scanning needed.
@@ -4163,7 +4168,9 @@ static int setup_swap_clusters_info(struct swap_info_struct *si,
/* All mapped clusters except cluster 0 are free at the tail */
si->nr_free_tail = si->nr_clusters_mapped - 1;
+
mutex_init(&si->xswap_lock);
+ INIT_WORK(&si->xswap_shrink_work, xswap_shrink_work_fn);
xswap_debugfs_add(si);
return 0;
--
2.54.0
prev parent reply other threads:[~2026-08-05 7:55 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 7:53 [RFC PATCH v2 00/10] mm, swap: dynamic cluster management for xswap devices Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 01/10] mm: xswap support for zswap Baoquan He
2026-08-05 14:17 ` Johannes Weiner
2026-08-05 7:53 ` [RFC PATCH v2 02/10] mm, swap: add CONFIG_XSWAP and xswap fields to swap_info_struct Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 03/10] mm, swap: add xswap cluster grow via VM_SPARSE vmalloc Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 04/10] mm, swap: add xswap grow trigger on cluster allocation Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 05/10] mm, swap: add xswap_try_shrink and shrink trigger on cluster free Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 06/10] mm, swap: free backing pages in xswap_unmap_clusters Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 07/10] mm, swap: add nr_free_tail for O(1) xswap shrink detection Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 08/10] mm, swap: add adjustable runtime ceiling (nr_clusters) for xswap Baoquan He
2026-08-05 7:53 ` [RFC PATCH v2 09/10] mm, swap: add debugfs knob for xswap per-device cluster limit Baoquan He
2026-08-05 7:53 ` Baoquan He [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260805075336.3579395-11-baoquan.he@linux.dev \
--to=baoquan.he@linux.dev \
--cc=baohua@kernel.org \
--cc=chengming.zhou@linux.dev \
--cc=chrisl@kernel.org \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=kasong@tencent.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=shikemeng@huaweicloud.com \
--cc=yosry@kernel.org \
--cc=youngjun.park@lge.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox