* [PATCH v2 0/2] ublk: fix auto buf reg ordering around uring_cmd
@ 2026-07-30 1:09 Yang Xiuwei
2026-07-30 1:09 ` [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd Yang Xiuwei
2026-07-30 1:09 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Yang Xiuwei
0 siblings, 2 replies; 7+ messages in thread
From: Yang Xiuwei @ 2026-07-30 1:09 UTC (permalink / raw)
To: Ming Lei, Jens Axboe; +Cc: linux-block, Caleb Sander Mateos, Yang Xiuwei
Two UBLK_F_AUTO_BUF_REG ordering fixes.
Patch 1: invalid auto_buf in sqe->addr can fail after ublk_fill_io_cmd()
has already set UBLK_IO_FLAG_ACTIVE. Split validate/apply so the check
has no side effects, then take the uring_cmd and store the validated
buffer.
Patch 2: batch commit wrote the new auto_buf into io->buf before
ublk_clear_auto_buf_reg(), so unregister could target the new index and
leave the old registered buffer behind. Clear first, then update
io->buf.
Changes in v2:
- patch 1: validate before __ublk_fetch()/fill; apply is infallible
(per Caleb's review)
- add patch 2 for the batch commit clear/store order
Tested:
ublk selftests generic_08/09, batch_01..03, stress_08;
liburing uring_cmd_ublk.t
v1: https://lore.kernel.org/linux-block/20260724100327.43482-1-yangxiuwei@kylinos.cn/
Yang Xiuwei (2):
ublk: validate auto buf reg before taking uring_cmd
ublk: clear auto buf reg before updating io->buf in batch commit
drivers/block/ublk_drv.c | 76 +++++++++++++++++++++-------------------
1 file changed, 39 insertions(+), 37 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd
2026-07-30 1:09 [PATCH v2 0/2] ublk: fix auto buf reg ordering around uring_cmd Yang Xiuwei
@ 2026-07-30 1:09 ` Yang Xiuwei
2026-07-31 16:10 ` Ming Lei
2026-07-30 1:09 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Yang Xiuwei
1 sibling, 1 reply; 7+ messages in thread
From: Yang Xiuwei @ 2026-07-30 1:09 UTC (permalink / raw)
To: Ming Lei, Jens Axboe; +Cc: linux-block, Caleb Sander Mateos, Yang Xiuwei
With UBLK_F_AUTO_BUF_REG, invalid sqe->addr can fail after
ublk_fill_io_cmd() has set UBLK_IO_FLAG_ACTIVE. The uring_cmd is
completed while the tag stays active, which can hang teardown.
Split validation from buffer apply so the check has no side effects,
then take the uring_cmd and store the already-validated buffer. Apply
the same order in FETCH so io->buf is not written before __ublk_fetch()
state checks.
Fixes: 52460dda3a77 ("ublk: move auto buffer register handling into one dedicated helper")
Suggested-by: Caleb Sander Mateos <csander@purestorage.com>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
---
drivers/block/ublk_drv.c | 74 +++++++++++++++++++++-------------------
1 file changed, 38 insertions(+), 36 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 4ca6ec738c93..041bd3ea023f 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -3075,18 +3075,19 @@ static inline int ublk_check_cmd_op(u32 cmd_op)
return 0;
}
-static inline int ublk_set_auto_buf_reg(struct ublk_io *io, struct io_uring_cmd *cmd)
+/* Must run before ublk_fill_io_cmd() / __ublk_fetch(). */
+static inline int ublk_validate_io_buf(const struct ublk_device *ub,
+ struct io_uring_cmd *cmd,
+ struct ublk_auto_buf_reg *buf)
{
- struct ublk_auto_buf_reg buf;
-
- buf = ublk_sqe_addr_to_auto_buf_reg(READ_ONCE(cmd->sqe->addr));
+ if (!ublk_dev_support_auto_buf_reg(ub))
+ return 0;
- if (buf.reserved0 || buf.reserved1)
+ *buf = ublk_sqe_addr_to_auto_buf_reg(READ_ONCE(cmd->sqe->addr));
+ if (buf->reserved0 || buf->reserved1)
return -EINVAL;
-
- if (buf.flags & ~UBLK_AUTO_BUF_REG_F_MASK)
+ if (buf->flags & ~UBLK_AUTO_BUF_REG_F_MASK)
return -EINVAL;
- io->buf.auto_reg = buf;
return 0;
}
@@ -3107,17 +3108,25 @@ static void ublk_clear_auto_buf_reg(struct ublk_io *io,
* responsibility for unregistering the buffer, otherwise
* this ublk request gets stuck.
*/
- if (io->buf_ctx_handle == io_uring_cmd_ctx_handle(cmd))
+ if (buf_idx &&
+ io->buf_ctx_handle == io_uring_cmd_ctx_handle(cmd))
*buf_idx = io->buf.auto_reg.index;
}
}
-static int ublk_handle_auto_buf_reg(struct ublk_io *io,
- struct io_uring_cmd *cmd,
- u16 *buf_idx)
+static inline void ublk_apply_io_buf(const struct ublk_device *ub,
+ struct ublk_io *io,
+ struct io_uring_cmd *cmd,
+ unsigned long buf_addr,
+ const struct ublk_auto_buf_reg *auto_buf,
+ u16 *buf_idx)
{
- ublk_clear_auto_buf_reg(io, cmd, buf_idx);
- return ublk_set_auto_buf_reg(io, cmd);
+ if (ublk_dev_support_auto_buf_reg(ub)) {
+ ublk_clear_auto_buf_reg(io, cmd, buf_idx);
+ io->buf.auto_reg = *auto_buf;
+ } else {
+ io->buf.addr = buf_addr;
+ }
}
/* Once we return, `io->req` can't be used any more */
@@ -3134,18 +3143,6 @@ ublk_fill_io_cmd(struct ublk_io *io, struct io_uring_cmd *cmd)
return req;
}
-static inline int
-ublk_config_io_buf(const struct ublk_device *ub, struct ublk_io *io,
- struct io_uring_cmd *cmd, unsigned long buf_addr,
- u16 *buf_idx)
-{
- if (ublk_dev_support_auto_buf_reg(ub))
- return ublk_handle_auto_buf_reg(io, cmd, buf_idx);
-
- io->buf.addr = buf_addr;
- return 0;
-}
-
static inline void ublk_prep_cancel(struct io_uring_cmd *cmd,
unsigned int issue_flags,
struct ublk_queue *ubq, unsigned int tag)
@@ -3286,6 +3283,7 @@ static int __ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,
static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,
struct ublk_io *io, __u64 buf_addr, u16 q_id)
{
+ struct ublk_auto_buf_reg auto_buf;
int ret;
/*
@@ -3294,11 +3292,13 @@ static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,
* FETCH, so it is fine even for IO_URING_F_NONBLOCK.
*/
mutex_lock(&ub->mutex);
- ret = __ublk_fetch(cmd, ub, io, q_id);
- if (!ret)
- ret = ublk_config_io_buf(ub, io, cmd, buf_addr, NULL);
+ ret = ublk_validate_io_buf(ub, cmd, &auto_buf);
if (!ret)
+ ret = __ublk_fetch(cmd, ub, io, q_id);
+ if (!ret) {
+ ublk_apply_io_buf(ub, io, cmd, buf_addr, &auto_buf, NULL);
ublk_mark_io_ready(ub, q_id, io);
+ }
mutex_unlock(&ub->mutex);
return ret;
}
@@ -3441,13 +3441,18 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
case UBLK_IO_REGISTER_IO_BUF:
return ublk_daemon_register_io_buf(cmd, ub, q_id, tag, io, addr,
issue_flags);
- case UBLK_IO_COMMIT_AND_FETCH_REQ:
+ case UBLK_IO_COMMIT_AND_FETCH_REQ: {
+ struct ublk_auto_buf_reg auto_buf;
+
ret = ublk_check_commit_and_fetch(ub, io, addr);
+ if (ret)
+ goto out;
+ ret = ublk_validate_io_buf(ub, cmd, &auto_buf);
if (ret)
goto out;
io->res = result;
req = ublk_fill_io_cmd(io, cmd);
- ret = ublk_config_io_buf(ub, io, cmd, addr, &buf_idx);
+ ublk_apply_io_buf(ub, io, cmd, addr, &auto_buf, &buf_idx);
if (buf_idx != UBLK_INVALID_BUF_IDX)
io_buffer_unregister_bvec(cmd, buf_idx, issue_flags);
compl = ublk_need_complete_req(ub, io);
@@ -3456,10 +3461,8 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
req->__sector = addr;
if (compl)
__ublk_complete_rq(req, io, ublk_dev_need_map_io(ub), NULL);
-
- if (ret)
- goto out;
break;
+ }
case UBLK_IO_NEED_GET_DATA:
/*
* ublk_get_data() may fail and fallback to requeue, so keep
@@ -3467,8 +3470,7 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
* request
*/
req = ublk_fill_io_cmd(io, cmd);
- ret = ublk_config_io_buf(ub, io, cmd, addr, NULL);
- WARN_ON_ONCE(ret);
+ io->buf.addr = addr;
if (likely(ublk_get_data(ubq, io, req))) {
__ublk_prep_compl_io_cmd(io, req);
return UBLK_IO_RES_OK;
--
2.25.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit
2026-07-30 1:09 [PATCH v2 0/2] ublk: fix auto buf reg ordering around uring_cmd Yang Xiuwei
2026-07-30 1:09 ` [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd Yang Xiuwei
@ 2026-07-30 1:09 ` Yang Xiuwei
2026-07-30 2:40 ` [PATCH] selftests: ublk: add rotating auto_buf index regression test Yang Xiuwei
2026-07-31 16:13 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Ming Lei
1 sibling, 2 replies; 7+ messages in thread
From: Yang Xiuwei @ 2026-07-30 1:09 UTC (permalink / raw)
To: Ming Lei, Jens Axboe; +Cc: linux-block, Caleb Sander Mateos, Yang Xiuwei
ublk_batch_commit_io() stored the new auto_buf into io->buf before
calling ublk_clear_auto_buf_reg(). Clear takes the unregister index
from io->buf.auto_reg, so it could drop the new slot and leave the
old registered buffer behind.
Fixes: 1e500e106d5a ("ublk: handle UBLK_U_IO_COMMIT_IO_CMDS")
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
---
drivers/block/ublk_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 041bd3ea023f..e12bc4ee74d3 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -3782,11 +3782,11 @@ static int ublk_batch_commit_io(struct ublk_queue *ubq,
ret = ublk_batch_commit_io_check(ubq, io, &buf);
if (!ret) {
io->res = elem->result;
- io->buf = buf;
req = ublk_fill_io_cmd(io, data->cmd);
if (auto_reg)
ublk_clear_auto_buf_reg(io, data->cmd, &buf_idx);
+ io->buf = buf;
compl = ublk_need_complete_req(data->ub, io);
}
ublk_io_unlock(io);
--
2.25.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH] selftests: ublk: add rotating auto_buf index regression test
2026-07-30 1:09 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Yang Xiuwei
@ 2026-07-30 2:40 ` Yang Xiuwei
2026-07-31 16:24 ` Ming Lei
2026-07-31 16:13 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Ming Lei
1 sibling, 1 reply; 7+ messages in thread
From: Yang Xiuwei @ 2026-07-30 2:40 UTC (permalink / raw)
To: Ming Lei, Jens Axboe, Shuah Khan
Cc: linux-block, linux-kselftest, Caleb Sander Mateos, Yang Xiuwei
Batch AUTO_BUF_REG COMMIT must unregister the old auto_buf index before
storing the next one. Fixed per-tag indexing (A == B) masks bugs that
clear after overwriting io->buf.
Add kublk --rotate_auto_buf so each tag alternates between two sparse
buffer indices, and test_batch_04.sh to exercise that path. Without the
driver fix, the request ref stays stuck and I/O hangs; the test uses a
short timeout and kills the ublk daemon to recover. With the fix, a
small write completes quickly.
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
---
tools/testing/selftests/ublk/Makefile | 1 +
tools/testing/selftests/ublk/batch.c | 2 +-
tools/testing/selftests/ublk/kublk.c | 19 +++++++-
tools/testing/selftests/ublk/kublk.h | 19 +++++++-
tools/testing/selftests/ublk/test_batch_04.sh | 44 +++++++++++++++++++
5 files changed, 82 insertions(+), 3 deletions(-)
create mode 100755 tools/testing/selftests/ublk/test_batch_04.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile
index 6e4fe8d1fed1..b5d757aa7ee8 100644
--- a/tools/testing/selftests/ublk/Makefile
+++ b/tools/testing/selftests/ublk/Makefile
@@ -23,6 +23,7 @@ TEST_PROGS += test_generic_17.sh
TEST_PROGS += test_batch_01.sh
TEST_PROGS += test_batch_02.sh
TEST_PROGS += test_batch_03.sh
+TEST_PROGS += test_batch_04.sh
TEST_PROGS += test_null_01.sh
TEST_PROGS += test_null_02.sh
diff --git a/tools/testing/selftests/ublk/batch.c b/tools/testing/selftests/ublk/batch.c
index a54025b00917..d8d9ebed5979 100644
--- a/tools/testing/selftests/ublk/batch.c
+++ b/tools/testing/selftests/ublk/batch.c
@@ -535,7 +535,7 @@ void ublk_batch_complete_io(struct ublk_thread *t, struct ublk_queue *q,
elem = (struct ublk_batch_elem *)(cb->elem + cb->done * t->commit_buf_elem_size);
elem->tag = tag;
- elem->buf_index = ublk_batch_io_buf_idx(t, q, tag);
+ elem->buf_index = ublk_batch_io_buf_idx_next(t, q, tag);
elem->result = res;
if (!ublk_queue_no_buf(q))
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c
index 0b23c09daea5..10320d9f73d1 100644
--- a/tools/testing/selftests/ublk/kublk.c
+++ b/tools/testing/selftests/ublk/kublk.c
@@ -540,9 +540,14 @@ static int ublk_thread_init(struct ublk_thread *t, unsigned long long extra_flag
unsigned max_nr_ios_per_thread = nr_ios / dev->nthreads;
max_nr_ios_per_thread += !!(nr_ios % dev->nthreads);
+ t->auto_buf_stride = max_nr_ios_per_thread;
t->nr_bufs = max_nr_ios_per_thread;
+ if ((extra_flags & UBLKS_Q_ROTATE_AUTO_BUF) &&
+ (dev->dev_info.flags & UBLK_F_AUTO_BUF_REG))
+ t->nr_bufs *= 2;
} else {
t->nr_bufs = 0;
+ t->auto_buf_stride = 0;
}
if (ublk_dev_batch_io(dev))
@@ -1436,6 +1441,8 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev)
extra_flags = UBLKS_Q_AUTO_BUF_REG_FALLBACK;
if (ctx->no_ublk_fixed_fd)
extra_flags |= UBLKS_Q_NO_UBLK_FIXED_FD;
+ if (ctx->rotate_auto_buf)
+ extra_flags |= UBLKS_Q_ROTATE_AUTO_BUF;
for (i = 0; i < dinfo->nr_hw_queues; i++) {
dev->q[i].dev = dev;
@@ -2067,7 +2074,7 @@ static void __cmd_create_help(char *exe, bool recovery)
printf("\t[--nthreads threads] [--per_io_tasks]\n");
printf("\t[--integrity_capable] [--integrity_reftag] [--metadata_size SIZE] "
"[--pi_offset OFFSET] [--csum_type ip|t10dif|nvme] [--tag_size SIZE]\n");
- printf("\t[--batch|-b] [--no_auto_part_scan]\n");
+ printf("\t[--batch|-b] [--rotate_auto_buf] [--no_auto_part_scan]\n");
printf("\t[target options] [backfile1] [backfile2] ...\n");
printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
printf("\tdefault: nthreads=nr_queues");
@@ -2141,6 +2148,7 @@ int main(int argc, char *argv[])
{ "tag_size", 1, NULL, 0 },
{ "safe", 0, NULL, 0 },
{ "batch", 0, NULL, 'b'},
+ { "rotate_auto_buf", 0, NULL, 0 },
{ "no_auto_part_scan", 0, NULL, 0 },
{ "shmem_zc", 0, NULL, 0 },
{ "htlb", 1, NULL, 0 },
@@ -2228,6 +2236,8 @@ int main(int argc, char *argv[])
ctx.flags |= UBLK_F_AUTO_BUF_REG;
if (!strcmp(longopts[option_idx].name, "auto_zc_fallback"))
ctx.auto_zc_fallback = 1;
+ if (!strcmp(longopts[option_idx].name, "rotate_auto_buf"))
+ ctx.rotate_auto_buf = 1;
if (!strcmp(longopts[option_idx].name, "nthreads"))
ctx.nthreads = strtol(optarg, NULL, 10);
if (!strcmp(longopts[option_idx].name, "per_io_tasks"))
@@ -2335,6 +2345,13 @@ int main(int argc, char *argv[])
return -EINVAL;
}
+ if (ctx.rotate_auto_buf &&
+ !((ctx.flags & UBLK_F_AUTO_BUF_REG) &&
+ (ctx.flags & UBLK_F_BATCH_IO))) {
+ ublk_err("rotate_auto_buf requires --auto_zc and --batch\n");
+ return -EINVAL;
+ }
+
i = optind;
while (i < argc && ctx.nr_files < MAX_BACK_FILES) {
ctx.files[ctx.nr_files++] = argv[i++];
diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h
index 742c41d77df1..188b97f0cb95 100644
--- a/tools/testing/selftests/ublk/kublk.h
+++ b/tools/testing/selftests/ublk/kublk.h
@@ -82,6 +82,7 @@ struct dev_ctx {
unsigned int safe_stop:1;
unsigned int no_auto_part_scan:1;
unsigned int rdonly_shmem_buf:1;
+ unsigned int rotate_auto_buf:1;
__u32 integrity_flags;
__u8 metadata_size;
__u8 pi_offset;
@@ -134,6 +135,7 @@ struct ublk_io {
unsigned short buf_index;
unsigned short tgt_ios;
+ unsigned char auto_buf_phase;
void *private_data;
};
@@ -184,6 +186,7 @@ struct ublk_queue {
#define UBLKS_Q_AUTO_BUF_REG_FALLBACK (1ULL << 63)
#define UBLKS_Q_NO_UBLK_FIXED_FD (1ULL << 62)
#define UBLKS_Q_PREPARED (1ULL << 61)
+#define UBLKS_Q_ROTATE_AUTO_BUF (1ULL << 60)
__u64 flags;
int ublk_fd; /* cached ublk char device fd */
__u8 metadata_size;
@@ -232,6 +235,7 @@ struct ublk_thread {
unsigned int io_inflight;
unsigned short nr_bufs;
+ unsigned short auto_buf_stride;
/* followings are for BATCH_IO */
unsigned short commit_buf_start;
@@ -550,7 +554,20 @@ static inline unsigned short ublk_batch_io_buf_idx(
const struct ublk_thread *t, const struct ublk_queue *q,
unsigned tag)
{
- return ublk_queue_idx_in_thread(t, q) * q->q_depth + tag;
+ unsigned short base = ublk_queue_idx_in_thread(t, q) * q->q_depth + tag;
+
+ if (q->flags & UBLKS_Q_ROTATE_AUTO_BUF)
+ return base + q->ios[tag].auto_buf_phase * t->auto_buf_stride;
+ return base;
+}
+
+static inline unsigned short ublk_batch_io_buf_idx_next(
+ const struct ublk_thread *t, struct ublk_queue *q,
+ unsigned tag)
+{
+ if (q->flags & UBLKS_Q_ROTATE_AUTO_BUF)
+ q->ios[tag].auto_buf_phase ^= 1;
+ return ublk_batch_io_buf_idx(t, q, tag);
}
/* Queue UBLK_U_IO_PREP_IO_CMDS for a specific queue with batch elements */
diff --git a/tools/testing/selftests/ublk/test_batch_04.sh b/tools/testing/selftests/ublk/test_batch_04.sh
new file mode 100755
index 000000000000..cd5e1ff9d630
--- /dev/null
+++ b/tools/testing/selftests/ublk/test_batch_04.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# --rotate_auto_buf: COMMIT must unregister old auto_buf index before store.
+
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+
+ERR_CODE=0
+
+if ! _have_feature "BATCH_IO" || ! _have_feature "AUTO_BUF_REG"; then
+ exit "$UBLK_SKIP_CODE"
+fi
+if ! _have_program fio || ! _have_program timeout; then
+ exit "$UBLK_SKIP_CODE"
+fi
+
+_prep_test "generic" "batch auto_buf unregister with rotating index"
+
+_create_backfile 0 64M
+
+dev_id=$(_add_ublk_dev_no_settle -t loop -q 1 --nthreads 1 -b --auto_zc \
+ --rotate_auto_buf "${UBLK_BACKFILES[0]}")
+_check_add_dev $TID $?
+
+for ((i = 0; i < 50; i++)); do
+ [ -b /dev/ublkb"${dev_id}" ] && break
+ sleep 0.1
+done
+[ -b /dev/ublkb"${dev_id}" ] || { _cleanup_test; _show_result $TID 1; }
+
+timeout -k 2 5 fio --name=job1 --filename=/dev/ublkb"${dev_id}" \
+ --ioengine=libaio --rw=write --direct=1 --bs=4k --iodepth=1 --size=64k \
+ > /dev/null 2>&1
+ERR_CODE=$?
+
+if [ "$ERR_CODE" -ne 0 ]; then
+ kill -9 "$(_get_ublk_daemon_pid "$dev_id" 2>/dev/null)" 2>/dev/null || true
+ sleep 0.5
+ pkill -9 fio 2>/dev/null || true
+ ERR_CODE=1
+fi
+
+_cleanup_test
+_show_result $TID $ERR_CODE
--
2.25.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd
2026-07-30 1:09 ` [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd Yang Xiuwei
@ 2026-07-31 16:10 ` Ming Lei
0 siblings, 0 replies; 7+ messages in thread
From: Ming Lei @ 2026-07-31 16:10 UTC (permalink / raw)
To: Yang Xiuwei; +Cc: Jens Axboe, linux-block, Caleb Sander Mateos
On Thu, Jul 30, 2026 at 09:09:09AM +0800, Yang Xiuwei wrote:
> With UBLK_F_AUTO_BUF_REG, invalid sqe->addr can fail after
> ublk_fill_io_cmd() has set UBLK_IO_FLAG_ACTIVE. The uring_cmd is
> completed while the tag stays active, which can hang teardown.
>
> Split validation from buffer apply so the check has no side effects,
> then take the uring_cmd and store the already-validated buffer. Apply
> the same order in FETCH so io->buf is not written before __ublk_fetch()
> state checks.
>
> Fixes: 52460dda3a77 ("ublk: move auto buffer register handling into one dedicated helper")
> Suggested-by: Caleb Sander Mateos <csander@purestorage.com>
> Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Nice catch!
Reviewed-by: Ming Lei <tom.leiming@gmail.com>
Thanks,
Ming
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit
2026-07-30 1:09 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Yang Xiuwei
2026-07-30 2:40 ` [PATCH] selftests: ublk: add rotating auto_buf index regression test Yang Xiuwei
@ 2026-07-31 16:13 ` Ming Lei
1 sibling, 0 replies; 7+ messages in thread
From: Ming Lei @ 2026-07-31 16:13 UTC (permalink / raw)
To: Yang Xiuwei; +Cc: Jens Axboe, linux-block, Caleb Sander Mateos
On Thu, Jul 30, 2026 at 09:09:10AM +0800, Yang Xiuwei wrote:
> ublk_batch_commit_io() stored the new auto_buf into io->buf before
> calling ublk_clear_auto_buf_reg(). Clear takes the unregister index
> from io->buf.auto_reg, so it could drop the new slot and leave the
> old registered buffer behind.
>
> Fixes: 1e500e106d5a ("ublk: handle UBLK_U_IO_COMMIT_IO_CMDS")
> Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Reviewed-by: Ming Lei <tom.leiming@gmail.com>
Thanks,
Ming
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] selftests: ublk: add rotating auto_buf index regression test
2026-07-30 2:40 ` [PATCH] selftests: ublk: add rotating auto_buf index regression test Yang Xiuwei
@ 2026-07-31 16:24 ` Ming Lei
0 siblings, 0 replies; 7+ messages in thread
From: Ming Lei @ 2026-07-31 16:24 UTC (permalink / raw)
To: Yang Xiuwei
Cc: Jens Axboe, Shuah Khan, linux-block, linux-kselftest,
Caleb Sander Mateos
On Thu, Jul 30, 2026 at 10:40:50AM +0800, Yang Xiuwei wrote:
> Batch AUTO_BUF_REG COMMIT must unregister the old auto_buf index before
> storing the next one. Fixed per-tag indexing (A == B) masks bugs that
> clear after overwriting io->buf.
>
> Add kublk --rotate_auto_buf so each tag alternates between two sparse
> buffer indices, and test_batch_04.sh to exercise that path. Without the
> driver fix, the request ref stays stuck and I/O hangs; the test uses a
> short timeout and kills the ublk daemon to recover. With the fix, a
> small write completes quickly.
>
> Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Looks fine,
Reviewed-by: Ming Lei <tom.leiming@gmail.com>
BTW, this selftest patch should have been part of
"[PATCH v2 0/2] ublk: fix auto buf reg ordering around uring_cmd"
Thanks,
Ming
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-31 16:25 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 1:09 [PATCH v2 0/2] ublk: fix auto buf reg ordering around uring_cmd Yang Xiuwei
2026-07-30 1:09 ` [PATCH v2 1/2] ublk: validate auto buf reg before taking uring_cmd Yang Xiuwei
2026-07-31 16:10 ` Ming Lei
2026-07-30 1:09 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Yang Xiuwei
2026-07-30 2:40 ` [PATCH] selftests: ublk: add rotating auto_buf index regression test Yang Xiuwei
2026-07-31 16:24 ` Ming Lei
2026-07-31 16:13 ` [PATCH v2 2/2] ublk: clear auto buf reg before updating io->buf in batch commit Ming Lei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox