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>,
Ming Lei <tom.leiming@gmail.com>
Subject: [PATCH 4/7] ublk: replace xarray with IDA for shmem buffer index allocation
Date: Thu, 9 Apr 2026 21:30:16 +0800 [thread overview]
Message-ID: <20260409133020.3780098-5-tom.leiming@gmail.com> (raw)
In-Reply-To: <20260409133020.3780098-1-tom.leiming@gmail.com>
Remove struct ublk_buf which only contained nr_pages that was never
read after registration. Use IDA for pure index allocation instead
of xarray. Make __ublk_ctrl_unreg_buf() return int so the caller
can detect invalid index without a separate lookup.
Simplify ublk_buf_cleanup() to walk the maple tree directly and
unpin all pages in one pass, instead of iterating the xarray by
buffer index.
Suggested-by: Caleb Sander Mateos <csander@purestorage.com>
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
---
drivers/block/ublk_drv.c | 92 ++++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index efbb22fe481c..8b686e70cf28 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -297,11 +297,6 @@ struct ublk_queue {
struct ublk_io ios[] __counted_by(q_depth);
};
-/* Per-registered shared memory buffer */
-struct ublk_buf {
- unsigned int nr_pages;
-};
-
/* Maple tree value: maps a PFN range to buffer location */
struct ublk_buf_range {
unsigned short buf_index;
@@ -345,7 +340,7 @@ struct ublk_device {
/* shared memory zero copy */
struct maple_tree buf_tree;
- struct xarray bufs_xa;
+ struct ida buf_ida;
struct ublk_queue *queues[];
};
@@ -4693,7 +4688,7 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
spin_lock_init(&ub->lock);
mutex_init(&ub->cancel_mutex);
mt_init(&ub->buf_tree);
- xa_init_flags(&ub->bufs_xa, XA_FLAGS_ALLOC);
+ ida_init(&ub->buf_ida);
INIT_WORK(&ub->partition_scan_work, ublk_partition_scan_work);
ret = ublk_alloc_dev_number(ub, header->dev_id);
@@ -5279,11 +5274,9 @@ static void ublk_buf_erase_ranges(struct ublk_device *ub, int buf_index)
}
static int __ublk_ctrl_reg_buf(struct ublk_device *ub,
- struct ublk_buf *ubuf,
- struct page **pages, int index,
- unsigned short flags)
+ struct page **pages, unsigned long nr_pages,
+ int index, unsigned short flags)
{
- unsigned long nr_pages = ubuf->nr_pages;
unsigned long i;
int ret;
@@ -5335,9 +5328,8 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
struct page **pages = NULL;
unsigned int gup_flags;
struct gendisk *disk;
- struct ublk_buf *ubuf;
long pinned;
- u32 index;
+ int index;
int ret;
if (!ublk_dev_support_shmem_zc(ub))
@@ -5367,16 +5359,10 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
return -ENODEV;
/* Pin pages before quiescing (may sleep) */
- ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL);
- if (!ubuf) {
- ret = -ENOMEM;
- goto put_disk;
- }
-
pages = kvmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
if (!pages) {
ret = -ENOMEM;
- goto err_free;
+ goto put_disk;
}
gup_flags = FOLL_LONGTERM;
@@ -5392,7 +5378,6 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
ret = -EFAULT;
goto err_unpin;
}
- ubuf->nr_pages = nr_pages;
/*
* Drain inflight I/O and quiesce the queue so no new requests
@@ -5403,13 +5388,15 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
mutex_lock(&ub->mutex);
- ret = xa_alloc(&ub->bufs_xa, &index, ubuf, xa_limit_16b, GFP_KERNEL);
- if (ret)
+ index = ida_alloc_max(&ub->buf_ida, USHRT_MAX, GFP_KERNEL);
+ if (index < 0) {
+ ret = index;
goto err_unlock;
+ }
- ret = __ublk_ctrl_reg_buf(ub, ubuf, pages, index, buf_reg.flags);
+ ret = __ublk_ctrl_reg_buf(ub, pages, nr_pages, index, buf_reg.flags);
if (ret) {
- xa_erase(&ub->bufs_xa, index);
+ ida_free(&ub->buf_ida, index);
goto err_unlock;
}
@@ -5427,19 +5414,17 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
unpin_user_pages(pages, pinned);
err_free_pages:
kvfree(pages);
-err_free:
- kfree(ubuf);
put_disk:
ublk_put_disk(disk);
return ret;
}
-static void __ublk_ctrl_unreg_buf(struct ublk_device *ub,
- struct ublk_buf *ubuf, int buf_index)
+static int __ublk_ctrl_unreg_buf(struct ublk_device *ub, int buf_index)
{
MA_STATE(mas, &ub->buf_tree, 0, ULONG_MAX);
struct ublk_buf_range *range;
struct page *pages[32];
+ int ret = -ENOENT;
mas_lock(&mas);
mas_for_each(&mas, range, ULONG_MAX) {
@@ -5448,6 +5433,7 @@ static void __ublk_ctrl_unreg_buf(struct ublk_device *ub,
if (range->buf_index != buf_index)
continue;
+ ret = 0;
base = mas.index;
nr = mas.last - base + 1;
mas_erase(&mas);
@@ -5465,7 +5451,8 @@ static void __ublk_ctrl_unreg_buf(struct ublk_device *ub,
kfree(range);
}
mas_unlock(&mas);
- kfree(ubuf);
+
+ return ret;
}
static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
@@ -5473,11 +5460,14 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
{
int index = (int)header->data[0];
struct gendisk *disk;
- struct ublk_buf *ubuf;
+ int ret;
if (!ublk_dev_support_shmem_zc(ub))
return -EOPNOTSUPP;
+ if (index < 0 || index > USHRT_MAX)
+ return -EINVAL;
+
disk = ublk_get_disk(ub);
if (!disk)
return -ENODEV;
@@ -5487,32 +5477,42 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
mutex_lock(&ub->mutex);
- ubuf = xa_erase(&ub->bufs_xa, index);
- if (!ubuf) {
- mutex_unlock(&ub->mutex);
- ublk_unquiesce_and_resume(disk);
- ublk_put_disk(disk);
- return -ENOENT;
- }
-
- __ublk_ctrl_unreg_buf(ub, ubuf, index);
+ ret = __ublk_ctrl_unreg_buf(ub, index);
+ if (!ret)
+ ida_free(&ub->buf_ida, index);
mutex_unlock(&ub->mutex);
ublk_unquiesce_and_resume(disk);
ublk_put_disk(disk);
- return 0;
+ return ret;
}
static void ublk_buf_cleanup(struct ublk_device *ub)
{
- struct ublk_buf *ubuf;
- unsigned long index;
+ MA_STATE(mas, &ub->buf_tree, 0, ULONG_MAX);
+ struct ublk_buf_range *range;
+ struct page *pages[32];
+
+ mas_for_each(&mas, range, ULONG_MAX) {
+ unsigned long base = mas.index;
+ unsigned long nr = mas.last - base + 1;
+ unsigned long off;
- xa_for_each(&ub->bufs_xa, index, ubuf)
- __ublk_ctrl_unreg_buf(ub, ubuf, index);
- xa_destroy(&ub->bufs_xa);
+ for (off = 0; off < nr; ) {
+ unsigned int batch = min_t(unsigned long,
+ nr - off, 32);
+ unsigned int j;
+
+ for (j = 0; j < batch; j++)
+ pages[j] = pfn_to_page(base + off + j);
+ unpin_user_pages(pages, batch);
+ off += batch;
+ }
+ kfree(range);
+ }
mtree_destroy(&ub->buf_tree);
+ ida_destroy(&ub->buf_ida);
}
/* Check if request pages match a registered shared memory buffer */
--
2.53.0
next prev parent reply other threads:[~2026-04-09 13:30 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 13:30 [PATCH 0/7] ublk: followup fixes for SHMEM_ZC Ming Lei
2026-04-09 13:30 ` [PATCH 1/7] ublk: widen ublk_shmem_buf_reg.len to __u64 for 4GB buffer support Ming Lei
2026-04-14 18:40 ` Caleb Sander Mateos
2026-04-14 23:49 ` Ming Lei
2026-04-09 13:30 ` [PATCH 2/7] ublk: verify all pages in multi-page bvec fall within registered range Ming Lei
2026-04-09 13:30 ` [PATCH 3/7] ublk: simplify PFN range loop in __ublk_ctrl_reg_buf Ming Lei
2026-04-09 13:30 ` Ming Lei [this message]
2026-04-09 13:30 ` [PATCH 5/7] ublk: allow buffer registration before device is started Ming Lei
2026-04-09 13:30 ` [PATCH 6/7] Documentation: ublk: address review comments for SHMEM_ZC docs Ming Lei
2026-04-09 13:30 ` [PATCH 7/7] MAINTAINERS: update ublk driver maintainer email Ming Lei
2026-04-10 1:11 ` [PATCH 0/7] ublk: followup fixes for SHMEM_ZC Jens Axboe
2026-04-10 1:12 ` 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=20260409133020.3780098-5-tom.leiming@gmail.com \
--to=tom.leiming@gmail.com \
--cc=axboe@kernel.dk \
--cc=csander@purestorage.com \
--cc=linux-block@vger.kernel.org \
/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.