* [PATCH v6.15 0/3] ublk: one selftest fix and two zero copy fixes
@ 2025-04-27 13:49 Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA Ming Lei
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Ming Lei @ 2025-04-27 13:49 UTC (permalink / raw)
To: Jens Axboe, linux-block
Cc: Uday Shankar, Caleb Sander Mateos, Keith Busch, Ming Lei
Hello Jens,
The 1st patch fixes UBLK_F_NEED_GET_DATA support in ublk selftest side.
The other two patches enhances check for zero copy feature.
Thanks,
Ming
Ming Lei (3):
selftests: ublk: fix UBLK_F_NEED_GET_DATA
ublk: decouple zero copy from user copy
ublk: enhance check for register/unregister io buffer command
drivers/block/ublk_drv.c | 59 ++++++++++++++-----
tools/testing/selftests/ublk/Makefile | 1 +
tools/testing/selftests/ublk/kublk.c | 20 ++++---
tools/testing/selftests/ublk/kublk.h | 1 +
.../testing/selftests/ublk/test_generic_07.sh | 24 ++++++++
.../testing/selftests/ublk/test_stress_05.sh | 8 +--
6 files changed, 86 insertions(+), 27 deletions(-)
create mode 100755 tools/testing/selftests/ublk/test_generic_07.sh
--
2.47.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA
2025-04-27 13:49 [PATCH v6.15 0/3] ublk: one selftest fix and two zero copy fixes Ming Lei
@ 2025-04-27 13:49 ` Ming Lei
2025-04-28 15:51 ` Caleb Sander Mateos
2025-04-27 13:49 ` [PATCH v6.15 2/3] ublk: decouple zero copy from user copy Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command Ming Lei
2 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-27 13:49 UTC (permalink / raw)
To: Jens Axboe, linux-block
Cc: Uday Shankar, Caleb Sander Mateos, Keith Busch, Ming Lei
Commit 57e13a2e8cd2 ("selftests: ublk: support user recovery") starts to
support UBLK_F_NEED_GET_DATA for covering recovery feature, however the
ublk utility implementation isn't done correctly.
Fix it by supporting UBLK_F_NEED_GET_DATA correctly.
Also add test generic_07 for covering UBLK_F_NEED_GET_DATA.
Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
Fixes: 57e13a2e8cd2 ("selftests: ublk: support user recovery")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
tools/testing/selftests/ublk/Makefile | 1 +
tools/testing/selftests/ublk/kublk.c | 20 ++++++++++------
tools/testing/selftests/ublk/kublk.h | 1 +
.../testing/selftests/ublk/test_generic_07.sh | 24 +++++++++++++++++++
.../testing/selftests/ublk/test_stress_05.sh | 8 +++----
5 files changed, 43 insertions(+), 11 deletions(-)
create mode 100755 tools/testing/selftests/ublk/test_generic_07.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile
index ec4624a283bc..f34ac0bac696 100644
--- a/tools/testing/selftests/ublk/Makefile
+++ b/tools/testing/selftests/ublk/Makefile
@@ -9,6 +9,7 @@ TEST_PROGS += test_generic_03.sh
TEST_PROGS += test_generic_04.sh
TEST_PROGS += test_generic_05.sh
TEST_PROGS += test_generic_06.sh
+TEST_PROGS += test_generic_07.sh
TEST_PROGS += test_null_01.sh
TEST_PROGS += test_null_02.sh
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c
index e57a1486bb48..3afd45d7f989 100644
--- a/tools/testing/selftests/ublk/kublk.c
+++ b/tools/testing/selftests/ublk/kublk.c
@@ -536,12 +536,17 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag)
if (!(io->flags & UBLKSRV_IO_FREE))
return 0;
- /* we issue because we need either fetching or committing */
+ /*
+ * we issue because we need either fetching or committing or
+ * getting data
+ */
if (!(io->flags &
- (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP)))
+ (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_NEED_GET_DATA)))
return 0;
- if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
+ if (io->flags & UBLKSRV_NEED_GET_DATA)
+ cmd_op = UBLK_U_IO_NEED_GET_DATA;
+ else if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ;
else if (io->flags & UBLKSRV_NEED_FETCH_RQ)
cmd_op = UBLK_U_IO_FETCH_REQ;
@@ -658,6 +663,9 @@ static void ublk_handle_cqe(struct io_uring *r,
assert(tag < q->q_depth);
if (q->tgt_ops->queue_io)
q->tgt_ops->queue_io(q, tag);
+ } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) {
+ io->flags |= UBLKSRV_NEED_GET_DATA | UBLKSRV_IO_FREE;
+ ublk_queue_io_cmd(q, io, tag);
} else {
/*
* COMMIT_REQ will be completed immediately since no fetching
@@ -1313,7 +1321,7 @@ int main(int argc, char *argv[])
opterr = 0;
optind = 2;
- while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:az",
+ while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:gaz",
longopts, &option_idx)) != -1) {
switch (opt) {
case 'a':
@@ -1351,9 +1359,7 @@ int main(int argc, char *argv[])
ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE;
break;
case 'g':
- value = strtol(optarg, NULL, 10);
- if (value)
- ctx.flags |= UBLK_F_NEED_GET_DATA;
+ ctx.flags |= UBLK_F_NEED_GET_DATA;
break;
case 0:
if (!strcmp(longopts[option_idx].name, "debug_mask"))
diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h
index 918db5cd633f..44ee1e4ac55b 100644
--- a/tools/testing/selftests/ublk/kublk.h
+++ b/tools/testing/selftests/ublk/kublk.h
@@ -115,6 +115,7 @@ struct ublk_io {
#define UBLKSRV_NEED_FETCH_RQ (1UL << 0)
#define UBLKSRV_NEED_COMMIT_RQ_COMP (1UL << 1)
#define UBLKSRV_IO_FREE (1UL << 2)
+#define UBLKSRV_NEED_GET_DATA (1UL << 3)
unsigned short flags;
unsigned short refs; /* used by target code only */
diff --git a/tools/testing/selftests/ublk/test_generic_07.sh b/tools/testing/selftests/ublk/test_generic_07.sh
new file mode 100755
index 000000000000..e3ad36ef7b9a
--- /dev/null
+++ b/tools/testing/selftests/ublk/test_generic_07.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+
+TID="generic_07"
+ERR_CODE=0
+
+_prep_test "generic" "test UBLK_F_NEED_GET_DATA"
+
+_create_backfile 0 256M
+dev_id=$(_add_ublk_dev -t loop -q 2 -g "${UBLK_BACKFILES[0]}")
+_check_add_dev $TID $?
+
+# run fio over the ublk disk
+_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
+ERR_CODE=$?
+if [ "$ERR_CODE" -eq 0 ]; then
+ _mkfs_mount_test /dev/ublkb"${dev_id}"
+ ERR_CODE=$?
+fi
+
+_cleanup_test "generic"
+_show_result $TID $ERR_CODE
diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh
index a7071b10224d..88601b48f1cd 100755
--- a/tools/testing/selftests/ublk/test_stress_05.sh
+++ b/tools/testing/selftests/ublk/test_stress_05.sh
@@ -47,15 +47,15 @@ _create_backfile 0 256M
_create_backfile 1 256M
for reissue in $(seq 0 1); do
- ublk_io_and_remove 8G -t null -q 4 -g 1 -r 1 -i "$reissue" &
- ublk_io_and_remove 256M -t loop -q 4 -g 1 -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" &
+ ublk_io_and_remove 8G -t null -q 4 -g -r 1 -i "$reissue" &
+ ublk_io_and_remove 256M -t loop -q 4 -g -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" &
wait
done
if _have_feature "ZERO_COPY"; then
for reissue in $(seq 0 1); do
- ublk_io_and_remove 8G -t null -q 4 -g 1 -z -r 1 -i "$reissue" &
- ublk_io_and_remove 256M -t loop -q 4 -g 1 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
+ ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &
+ ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
wait
done
fi
--
2.47.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v6.15 2/3] ublk: decouple zero copy from user copy
2025-04-27 13:49 [PATCH v6.15 0/3] ublk: one selftest fix and two zero copy fixes Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA Ming Lei
@ 2025-04-27 13:49 ` Ming Lei
2025-04-28 16:01 ` Caleb Sander Mateos
2025-04-27 13:49 ` [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command Ming Lei
2 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-27 13:49 UTC (permalink / raw)
To: Jens Axboe, linux-block
Cc: Uday Shankar, Caleb Sander Mateos, Keith Busch, Ming Lei
UBLK_F_USER_COPY and UBLK_F_SUPPORT_ZERO_COPY are two different
features, and shouldn't be coupled together.
Commit 1f6540e2aabb ("ublk: zc register/unregister bvec") enables
user copy automatically in case of UBLK_F_SUPPORT_ZERO_COPY, this way
isn't correct.
So decouple zero copy from user copy, and use independent helper to
check each one.
Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 40f971a66d3e..0a3a3c64316d 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -205,11 +205,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
static inline unsigned int ublk_req_build_flags(struct request *req);
static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
int tag);
-static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
-{
- return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
-}
-
static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
{
return ub->dev_info.flags & UBLK_F_ZONED;
@@ -609,14 +604,19 @@ static void ublk_apply_params(struct ublk_device *ub)
ublk_dev_param_zoned_apply(ub);
}
+static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
+{
+ return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
+}
+
static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
{
- return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
+ return ubq->flags & UBLK_F_USER_COPY;
}
static inline bool ublk_need_map_io(const struct ublk_queue *ubq)
{
- return !ublk_support_user_copy(ubq);
+ return !ublk_support_user_copy(ubq) && !ublk_support_zero_copy(ubq);
}
static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
@@ -624,8 +624,11 @@ static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
/*
* read()/write() is involved in user copy, so request reference
* has to be grabbed
+ *
+ * for zero copy, request buffer need to be registered to io_uring
+ * buffer table, so reference is needed
*/
- return ublk_support_user_copy(ubq);
+ return ublk_support_user_copy(ubq) || ublk_support_zero_copy(ubq);
}
static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
@@ -2245,6 +2248,9 @@ static struct request *ublk_check_and_get_req(struct kiocb *iocb,
if (!ubq)
return ERR_PTR(-EINVAL);
+ if (!ublk_support_user_copy(ubq))
+ return ERR_PTR(-EACCES);
+
if (tag >= ubq->q_depth)
return ERR_PTR(-EINVAL);
@@ -2783,13 +2789,18 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
UBLK_F_URING_CMD_COMP_IN_TASK;
- /* GET_DATA isn't needed any more with USER_COPY */
- if (ublk_dev_is_user_copy(ub))
+ /* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */
+ if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY))
ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA;
- /* Zoned storage support requires user copy feature */
+ /*
+ * Zoned storage support requires reuse `ublksrv_io_cmd->addr` for
+ * returning write_append_lba, which is only allowed in case of
+ * user copy or zero copy
+ */
if (ublk_dev_is_zoned(ub) &&
- (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !ublk_dev_is_user_copy(ub))) {
+ (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !(ub->dev_info.flags &
+ (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY)))) {
ret = -EINVAL;
goto out_free_dev_number;
}
--
2.47.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command
2025-04-27 13:49 [PATCH v6.15 0/3] ublk: one selftest fix and two zero copy fixes Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 2/3] ublk: decouple zero copy from user copy Ming Lei
@ 2025-04-27 13:49 ` Ming Lei
2025-04-28 16:28 ` Caleb Sander Mateos
2 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-27 13:49 UTC (permalink / raw)
To: Jens Axboe, linux-block
Cc: Uday Shankar, Caleb Sander Mateos, Keith Busch, Ming Lei
The simple check of UBLK_IO_FLAG_OWNED_BY_SRV can avoid incorrect
register/unregister io buffer easily, so check it before calling
starting to register/un-register io buffer.
Also only allow io buffer register/unregister uring_cmd in case of
UBLK_F_SUPPORT_ZERO_COPY.
Also mark argument 'ublk_queue *' of ublk_register_io_buf as const.
Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
drivers/block/ublk_drv.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 0a3a3c64316d..c624d8f653ae 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -201,7 +201,7 @@ struct ublk_params_header {
static void ublk_stop_dev_unlocked(struct ublk_device *ub);
static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
- struct ublk_queue *ubq, int tag, size_t offset);
+ const struct ublk_queue *ubq, int tag, size_t offset);
static inline unsigned int ublk_req_build_flags(struct request *req);
static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
int tag);
@@ -1949,13 +1949,20 @@ static void ublk_io_release(void *priv)
}
static int ublk_register_io_buf(struct io_uring_cmd *cmd,
- struct ublk_queue *ubq, unsigned int tag,
+ const struct ublk_queue *ubq, unsigned int tag,
unsigned int index, unsigned int issue_flags)
{
struct ublk_device *ub = cmd->file->private_data;
+ const struct ublk_io *io = &ubq->ios[tag];
struct request *req;
int ret;
+ if (!ublk_support_zero_copy(ubq))
+ return -EINVAL;
+
+ if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
+ return -EINVAL;
+
req = __ublk_check_and_get_req(ub, ubq, tag, 0);
if (!req)
return -EINVAL;
@@ -1971,8 +1978,17 @@ static int ublk_register_io_buf(struct io_uring_cmd *cmd,
}
static int ublk_unregister_io_buf(struct io_uring_cmd *cmd,
+ const struct ublk_queue *ubq, unsigned int tag,
unsigned int index, unsigned int issue_flags)
{
+ const struct ublk_io *io = &ubq->ios[tag];
+
+ if (!ublk_support_zero_copy(ubq))
+ return -EINVAL;
+
+ if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
+ return -EINVAL;
+
return io_buffer_unregister_bvec(cmd, index, issue_flags);
}
@@ -2076,7 +2092,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
case UBLK_IO_REGISTER_IO_BUF:
return ublk_register_io_buf(cmd, ubq, tag, ub_cmd->addr, issue_flags);
case UBLK_IO_UNREGISTER_IO_BUF:
- return ublk_unregister_io_buf(cmd, ub_cmd->addr, issue_flags);
+ return ublk_unregister_io_buf(cmd, ubq, tag, ub_cmd->addr, issue_flags);
case UBLK_IO_FETCH_REQ:
ret = ublk_fetch(cmd, ubq, io, ub_cmd->addr);
if (ret)
@@ -2128,7 +2144,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
}
static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
- struct ublk_queue *ubq, int tag, size_t offset)
+ const struct ublk_queue *ubq, int tag, size_t offset)
{
struct request *req;
--
2.47.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA
2025-04-27 13:49 ` [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA Ming Lei
@ 2025-04-28 15:51 ` Caleb Sander Mateos
2025-04-29 0:53 ` Ming Lei
0 siblings, 1 reply; 13+ messages in thread
From: Caleb Sander Mateos @ 2025-04-28 15:51 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
>
> Commit 57e13a2e8cd2 ("selftests: ublk: support user recovery") starts to
> support UBLK_F_NEED_GET_DATA for covering recovery feature, however the
> ublk utility implementation isn't done correctly.
>
> Fix it by supporting UBLK_F_NEED_GET_DATA correctly.
>
> Also add test generic_07 for covering UBLK_F_NEED_GET_DATA.
>
> Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
> Fixes: 57e13a2e8cd2 ("selftests: ublk: support user recovery")
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
> tools/testing/selftests/ublk/Makefile | 1 +
> tools/testing/selftests/ublk/kublk.c | 20 ++++++++++------
> tools/testing/selftests/ublk/kublk.h | 1 +
> .../testing/selftests/ublk/test_generic_07.sh | 24 +++++++++++++++++++
> .../testing/selftests/ublk/test_stress_05.sh | 8 +++----
> 5 files changed, 43 insertions(+), 11 deletions(-)
> create mode 100755 tools/testing/selftests/ublk/test_generic_07.sh
>
> diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile
> index ec4624a283bc..f34ac0bac696 100644
> --- a/tools/testing/selftests/ublk/Makefile
> +++ b/tools/testing/selftests/ublk/Makefile
> @@ -9,6 +9,7 @@ TEST_PROGS += test_generic_03.sh
> TEST_PROGS += test_generic_04.sh
> TEST_PROGS += test_generic_05.sh
> TEST_PROGS += test_generic_06.sh
> +TEST_PROGS += test_generic_07.sh
>
> TEST_PROGS += test_null_01.sh
> TEST_PROGS += test_null_02.sh
> diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c
> index e57a1486bb48..3afd45d7f989 100644
> --- a/tools/testing/selftests/ublk/kublk.c
> +++ b/tools/testing/selftests/ublk/kublk.c
> @@ -536,12 +536,17 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag)
> if (!(io->flags & UBLKSRV_IO_FREE))
> return 0;
>
> - /* we issue because we need either fetching or committing */
> + /*
> + * we issue because we need either fetching or committing or
> + * getting data
> + */
> if (!(io->flags &
> - (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP)))
> + (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_NEED_GET_DATA)))
> return 0;
>
> - if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
> + if (io->flags & UBLKSRV_NEED_GET_DATA)
> + cmd_op = UBLK_U_IO_NEED_GET_DATA;
> + else if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
> cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ;
> else if (io->flags & UBLKSRV_NEED_FETCH_RQ)
> cmd_op = UBLK_U_IO_FETCH_REQ;
> @@ -658,6 +663,9 @@ static void ublk_handle_cqe(struct io_uring *r,
> assert(tag < q->q_depth);
> if (q->tgt_ops->queue_io)
> q->tgt_ops->queue_io(q, tag);
> + } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) {
> + io->flags |= UBLKSRV_NEED_GET_DATA | UBLKSRV_IO_FREE;
> + ublk_queue_io_cmd(q, io, tag);
> } else {
> /*
> * COMMIT_REQ will be completed immediately since no fetching
> @@ -1313,7 +1321,7 @@ int main(int argc, char *argv[])
>
> opterr = 0;
> optind = 2;
> - while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:az",
> + while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:gaz",
> longopts, &option_idx)) != -1) {
> switch (opt) {
> case 'a':
> @@ -1351,9 +1359,7 @@ int main(int argc, char *argv[])
> ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE;
> break;
> case 'g':
> - value = strtol(optarg, NULL, 10);
> - if (value)
> - ctx.flags |= UBLK_F_NEED_GET_DATA;
> + ctx.flags |= UBLK_F_NEED_GET_DATA;
The help text in __cmd_create_help() should be updated accordingly.
> break;
> case 0:
> if (!strcmp(longopts[option_idx].name, "debug_mask"))
> diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h
> index 918db5cd633f..44ee1e4ac55b 100644
> --- a/tools/testing/selftests/ublk/kublk.h
> +++ b/tools/testing/selftests/ublk/kublk.h
> @@ -115,6 +115,7 @@ struct ublk_io {
> #define UBLKSRV_NEED_FETCH_RQ (1UL << 0)
> #define UBLKSRV_NEED_COMMIT_RQ_COMP (1UL << 1)
> #define UBLKSRV_IO_FREE (1UL << 2)
> +#define UBLKSRV_NEED_GET_DATA (1UL << 3)
> unsigned short flags;
> unsigned short refs; /* used by target code only */
>
> diff --git a/tools/testing/selftests/ublk/test_generic_07.sh b/tools/testing/selftests/ublk/test_generic_07.sh
> new file mode 100755
> index 000000000000..e3ad36ef7b9a
> --- /dev/null
> +++ b/tools/testing/selftests/ublk/test_generic_07.sh
> @@ -0,0 +1,24 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +
> +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
> +
> +TID="generic_07"
> +ERR_CODE=0
> +
> +_prep_test "generic" "test UBLK_F_NEED_GET_DATA"
> +
> +_create_backfile 0 256M
> +dev_id=$(_add_ublk_dev -t loop -q 2 -g "${UBLK_BACKFILES[0]}")
> +_check_add_dev $TID $?
> +
> +# run fio over the ublk disk
> +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
I thought you were planning to add a _have_program fio check?
Best,
Caleb
> +ERR_CODE=$?
> +if [ "$ERR_CODE" -eq 0 ]; then
> + _mkfs_mount_test /dev/ublkb"${dev_id}"
> + ERR_CODE=$?
> +fi
> +
> +_cleanup_test "generic"
> +_show_result $TID $ERR_CODE
> diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh
> index a7071b10224d..88601b48f1cd 100755
> --- a/tools/testing/selftests/ublk/test_stress_05.sh
> +++ b/tools/testing/selftests/ublk/test_stress_05.sh
> @@ -47,15 +47,15 @@ _create_backfile 0 256M
> _create_backfile 1 256M
>
> for reissue in $(seq 0 1); do
> - ublk_io_and_remove 8G -t null -q 4 -g 1 -r 1 -i "$reissue" &
> - ublk_io_and_remove 256M -t loop -q 4 -g 1 -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" &
> + ublk_io_and_remove 8G -t null -q 4 -g -r 1 -i "$reissue" &
> + ublk_io_and_remove 256M -t loop -q 4 -g -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" &
> wait
> done
>
> if _have_feature "ZERO_COPY"; then
> for reissue in $(seq 0 1); do
> - ublk_io_and_remove 8G -t null -q 4 -g 1 -z -r 1 -i "$reissue" &
> - ublk_io_and_remove 256M -t loop -q 4 -g 1 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
> + ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &
> + ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
> wait
> done
> fi
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 2/3] ublk: decouple zero copy from user copy
2025-04-27 13:49 ` [PATCH v6.15 2/3] ublk: decouple zero copy from user copy Ming Lei
@ 2025-04-28 16:01 ` Caleb Sander Mateos
2025-04-29 0:55 ` Ming Lei
0 siblings, 1 reply; 13+ messages in thread
From: Caleb Sander Mateos @ 2025-04-28 16:01 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
>
> UBLK_F_USER_COPY and UBLK_F_SUPPORT_ZERO_COPY are two different
> features, and shouldn't be coupled together.
>
> Commit 1f6540e2aabb ("ublk: zc register/unregister bvec") enables
> user copy automatically in case of UBLK_F_SUPPORT_ZERO_COPY, this way
> isn't correct.
>
> So decouple zero copy from user copy, and use independent helper to
> check each one.
I agree this makes sense.
>
> Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
> drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++------------
> 1 file changed, 23 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 40f971a66d3e..0a3a3c64316d 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -205,11 +205,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> static inline unsigned int ublk_req_build_flags(struct request *req);
> static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> int tag);
> -static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
> -{
> - return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> -}
> -
> static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
> {
> return ub->dev_info.flags & UBLK_F_ZONED;
> @@ -609,14 +604,19 @@ static void ublk_apply_params(struct ublk_device *ub)
> ublk_dev_param_zoned_apply(ub);
> }
>
> +static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
> +{
> + return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
> +}
> +
> static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
> {
> - return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> + return ubq->flags & UBLK_F_USER_COPY;
> }
>
> static inline bool ublk_need_map_io(const struct ublk_queue *ubq)
> {
> - return !ublk_support_user_copy(ubq);
> + return !ublk_support_user_copy(ubq) && !ublk_support_zero_copy(ubq);
> }
>
> static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> @@ -624,8 +624,11 @@ static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> /*
> * read()/write() is involved in user copy, so request reference
> * has to be grabbed
> + *
> + * for zero copy, request buffer need to be registered to io_uring
> + * buffer table, so reference is needed
> */
> - return ublk_support_user_copy(ubq);
> + return ublk_support_user_copy(ubq) || ublk_support_zero_copy(ubq);
> }
>
> static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
> @@ -2245,6 +2248,9 @@ static struct request *ublk_check_and_get_req(struct kiocb *iocb,
> if (!ubq)
> return ERR_PTR(-EINVAL);
>
> + if (!ublk_support_user_copy(ubq))
> + return ERR_PTR(-EACCES);
This partly overlaps with the existing ublk_need_req_ref() check in
__ublk_check_and_get_req() (although that allows
UBLK_F_SUPPORT_ZERO_COPY too). Can that check be removed now that the
callers explicitly check ublk_support_user_copy() or
ublk_support_zero_copy()?
> +
> if (tag >= ubq->q_depth)
> return ERR_PTR(-EINVAL);
>
> @@ -2783,13 +2789,18 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
> ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
> UBLK_F_URING_CMD_COMP_IN_TASK;
>
> - /* GET_DATA isn't needed any more with USER_COPY */
> - if (ublk_dev_is_user_copy(ub))
> + /* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */
> + if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY))
> ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA;
>
> - /* Zoned storage support requires user copy feature */
> + /*
> + * Zoned storage support requires reuse `ublksrv_io_cmd->addr` for
> + * returning write_append_lba, which is only allowed in case of
> + * user copy or zero copy
Thanks, this comment is much more helpful.
Best,
Caleb
> + */
> if (ublk_dev_is_zoned(ub) &&
> - (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !ublk_dev_is_user_copy(ub))) {
> + (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !(ub->dev_info.flags &
> + (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY)))) {
> ret = -EINVAL;
> goto out_free_dev_number;
> }
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command
2025-04-27 13:49 ` [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command Ming Lei
@ 2025-04-28 16:28 ` Caleb Sander Mateos
2025-04-29 1:02 ` Ming Lei
0 siblings, 1 reply; 13+ messages in thread
From: Caleb Sander Mateos @ 2025-04-28 16:28 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Sun, Apr 27, 2025 at 6:50 AM Ming Lei <ming.lei@redhat.com> wrote:
>
> The simple check of UBLK_IO_FLAG_OWNED_BY_SRV can avoid incorrect
> register/unregister io buffer easily, so check it before calling
> starting to register/un-register io buffer.
>
> Also only allow io buffer register/unregister uring_cmd in case of
> UBLK_F_SUPPORT_ZERO_COPY.
>
> Also mark argument 'ublk_queue *' of ublk_register_io_buf as const.
>
> Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
> drivers/block/ublk_drv.c | 24 ++++++++++++++++++++----
> 1 file changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 0a3a3c64316d..c624d8f653ae 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -201,7 +201,7 @@ struct ublk_params_header {
> static void ublk_stop_dev_unlocked(struct ublk_device *ub);
> static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
> static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> - struct ublk_queue *ubq, int tag, size_t offset);
> + const struct ublk_queue *ubq, int tag, size_t offset);
> static inline unsigned int ublk_req_build_flags(struct request *req);
> static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> int tag);
> @@ -1949,13 +1949,20 @@ static void ublk_io_release(void *priv)
> }
>
> static int ublk_register_io_buf(struct io_uring_cmd *cmd,
> - struct ublk_queue *ubq, unsigned int tag,
> + const struct ublk_queue *ubq, unsigned int tag,
> unsigned int index, unsigned int issue_flags)
> {
> struct ublk_device *ub = cmd->file->private_data;
> + const struct ublk_io *io = &ubq->ios[tag];
> struct request *req;
> int ret;
>
> + if (!ublk_support_zero_copy(ubq))
> + return -EINVAL;
> +
> + if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
> + return -EINVAL;
I would still prefer to see this common UBLK_IO_FLAG_OWNED_BY_SRV
check moved to __ublk_ch_uring_cmd() along with the existing flag
checks. Something like this:
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index a183aa7648c3..79ef2580ddcc 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -2055,6 +2055,11 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
goto out;
}
+ /* only FETCH_REQ is allowed if io is not OWNED_BY_SRV */
+ if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV) &&
+ _IOC_NR(cmd_op) != UBLK_IO_FETCH_REQ)
+ goto out;
+
/*
* ensure that the user issues UBLK_IO_NEED_GET_DATA
* iff the driver have set the UBLK_IO_FLAG_NEED_GET_DATA.
@@ -2080,10 +2085,6 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
break;
case UBLK_IO_COMMIT_AND_FETCH_REQ:
req = blk_mq_tag_to_rq(ub->tag_set.tags[ub_cmd->q_id], tag);
-
- if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
- goto out;
-
if (ublk_need_map_io(ubq)) {
/*
* COMMIT_AND_FETCH_REQ has to provide IO buffer if
@@ -2105,8 +2106,6 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
ublk_commit_completion(ub, ub_cmd);
break;
case UBLK_IO_NEED_GET_DATA:
- if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
- goto out;
ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
req = blk_mq_tag_to_rq(ub->tag_set.tags[ub_cmd->q_id], tag);
ublk_dispatch_req(ubq, req, issue_flags);
> +
> req = __ublk_check_and_get_req(ub, ubq, tag, 0);
> if (!req)
> return -EINVAL;
> @@ -1971,8 +1978,17 @@ static int ublk_register_io_buf(struct io_uring_cmd *cmd,
> }
>
> static int ublk_unregister_io_buf(struct io_uring_cmd *cmd,
> + const struct ublk_queue *ubq, unsigned int tag,
> unsigned int index, unsigned int issue_flags)
> {
> + const struct ublk_io *io = &ubq->ios[tag];
> +
> + if (!ublk_support_zero_copy(ubq))
> + return -EINVAL;
> +
> + if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
> + return -EINVAL;
> +
> return io_buffer_unregister_bvec(cmd, index, issue_flags);
> }
>
> @@ -2076,7 +2092,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
> case UBLK_IO_REGISTER_IO_BUF:
> return ublk_register_io_buf(cmd, ubq, tag, ub_cmd->addr, issue_flags);
> case UBLK_IO_UNREGISTER_IO_BUF:
> - return ublk_unregister_io_buf(cmd, ub_cmd->addr, issue_flags);
> + return ublk_unregister_io_buf(cmd, ubq, tag, ub_cmd->addr, issue_flags);
> case UBLK_IO_FETCH_REQ:
> ret = ublk_fetch(cmd, ubq, io, ub_cmd->addr);
> if (ret)
> @@ -2128,7 +2144,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
> }
>
> static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> - struct ublk_queue *ubq, int tag, size_t offset)
> + const struct ublk_queue *ubq, int tag, size_t offset)
> {
> struct request *req;
>
> --
> 2.47.0
>
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA
2025-04-28 15:51 ` Caleb Sander Mateos
@ 2025-04-29 0:53 ` Ming Lei
0 siblings, 0 replies; 13+ messages in thread
From: Ming Lei @ 2025-04-29 0:53 UTC (permalink / raw)
To: Caleb Sander Mateos; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Mon, Apr 28, 2025 at 08:51:03AM -0700, Caleb Sander Mateos wrote:
> On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > Commit 57e13a2e8cd2 ("selftests: ublk: support user recovery") starts to
> > support UBLK_F_NEED_GET_DATA for covering recovery feature, however the
> > ublk utility implementation isn't done correctly.
> >
> > Fix it by supporting UBLK_F_NEED_GET_DATA correctly.
> >
> > Also add test generic_07 for covering UBLK_F_NEED_GET_DATA.
> >
> > Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
> > Fixes: 57e13a2e8cd2 ("selftests: ublk: support user recovery")
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > ---
> > tools/testing/selftests/ublk/Makefile | 1 +
> > tools/testing/selftests/ublk/kublk.c | 20 ++++++++++------
> > tools/testing/selftests/ublk/kublk.h | 1 +
> > .../testing/selftests/ublk/test_generic_07.sh | 24 +++++++++++++++++++
> > .../testing/selftests/ublk/test_stress_05.sh | 8 +++----
> > 5 files changed, 43 insertions(+), 11 deletions(-)
> > create mode 100755 tools/testing/selftests/ublk/test_generic_07.sh
> >
> > diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile
> > index ec4624a283bc..f34ac0bac696 100644
> > --- a/tools/testing/selftests/ublk/Makefile
> > +++ b/tools/testing/selftests/ublk/Makefile
> > @@ -9,6 +9,7 @@ TEST_PROGS += test_generic_03.sh
> > TEST_PROGS += test_generic_04.sh
> > TEST_PROGS += test_generic_05.sh
> > TEST_PROGS += test_generic_06.sh
> > +TEST_PROGS += test_generic_07.sh
> >
> > TEST_PROGS += test_null_01.sh
> > TEST_PROGS += test_null_02.sh
> > diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c
> > index e57a1486bb48..3afd45d7f989 100644
> > --- a/tools/testing/selftests/ublk/kublk.c
> > +++ b/tools/testing/selftests/ublk/kublk.c
> > @@ -536,12 +536,17 @@ int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag)
> > if (!(io->flags & UBLKSRV_IO_FREE))
> > return 0;
> >
> > - /* we issue because we need either fetching or committing */
> > + /*
> > + * we issue because we need either fetching or committing or
> > + * getting data
> > + */
> > if (!(io->flags &
> > - (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP)))
> > + (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_NEED_GET_DATA)))
> > return 0;
> >
> > - if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
> > + if (io->flags & UBLKSRV_NEED_GET_DATA)
> > + cmd_op = UBLK_U_IO_NEED_GET_DATA;
> > + else if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP)
> > cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ;
> > else if (io->flags & UBLKSRV_NEED_FETCH_RQ)
> > cmd_op = UBLK_U_IO_FETCH_REQ;
> > @@ -658,6 +663,9 @@ static void ublk_handle_cqe(struct io_uring *r,
> > assert(tag < q->q_depth);
> > if (q->tgt_ops->queue_io)
> > q->tgt_ops->queue_io(q, tag);
> > + } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) {
> > + io->flags |= UBLKSRV_NEED_GET_DATA | UBLKSRV_IO_FREE;
> > + ublk_queue_io_cmd(q, io, tag);
> > } else {
> > /*
> > * COMMIT_REQ will be completed immediately since no fetching
> > @@ -1313,7 +1321,7 @@ int main(int argc, char *argv[])
> >
> > opterr = 0;
> > optind = 2;
> > - while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:az",
> > + while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:gaz",
> > longopts, &option_idx)) != -1) {
> > switch (opt) {
> > case 'a':
> > @@ -1351,9 +1359,7 @@ int main(int argc, char *argv[])
> > ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE;
> > break;
> > case 'g':
> > - value = strtol(optarg, NULL, 10);
> > - if (value)
> > - ctx.flags |= UBLK_F_NEED_GET_DATA;
> > + ctx.flags |= UBLK_F_NEED_GET_DATA;
>
> The help text in __cmd_create_help() should be updated accordingly.
Good catch!
>
> > break;
> > case 0:
> > if (!strcmp(longopts[option_idx].name, "debug_mask"))
> > diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h
> > index 918db5cd633f..44ee1e4ac55b 100644
> > --- a/tools/testing/selftests/ublk/kublk.h
> > +++ b/tools/testing/selftests/ublk/kublk.h
> > @@ -115,6 +115,7 @@ struct ublk_io {
> > #define UBLKSRV_NEED_FETCH_RQ (1UL << 0)
> > #define UBLKSRV_NEED_COMMIT_RQ_COMP (1UL << 1)
> > #define UBLKSRV_IO_FREE (1UL << 2)
> > +#define UBLKSRV_NEED_GET_DATA (1UL << 3)
> > unsigned short flags;
> > unsigned short refs; /* used by target code only */
> >
> > diff --git a/tools/testing/selftests/ublk/test_generic_07.sh b/tools/testing/selftests/ublk/test_generic_07.sh
> > new file mode 100755
> > index 000000000000..e3ad36ef7b9a
> > --- /dev/null
> > +++ b/tools/testing/selftests/ublk/test_generic_07.sh
> > @@ -0,0 +1,24 @@
> > +#!/bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
> > +
> > +TID="generic_07"
> > +ERR_CODE=0
> > +
> > +_prep_test "generic" "test UBLK_F_NEED_GET_DATA"
> > +
> > +_create_backfile 0 256M
> > +dev_id=$(_add_ublk_dev -t loop -q 2 -g "${UBLK_BACKFILES[0]}")
> > +_check_add_dev $TID $?
> > +
> > +# run fio over the ublk disk
> > +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
>
> I thought you were planning to add a _have_program fio check?
Indeed, don't know how the check wasn't added, :-(
thanks,
Ming
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 2/3] ublk: decouple zero copy from user copy
2025-04-28 16:01 ` Caleb Sander Mateos
@ 2025-04-29 0:55 ` Ming Lei
2025-04-29 1:36 ` Ming Lei
0 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-29 0:55 UTC (permalink / raw)
To: Caleb Sander Mateos; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Mon, Apr 28, 2025 at 09:01:04AM -0700, Caleb Sander Mateos wrote:
> On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > UBLK_F_USER_COPY and UBLK_F_SUPPORT_ZERO_COPY are two different
> > features, and shouldn't be coupled together.
> >
> > Commit 1f6540e2aabb ("ublk: zc register/unregister bvec") enables
> > user copy automatically in case of UBLK_F_SUPPORT_ZERO_COPY, this way
> > isn't correct.
> >
> > So decouple zero copy from user copy, and use independent helper to
> > check each one.
>
> I agree this makes sense.
>
> >
> > Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > ---
> > drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++------------
> > 1 file changed, 23 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > index 40f971a66d3e..0a3a3c64316d 100644
> > --- a/drivers/block/ublk_drv.c
> > +++ b/drivers/block/ublk_drv.c
> > @@ -205,11 +205,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > static inline unsigned int ublk_req_build_flags(struct request *req);
> > static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> > int tag);
> > -static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
> > -{
> > - return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > -}
> > -
> > static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
> > {
> > return ub->dev_info.flags & UBLK_F_ZONED;
> > @@ -609,14 +604,19 @@ static void ublk_apply_params(struct ublk_device *ub)
> > ublk_dev_param_zoned_apply(ub);
> > }
> >
> > +static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
> > +{
> > + return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
> > +}
> > +
> > static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
> > {
> > - return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > + return ubq->flags & UBLK_F_USER_COPY;
> > }
> >
> > static inline bool ublk_need_map_io(const struct ublk_queue *ubq)
> > {
> > - return !ublk_support_user_copy(ubq);
> > + return !ublk_support_user_copy(ubq) && !ublk_support_zero_copy(ubq);
> > }
> >
> > static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > @@ -624,8 +624,11 @@ static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > /*
> > * read()/write() is involved in user copy, so request reference
> > * has to be grabbed
> > + *
> > + * for zero copy, request buffer need to be registered to io_uring
> > + * buffer table, so reference is needed
> > */
> > - return ublk_support_user_copy(ubq);
> > + return ublk_support_user_copy(ubq) || ublk_support_zero_copy(ubq);
> > }
> >
> > static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
> > @@ -2245,6 +2248,9 @@ static struct request *ublk_check_and_get_req(struct kiocb *iocb,
> > if (!ubq)
> > return ERR_PTR(-EINVAL);
> >
> > + if (!ublk_support_user_copy(ubq))
> > + return ERR_PTR(-EACCES);
>
> This partly overlaps with the existing ublk_need_req_ref() check in
> __ublk_check_and_get_req() (although that allows
> UBLK_F_SUPPORT_ZERO_COPY too). Can that check be removed now that the
> callers explicitly check ublk_support_user_copy() or
> ublk_support_zero_copy()?
Yeah, it can be removed.
Thanks,
Ming
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command
2025-04-28 16:28 ` Caleb Sander Mateos
@ 2025-04-29 1:02 ` Ming Lei
2025-04-29 1:03 ` Caleb Sander Mateos
0 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-29 1:02 UTC (permalink / raw)
To: Caleb Sander Mateos; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Mon, Apr 28, 2025 at 09:28:07AM -0700, Caleb Sander Mateos wrote:
> On Sun, Apr 27, 2025 at 6:50 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > The simple check of UBLK_IO_FLAG_OWNED_BY_SRV can avoid incorrect
> > register/unregister io buffer easily, so check it before calling
> > starting to register/un-register io buffer.
> >
> > Also only allow io buffer register/unregister uring_cmd in case of
> > UBLK_F_SUPPORT_ZERO_COPY.
> >
> > Also mark argument 'ublk_queue *' of ublk_register_io_buf as const.
> >
> > Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > ---
> > drivers/block/ublk_drv.c | 24 ++++++++++++++++++++----
> > 1 file changed, 20 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > index 0a3a3c64316d..c624d8f653ae 100644
> > --- a/drivers/block/ublk_drv.c
> > +++ b/drivers/block/ublk_drv.c
> > @@ -201,7 +201,7 @@ struct ublk_params_header {
> > static void ublk_stop_dev_unlocked(struct ublk_device *ub);
> > static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
> > static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > - struct ublk_queue *ubq, int tag, size_t offset);
> > + const struct ublk_queue *ubq, int tag, size_t offset);
> > static inline unsigned int ublk_req_build_flags(struct request *req);
> > static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> > int tag);
> > @@ -1949,13 +1949,20 @@ static void ublk_io_release(void *priv)
> > }
> >
> > static int ublk_register_io_buf(struct io_uring_cmd *cmd,
> > - struct ublk_queue *ubq, unsigned int tag,
> > + const struct ublk_queue *ubq, unsigned int tag,
> > unsigned int index, unsigned int issue_flags)
> > {
> > struct ublk_device *ub = cmd->file->private_data;
> > + const struct ublk_io *io = &ubq->ios[tag];
> > struct request *req;
> > int ret;
> >
> > + if (!ublk_support_zero_copy(ubq))
> > + return -EINVAL;
> > +
> > + if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
> > + return -EINVAL;
>
> I would still prefer to see this common UBLK_IO_FLAG_OWNED_BY_SRV
> check moved to __ublk_ch_uring_cmd() along with the existing flag
> checks. Something like this:
This way mixes bug fix with cleanup.
We are close to v6.15-rc5, and bug fix should keep simple for minimizing
regression.
But it is fine to make it one cleanup aiming at v6.16.
thanks,
Ming
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command
2025-04-29 1:02 ` Ming Lei
@ 2025-04-29 1:03 ` Caleb Sander Mateos
0 siblings, 0 replies; 13+ messages in thread
From: Caleb Sander Mateos @ 2025-04-29 1:03 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Mon, Apr 28, 2025 at 6:02 PM Ming Lei <ming.lei@redhat.com> wrote:
>
> On Mon, Apr 28, 2025 at 09:28:07AM -0700, Caleb Sander Mateos wrote:
> > On Sun, Apr 27, 2025 at 6:50 AM Ming Lei <ming.lei@redhat.com> wrote:
> > >
> > > The simple check of UBLK_IO_FLAG_OWNED_BY_SRV can avoid incorrect
> > > register/unregister io buffer easily, so check it before calling
> > > starting to register/un-register io buffer.
> > >
> > > Also only allow io buffer register/unregister uring_cmd in case of
> > > UBLK_F_SUPPORT_ZERO_COPY.
> > >
> > > Also mark argument 'ublk_queue *' of ublk_register_io_buf as const.
> > >
> > > Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> > > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > > ---
> > > drivers/block/ublk_drv.c | 24 ++++++++++++++++++++----
> > > 1 file changed, 20 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > > index 0a3a3c64316d..c624d8f653ae 100644
> > > --- a/drivers/block/ublk_drv.c
> > > +++ b/drivers/block/ublk_drv.c
> > > @@ -201,7 +201,7 @@ struct ublk_params_header {
> > > static void ublk_stop_dev_unlocked(struct ublk_device *ub);
> > > static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
> > > static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > > - struct ublk_queue *ubq, int tag, size_t offset);
> > > + const struct ublk_queue *ubq, int tag, size_t offset);
> > > static inline unsigned int ublk_req_build_flags(struct request *req);
> > > static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> > > int tag);
> > > @@ -1949,13 +1949,20 @@ static void ublk_io_release(void *priv)
> > > }
> > >
> > > static int ublk_register_io_buf(struct io_uring_cmd *cmd,
> > > - struct ublk_queue *ubq, unsigned int tag,
> > > + const struct ublk_queue *ubq, unsigned int tag,
> > > unsigned int index, unsigned int issue_flags)
> > > {
> > > struct ublk_device *ub = cmd->file->private_data;
> > > + const struct ublk_io *io = &ubq->ios[tag];
> > > struct request *req;
> > > int ret;
> > >
> > > + if (!ublk_support_zero_copy(ubq))
> > > + return -EINVAL;
> > > +
> > > + if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
> > > + return -EINVAL;
> >
> > I would still prefer to see this common UBLK_IO_FLAG_OWNED_BY_SRV
> > check moved to __ublk_ch_uring_cmd() along with the existing flag
> > checks. Something like this:
>
> This way mixes bug fix with cleanup.
>
> We are close to v6.15-rc5, and bug fix should keep simple for minimizing
> regression.
>
> But it is fine to make it one cleanup aiming at v6.16.
Okay, I can send out this cleanup for 6.16. In that case,
Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 2/3] ublk: decouple zero copy from user copy
2025-04-29 0:55 ` Ming Lei
@ 2025-04-29 1:36 ` Ming Lei
2025-04-29 1:38 ` Caleb Sander Mateos
0 siblings, 1 reply; 13+ messages in thread
From: Ming Lei @ 2025-04-29 1:36 UTC (permalink / raw)
To: Caleb Sander Mateos; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Tue, Apr 29, 2025 at 08:55:48AM +0800, Ming Lei wrote:
> On Mon, Apr 28, 2025 at 09:01:04AM -0700, Caleb Sander Mateos wrote:
> > On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
> > >
> > > UBLK_F_USER_COPY and UBLK_F_SUPPORT_ZERO_COPY are two different
> > > features, and shouldn't be coupled together.
> > >
> > > Commit 1f6540e2aabb ("ublk: zc register/unregister bvec") enables
> > > user copy automatically in case of UBLK_F_SUPPORT_ZERO_COPY, this way
> > > isn't correct.
> > >
> > > So decouple zero copy from user copy, and use independent helper to
> > > check each one.
> >
> > I agree this makes sense.
> >
> > >
> > > Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> > > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > > ---
> > > drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++------------
> > > 1 file changed, 23 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > > index 40f971a66d3e..0a3a3c64316d 100644
> > > --- a/drivers/block/ublk_drv.c
> > > +++ b/drivers/block/ublk_drv.c
> > > @@ -205,11 +205,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > > static inline unsigned int ublk_req_build_flags(struct request *req);
> > > static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> > > int tag);
> > > -static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
> > > -{
> > > - return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > > -}
> > > -
> > > static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
> > > {
> > > return ub->dev_info.flags & UBLK_F_ZONED;
> > > @@ -609,14 +604,19 @@ static void ublk_apply_params(struct ublk_device *ub)
> > > ublk_dev_param_zoned_apply(ub);
> > > }
> > >
> > > +static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
> > > +{
> > > + return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
> > > +}
> > > +
> > > static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
> > > {
> > > - return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > > + return ubq->flags & UBLK_F_USER_COPY;
> > > }
> > >
> > > static inline bool ublk_need_map_io(const struct ublk_queue *ubq)
> > > {
> > > - return !ublk_support_user_copy(ubq);
> > > + return !ublk_support_user_copy(ubq) && !ublk_support_zero_copy(ubq);
> > > }
> > >
> > > static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > > @@ -624,8 +624,11 @@ static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > > /*
> > > * read()/write() is involved in user copy, so request reference
> > > * has to be grabbed
> > > + *
> > > + * for zero copy, request buffer need to be registered to io_uring
> > > + * buffer table, so reference is needed
> > > */
> > > - return ublk_support_user_copy(ubq);
> > > + return ublk_support_user_copy(ubq) || ublk_support_zero_copy(ubq);
> > > }
> > >
> > > static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
> > > @@ -2245,6 +2248,9 @@ static struct request *ublk_check_and_get_req(struct kiocb *iocb,
> > > if (!ubq)
> > > return ERR_PTR(-EINVAL);
> > >
> > > + if (!ublk_support_user_copy(ubq))
> > > + return ERR_PTR(-EACCES);
> >
> > This partly overlaps with the existing ublk_need_req_ref() check in
> > __ublk_check_and_get_req() (although that allows
> > UBLK_F_SUPPORT_ZERO_COPY too). Can that check be removed now that the
> > callers explicitly check ublk_support_user_copy() or
> > ublk_support_zero_copy()?
>
> Yeah, it can be removed.
Actually the removal can only be done after the 3rd patch is applied with
zero copy check is added.
Thanks,
Ming
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6.15 2/3] ublk: decouple zero copy from user copy
2025-04-29 1:36 ` Ming Lei
@ 2025-04-29 1:38 ` Caleb Sander Mateos
0 siblings, 0 replies; 13+ messages in thread
From: Caleb Sander Mateos @ 2025-04-29 1:38 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, linux-block, Uday Shankar, Keith Busch
On Mon, Apr 28, 2025 at 6:36 PM Ming Lei <ming.lei@redhat.com> wrote:
>
> On Tue, Apr 29, 2025 at 08:55:48AM +0800, Ming Lei wrote:
> > On Mon, Apr 28, 2025 at 09:01:04AM -0700, Caleb Sander Mateos wrote:
> > > On Sun, Apr 27, 2025 at 6:49 AM Ming Lei <ming.lei@redhat.com> wrote:
> > > >
> > > > UBLK_F_USER_COPY and UBLK_F_SUPPORT_ZERO_COPY are two different
> > > > features, and shouldn't be coupled together.
> > > >
> > > > Commit 1f6540e2aabb ("ublk: zc register/unregister bvec") enables
> > > > user copy automatically in case of UBLK_F_SUPPORT_ZERO_COPY, this way
> > > > isn't correct.
> > > >
> > > > So decouple zero copy from user copy, and use independent helper to
> > > > check each one.
> > >
> > > I agree this makes sense.
> > >
> > > >
> > > > Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec")
> > > > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > > > ---
> > > > drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++------------
> > > > 1 file changed, 23 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > > > index 40f971a66d3e..0a3a3c64316d 100644
> > > > --- a/drivers/block/ublk_drv.c
> > > > +++ b/drivers/block/ublk_drv.c
> > > > @@ -205,11 +205,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > > > static inline unsigned int ublk_req_build_flags(struct request *req);
> > > > static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
> > > > int tag);
> > > > -static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
> > > > -{
> > > > - return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > > > -}
> > > > -
> > > > static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
> > > > {
> > > > return ub->dev_info.flags & UBLK_F_ZONED;
> > > > @@ -609,14 +604,19 @@ static void ublk_apply_params(struct ublk_device *ub)
> > > > ublk_dev_param_zoned_apply(ub);
> > > > }
> > > >
> > > > +static inline bool ublk_support_zero_copy(const struct ublk_queue *ubq)
> > > > +{
> > > > + return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY;
> > > > +}
> > > > +
> > > > static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
> > > > {
> > > > - return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
> > > > + return ubq->flags & UBLK_F_USER_COPY;
> > > > }
> > > >
> > > > static inline bool ublk_need_map_io(const struct ublk_queue *ubq)
> > > > {
> > > > - return !ublk_support_user_copy(ubq);
> > > > + return !ublk_support_user_copy(ubq) && !ublk_support_zero_copy(ubq);
> > > > }
> > > >
> > > > static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > > > @@ -624,8 +624,11 @@ static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
> > > > /*
> > > > * read()/write() is involved in user copy, so request reference
> > > > * has to be grabbed
> > > > + *
> > > > + * for zero copy, request buffer need to be registered to io_uring
> > > > + * buffer table, so reference is needed
> > > > */
> > > > - return ublk_support_user_copy(ubq);
> > > > + return ublk_support_user_copy(ubq) || ublk_support_zero_copy(ubq);
> > > > }
> > > >
> > > > static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
> > > > @@ -2245,6 +2248,9 @@ static struct request *ublk_check_and_get_req(struct kiocb *iocb,
> > > > if (!ubq)
> > > > return ERR_PTR(-EINVAL);
> > > >
> > > > + if (!ublk_support_user_copy(ubq))
> > > > + return ERR_PTR(-EACCES);
> > >
> > > This partly overlaps with the existing ublk_need_req_ref() check in
> > > __ublk_check_and_get_req() (although that allows
> > > UBLK_F_SUPPORT_ZERO_COPY too). Can that check be removed now that the
> > > callers explicitly check ublk_support_user_copy() or
> > > ublk_support_zero_copy()?
> >
> > Yeah, it can be removed.
>
> Actually the removal can only be done after the 3rd patch is applied with
> zero copy check is added.
Right, I just meant it can be removed in this series.
Thanks,
Caleb
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-04-29 1:39 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-27 13:49 [PATCH v6.15 0/3] ublk: one selftest fix and two zero copy fixes Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 1/3] selftests: ublk: fix UBLK_F_NEED_GET_DATA Ming Lei
2025-04-28 15:51 ` Caleb Sander Mateos
2025-04-29 0:53 ` Ming Lei
2025-04-27 13:49 ` [PATCH v6.15 2/3] ublk: decouple zero copy from user copy Ming Lei
2025-04-28 16:01 ` Caleb Sander Mateos
2025-04-29 0:55 ` Ming Lei
2025-04-29 1:36 ` Ming Lei
2025-04-29 1:38 ` Caleb Sander Mateos
2025-04-27 13:49 ` [PATCH v6.15 3/3] ublk: enhance check for register/unregister io buffer command Ming Lei
2025-04-28 16:28 ` Caleb Sander Mateos
2025-04-29 1:02 ` Ming Lei
2025-04-29 1:03 ` Caleb Sander Mateos
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox