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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.