Skip to content

Commit 8cb9b97

Browse files
Ming Leiaxboe
authored andcommitted
selftests: ublk: enable zero copy for null target
Enable zero copy for null target so that we can evaluate performance from zero copy or not. Also this should be the simplest ublk zero copy implementation, which can be served as zc example. Add test for covering 'add -t null -z'. Signed-off-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 8842b72 commit 8cb9b97

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

tools/testing/selftests/ublk/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ LDLIBS += -lpthread -lm -luring
66
TEST_PROGS := test_generic_01.sh
77

88
TEST_PROGS += test_null_01.sh
9+
TEST_PROGS += test_null_02.sh
910
TEST_PROGS += test_loop_01.sh
1011
TEST_PROGS += test_loop_02.sh
1112
TEST_PROGS += test_loop_03.sh

tools/testing/selftests/ublk/kublk.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ static inline unsigned int user_data_to_tgt_data(__u64 user_data)
198198
return (user_data >> 24) & 0xffff;
199199
}
200200

201+
static inline unsigned short ublk_cmd_op_nr(unsigned int op)
202+
{
203+
return _IOC_NR(op);
204+
}
205+
201206
static inline void ublk_err(const char *fmt, ...)
202207
{
203208
va_list ap;

tools/testing/selftests/ublk/null.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
#include "kublk.h"
44

5+
#ifndef IORING_NOP_INJECT_RESULT
6+
#define IORING_NOP_INJECT_RESULT (1U << 0)
7+
#endif
8+
9+
#ifndef IORING_NOP_FIXED_BUFFER
10+
#define IORING_NOP_FIXED_BUFFER (1U << 3)
11+
#endif
12+
513
static int ublk_null_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
614
{
715
const struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
@@ -20,19 +28,79 @@ static int ublk_null_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
2028
},
2129
};
2230

31+
if (info->flags & UBLK_F_SUPPORT_ZERO_COPY)
32+
dev->tgt.sq_depth = dev->tgt.cq_depth = 2 * info->queue_depth;
2333
return 0;
2434
}
2535

36+
static int null_queue_zc_io(struct ublk_queue *q, int tag)
37+
{
38+
const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
39+
unsigned ublk_op = ublksrv_get_op(iod);
40+
struct io_uring_sqe *sqe[3];
41+
42+
ublk_queue_alloc_sqes(q, sqe, 3);
43+
44+
io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, tag);
45+
sqe[0]->user_data = build_user_data(tag,
46+
ublk_cmd_op_nr(sqe[0]->cmd_op), 0, 1);
47+
sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK;
48+
49+
io_uring_prep_nop(sqe[1]);
50+
sqe[1]->buf_index = tag;
51+
sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK;
52+
sqe[1]->rw_flags = IORING_NOP_FIXED_BUFFER | IORING_NOP_INJECT_RESULT;
53+
sqe[1]->len = iod->nr_sectors << 9; /* injected result */
54+
sqe[1]->user_data = build_user_data(tag, ublk_op, 0, 1);
55+
56+
io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, tag);
57+
sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, 1);
58+
59+
// buf register is marked as IOSQE_CQE_SKIP_SUCCESS
60+
return 2;
61+
}
62+
63+
static void ublk_null_io_done(struct ublk_queue *q, int tag,
64+
const struct io_uring_cqe *cqe)
65+
{
66+
unsigned op = user_data_to_op(cqe->user_data);
67+
struct ublk_io *io = ublk_get_io(q, tag);
68+
69+
if (cqe->res < 0 || op != ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) {
70+
if (!io->result)
71+
io->result = cqe->res;
72+
if (cqe->res < 0)
73+
ublk_err("%s: io failed op %x user_data %lx\n",
74+
__func__, op, cqe->user_data);
75+
}
76+
77+
/* buffer register op is IOSQE_CQE_SKIP_SUCCESS */
78+
if (op == ublk_cmd_op_nr(UBLK_U_IO_REGISTER_IO_BUF))
79+
io->tgt_ios += 1;
80+
81+
if (ublk_completed_tgt_io(q, tag))
82+
ublk_complete_io(q, tag, io->result);
83+
}
84+
2685
static int ublk_null_queue_io(struct ublk_queue *q, int tag)
2786
{
2887
const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
88+
int zc = ublk_queue_use_zc(q);
89+
int queued;
90+
91+
if (!zc) {
92+
ublk_complete_io(q, tag, iod->nr_sectors << 9);
93+
return 0;
94+
}
2995

30-
ublk_complete_io(q, tag, iod->nr_sectors << 9);
96+
queued = null_queue_zc_io(q, tag);
97+
ublk_queued_tgt_io(q, tag, queued);
3198
return 0;
3299
}
33100

34101
const struct ublk_tgt_ops null_tgt_ops = {
35102
.name = "null",
36103
.init_tgt = ublk_null_tgt_init,
37104
.queue_io = ublk_null_queue_io,
105+
.tgt_io_done = ublk_null_io_done,
38106
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
5+
6+
TID="null_02"
7+
ERR_CODE=0
8+
9+
_prep_test "null" "basic IO test with zero copy"
10+
11+
dev_id=$(_add_ublk_dev -t null -z)
12+
_check_add_dev $TID $?
13+
14+
# run fio over the two disks
15+
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1
16+
ERR_CODE=$?
17+
18+
_cleanup_test "null"
19+
20+
_show_result $TID $ERR_CODE

0 commit comments

Comments
 (0)