From: Ming Lei <tom.leiming@gmail.com>
To: Jens Axboe <axboe@kernel.dk>, linux-block@vger.kernel.org
Cc: Caleb Sander Mateos <csander@purestorage.com>,
"Liam R . Howlett" <liam.howlett@oracle.com>,
Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>,
Ming Lei <tom.leiming@gmail.com>
Subject: [PATCH 3/3] ublk: avoid unpinning pages under maple tree spinlock
Date: Thu, 23 Apr 2026 11:30:58 +0800 [thread overview]
Message-ID: <20260423033058.2805135-4-tom.leiming@gmail.com> (raw)
In-Reply-To: <20260423033058.2805135-1-tom.leiming@gmail.com>
ublk_shmem_remove_ranges() calls unpin_user_pages() while holding the
maple tree spinlock (mas_lock). Although unpin_user_pages() is safe in
atomic context, holding the spinlock across potentially many page
unpinning operations is not ideal.
Split into __ublk_shmem_remove_ranges() which erases up to 64 ranges
under mas_lock, collecting base_pfn and nr_pages into a temporary
xarray. Then drop the lock and unpin pages outside spinlock context.
ublk_shmem_remove_ranges() loops until all matching ranges are
processed.
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
---
drivers/block/ublk_drv.c | 56 +++++++++++++++++++++++++++++++++-------
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6edc65af250d..a68bff69844e 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -5424,32 +5424,68 @@ static void ublk_unpin_range_pages(unsigned long base_pfn,
}
/*
- * Remove ranges from the maple tree matching buf_index, unpin pages
- * and free range structs. If buf_index < 0, remove all ranges.
+ * Inner loop: erase up to UBLK_REMOVE_BATCH matching ranges under
+ * mas_lock, collecting them into an xarray. Then drop the lock and
+ * unpin pages + free ranges outside spinlock context.
+ *
+ * Returns true if the tree walk completed, false if more ranges remain.
+ * Xarray key is the base PFN, value encodes nr_pages via xa_mk_value().
*/
-static int ublk_shmem_remove_ranges(struct ublk_device *ub, int buf_index)
+#define UBLK_REMOVE_BATCH 64
+
+static bool __ublk_shmem_remove_ranges(struct ublk_device *ub,
+ int buf_index, int *ret)
{
MA_STATE(mas, &ub->buf_tree, 0, ULONG_MAX);
struct ublk_buf_range *range;
- int ret = -ENOENT;
+ struct xarray to_unpin;
+ unsigned long idx;
+ unsigned int count = 0;
+ bool done = false;
+ void *entry;
+
+ xa_init(&to_unpin);
mas_lock(&mas);
mas_for_each(&mas, range, ULONG_MAX) {
- unsigned long base, nr;
+ unsigned long nr;
if (buf_index >= 0 && range->buf_index != buf_index)
continue;
- ret = 0;
- base = mas.index;
- nr = mas.last - base + 1;
+ *ret = 0;
+ nr = mas.last - mas.index + 1;
+ if (xa_err(xa_store(&to_unpin, mas.index,
+ xa_mk_value(nr), GFP_ATOMIC)))
+ goto unlock;
mas_erase(&mas);
-
- ublk_unpin_range_pages(base, nr);
kfree(range);
+ if (++count >= UBLK_REMOVE_BATCH)
+ goto unlock;
}
+ done = true;
+unlock:
mas_unlock(&mas);
+ xa_for_each(&to_unpin, idx, entry)
+ ublk_unpin_range_pages(idx, xa_to_value(entry));
+ xa_destroy(&to_unpin);
+
+ return done;
+}
+
+/*
+ * Remove ranges from the maple tree matching buf_index, unpin pages
+ * and free range structs. If buf_index < 0, remove all ranges.
+ * Processes ranges in batches to avoid holding the maple tree spinlock
+ * across potentially expensive page unpinning.
+ */
+static int ublk_shmem_remove_ranges(struct ublk_device *ub, int buf_index)
+{
+ int ret = -ENOENT;
+
+ while (!__ublk_shmem_remove_ranges(ub, buf_index, &ret))
+ cond_resched();
return ret;
}
--
2.53.0
next prev parent reply other threads:[~2026-04-23 3:31 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-23 3:30 [PATCH 0/3] ublk: fix maple tree lockdep warning and cleanup Ming Lei
2026-04-23 3:30 ` [PATCH 1/3] ublk: fix maple tree lockdep warning in ublk_buf_cleanup Ming Lei
2026-04-23 3:30 ` [PATCH 2/3] ublk: refactor common helper ublk_shmem_remove_ranges() Ming Lei
2026-04-23 3:30 ` Ming Lei [this message]
2026-04-23 10:55 ` [PATCH 0/3] ublk: fix maple tree lockdep warning and cleanup Jens Axboe
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=20260423033058.2805135-4-tom.leiming@gmail.com \
--to=tom.leiming@gmail.com \
--cc=axboe@kernel.dk \
--cc=csander@purestorage.com \
--cc=liam.howlett@oracle.com \
--cc=linux-block@vger.kernel.org \
--cc=shinichiro.kawasaki@wdc.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