mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-01 06:39:05 +00:00
selftests: ublk: add ublk zero copy test
Enable zero copy on file backed target, meantime add one fio test for covering write verify, another test for mkfs/mount/umount. Signed-off-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20250228161919.2869102-4-ming.lei@redhat.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
5d95bfb535
commit
bedc9cbc5f
@ -6,6 +6,8 @@ LDLIBS += -lpthread -lm -luring
|
|||||||
TEST_PROGS := test_null_01.sh
|
TEST_PROGS := test_null_01.sh
|
||||||
TEST_PROGS += test_loop_01.sh
|
TEST_PROGS += test_loop_01.sh
|
||||||
TEST_PROGS += test_loop_02.sh
|
TEST_PROGS += test_loop_02.sh
|
||||||
|
TEST_PROGS += test_loop_03.sh
|
||||||
|
TEST_PROGS += test_loop_04.sh
|
||||||
|
|
||||||
TEST_GEN_PROGS_EXTENDED = kublk
|
TEST_GEN_PROGS_EXTENDED = kublk
|
||||||
|
|
||||||
|
@ -54,48 +54,94 @@ static int backing_file_tgt_init(struct ublk_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum io_uring_op ublk_to_uring_op(const struct ublksrv_io_desc *iod, int zc)
|
||||||
|
{
|
||||||
|
unsigned ublk_op = ublksrv_get_op(iod);
|
||||||
|
|
||||||
|
if (ublk_op == UBLK_IO_OP_READ)
|
||||||
|
return zc ? IORING_OP_READ_FIXED : IORING_OP_READ;
|
||||||
|
else if (ublk_op == UBLK_IO_OP_WRITE)
|
||||||
|
return zc ? IORING_OP_WRITE_FIXED : IORING_OP_WRITE;
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loop_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_desc *iod, int tag)
|
||||||
|
{
|
||||||
|
int zc = ublk_queue_use_zc(q);
|
||||||
|
enum io_uring_op op = ublk_to_uring_op(iod, zc);
|
||||||
|
struct io_uring_sqe *reg;
|
||||||
|
struct io_uring_sqe *rw;
|
||||||
|
struct io_uring_sqe *ureg;
|
||||||
|
|
||||||
|
if (!zc) {
|
||||||
|
rw = ublk_queue_alloc_sqe(q);
|
||||||
|
if (!rw)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
io_uring_prep_rw(op, rw, 1 /*fds[1]*/,
|
||||||
|
(void *)iod->addr,
|
||||||
|
iod->nr_sectors << 9,
|
||||||
|
iod->start_sector << 9);
|
||||||
|
io_uring_sqe_set_flags(rw, IOSQE_FIXED_FILE);
|
||||||
|
q->io_inflight++;
|
||||||
|
/* bit63 marks us as tgt io */
|
||||||
|
rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_NORMAL, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ublk_queue_alloc_sqe3(q, ®, &rw, &ureg);
|
||||||
|
|
||||||
|
io_uring_prep_buf_register(reg, 0, tag, q->q_id, tag);
|
||||||
|
reg->user_data = build_user_data(tag, 0xfe, 1, 1);
|
||||||
|
reg->flags |= IOSQE_CQE_SKIP_SUCCESS;
|
||||||
|
reg->flags |= IOSQE_IO_LINK;
|
||||||
|
|
||||||
|
io_uring_prep_rw(op, rw, 1 /*fds[1]*/, 0,
|
||||||
|
iod->nr_sectors << 9,
|
||||||
|
iod->start_sector << 9);
|
||||||
|
rw->buf_index = tag;
|
||||||
|
rw->flags |= IOSQE_FIXED_FILE;
|
||||||
|
rw->flags |= IOSQE_IO_LINK;
|
||||||
|
rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_ZC_OP, 1);
|
||||||
|
q->io_inflight++;
|
||||||
|
|
||||||
|
io_uring_prep_buf_unregister(ureg, 0, tag, q->q_id, tag);
|
||||||
|
ureg->user_data = build_user_data(tag, 0xff, UBLK_IO_TGT_ZC_BUF, 1);
|
||||||
|
q->io_inflight++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int loop_queue_tgt_io(struct ublk_queue *q, int tag)
|
static int loop_queue_tgt_io(struct ublk_queue *q, int tag)
|
||||||
{
|
{
|
||||||
const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
|
const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
|
||||||
struct io_uring_sqe *sqe = ublk_queue_alloc_sqe(q);
|
|
||||||
unsigned ublk_op = ublksrv_get_op(iod);
|
unsigned ublk_op = ublksrv_get_op(iod);
|
||||||
|
struct io_uring_sqe *sqe;
|
||||||
if (!sqe)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
switch (ublk_op) {
|
switch (ublk_op) {
|
||||||
case UBLK_IO_OP_FLUSH:
|
case UBLK_IO_OP_FLUSH:
|
||||||
|
sqe = ublk_queue_alloc_sqe(q);
|
||||||
|
if (!sqe)
|
||||||
|
return -ENOMEM;
|
||||||
io_uring_prep_sync_file_range(sqe, 1 /*fds[1]*/,
|
io_uring_prep_sync_file_range(sqe, 1 /*fds[1]*/,
|
||||||
iod->nr_sectors << 9,
|
iod->nr_sectors << 9,
|
||||||
iod->start_sector << 9,
|
iod->start_sector << 9,
|
||||||
IORING_FSYNC_DATASYNC);
|
IORING_FSYNC_DATASYNC);
|
||||||
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
||||||
|
q->io_inflight++;
|
||||||
|
sqe->user_data = build_user_data(tag, ublk_op, UBLK_IO_TGT_NORMAL, 1);
|
||||||
break;
|
break;
|
||||||
case UBLK_IO_OP_WRITE_ZEROES:
|
case UBLK_IO_OP_WRITE_ZEROES:
|
||||||
case UBLK_IO_OP_DISCARD:
|
case UBLK_IO_OP_DISCARD:
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
case UBLK_IO_OP_READ:
|
case UBLK_IO_OP_READ:
|
||||||
io_uring_prep_read(sqe, 1 /*fds[1]*/,
|
|
||||||
(void *)iod->addr,
|
|
||||||
iod->nr_sectors << 9,
|
|
||||||
iod->start_sector << 9);
|
|
||||||
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
|
||||||
break;
|
|
||||||
case UBLK_IO_OP_WRITE:
|
case UBLK_IO_OP_WRITE:
|
||||||
io_uring_prep_write(sqe, 1 /*fds[1]*/,
|
loop_queue_tgt_rw_io(q, iod, tag);
|
||||||
(void *)iod->addr,
|
|
||||||
iod->nr_sectors << 9,
|
|
||||||
iod->start_sector << 9);
|
|
||||||
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
q->io_inflight++;
|
|
||||||
/* bit63 marks us as tgt io */
|
|
||||||
sqe->user_data = build_user_data(tag, ublk_op, 0, 1);
|
|
||||||
|
|
||||||
ublk_dbg(UBLK_DBG_IO, "%s: tag %d ublk io %x %llx %u\n", __func__, tag,
|
ublk_dbg(UBLK_DBG_IO, "%s: tag %d ublk io %x %llx %u\n", __func__, tag,
|
||||||
iod->op_flags, iod->start_sector, iod->nr_sectors << 9);
|
iod->op_flags, iod->start_sector, iod->nr_sectors << 9);
|
||||||
return 1;
|
return 1;
|
||||||
@ -115,9 +161,22 @@ static void ublk_loop_io_done(struct ublk_queue *q, int tag,
|
|||||||
const struct io_uring_cqe *cqe)
|
const struct io_uring_cqe *cqe)
|
||||||
{
|
{
|
||||||
int cqe_tag = user_data_to_tag(cqe->user_data);
|
int cqe_tag = user_data_to_tag(cqe->user_data);
|
||||||
|
unsigned tgt_data = user_data_to_tgt_data(cqe->user_data);
|
||||||
|
int res = cqe->res;
|
||||||
|
|
||||||
|
if (res < 0 || tgt_data == UBLK_IO_TGT_NORMAL)
|
||||||
|
goto complete;
|
||||||
|
|
||||||
|
if (tgt_data == UBLK_IO_TGT_ZC_OP) {
|
||||||
|
ublk_set_io_res(q, tag, cqe->res);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
assert(tgt_data == UBLK_IO_TGT_ZC_BUF);
|
||||||
|
res = ublk_get_io_res(q, tag);
|
||||||
|
complete:
|
||||||
assert(tag == cqe_tag);
|
assert(tag == cqe_tag);
|
||||||
ublk_complete_io(q, tag, cqe->res);
|
ublk_complete_io(q, tag, res);
|
||||||
|
exit:
|
||||||
q->io_inflight--;
|
q->io_inflight--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +185,7 @@ static int ublk_loop_tgt_init(struct ublk_dev *dev)
|
|||||||
unsigned long long bytes;
|
unsigned long long bytes;
|
||||||
int ret;
|
int ret;
|
||||||
struct ublk_params p = {
|
struct ublk_params p = {
|
||||||
.types = UBLK_PARAM_TYPE_BASIC,
|
.types = UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN,
|
||||||
.basic = {
|
.basic = {
|
||||||
.logical_bs_shift = 9,
|
.logical_bs_shift = 9,
|
||||||
.physical_bs_shift = 12,
|
.physical_bs_shift = 12,
|
||||||
@ -134,6 +193,9 @@ static int ublk_loop_tgt_init(struct ublk_dev *dev)
|
|||||||
.io_min_shift = 9,
|
.io_min_shift = 9,
|
||||||
.max_sectors = dev->dev_info.max_io_buf_bytes >> 9,
|
.max_sectors = dev->dev_info.max_io_buf_bytes >> 9,
|
||||||
},
|
},
|
||||||
|
.dma = {
|
||||||
|
.alignment = 511,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(dev->tgt.nr_backing_files == 1);
|
assert(dev->tgt.nr_backing_files == 1);
|
||||||
|
@ -282,6 +282,8 @@ static void ublk_queue_deinit(struct ublk_queue *q)
|
|||||||
int i;
|
int i;
|
||||||
int nr_ios = q->q_depth;
|
int nr_ios = q->q_depth;
|
||||||
|
|
||||||
|
io_uring_unregister_buffers(&q->ring);
|
||||||
|
|
||||||
io_uring_unregister_ring_fd(&q->ring);
|
io_uring_unregister_ring_fd(&q->ring);
|
||||||
|
|
||||||
if (q->ring.ring_fd > 0) {
|
if (q->ring.ring_fd > 0) {
|
||||||
@ -312,6 +314,11 @@ static int ublk_queue_init(struct ublk_queue *q)
|
|||||||
q->cmd_inflight = 0;
|
q->cmd_inflight = 0;
|
||||||
q->tid = gettid();
|
q->tid = gettid();
|
||||||
|
|
||||||
|
if (dev->dev_info.flags & UBLK_F_SUPPORT_ZERO_COPY) {
|
||||||
|
q->state |= UBLKSRV_NO_BUF;
|
||||||
|
q->state |= UBLKSRV_ZC;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_buf_size = ublk_queue_cmd_buf_sz(q);
|
cmd_buf_size = ublk_queue_cmd_buf_sz(q);
|
||||||
off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz();
|
off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz();
|
||||||
q->io_cmd_buf = (char *)mmap(0, cmd_buf_size, PROT_READ,
|
q->io_cmd_buf = (char *)mmap(0, cmd_buf_size, PROT_READ,
|
||||||
@ -346,6 +353,15 @@ static int ublk_queue_init(struct ublk_queue *q)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->dev_info.flags & UBLK_F_SUPPORT_ZERO_COPY) {
|
||||||
|
ret = io_uring_register_buffers_sparse(&q->ring, q->q_depth);
|
||||||
|
if (ret) {
|
||||||
|
ublk_err("ublk dev %d queue %d register spare buffers failed %d",
|
||||||
|
dev->dev_info.dev_id, q->q_id, ret);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
io_uring_register_ring_fd(&q->ring);
|
io_uring_register_ring_fd(&q->ring);
|
||||||
|
|
||||||
ret = io_uring_register_files(&q->ring, dev->fds, dev->nr_fds);
|
ret = io_uring_register_files(&q->ring, dev->fds, dev->nr_fds);
|
||||||
@ -502,9 +518,10 @@ static void ublk_handle_cqe(struct io_uring *r,
|
|||||||
ublk_err("%s: res %d userdata %llx queue state %x\n", __func__,
|
ublk_err("%s: res %d userdata %llx queue state %x\n", __func__,
|
||||||
cqe->res, cqe->user_data, q->state);
|
cqe->res, cqe->user_data, q->state);
|
||||||
|
|
||||||
ublk_dbg(UBLK_DBG_IO_CMD, "%s: res %d (qid %d tag %u cmd_op %u target %d) stopping %d\n",
|
ublk_dbg(UBLK_DBG_IO_CMD, "%s: res %d (qid %d tag %u cmd_op %u target %d/%d) stopping %d\n",
|
||||||
__func__, cqe->res, q->q_id, tag, cmd_op,
|
__func__, cqe->res, q->q_id, tag, cmd_op,
|
||||||
is_target_io(cqe->user_data),
|
is_target_io(cqe->user_data),
|
||||||
|
user_data_to_tgt_data(cqe->user_data),
|
||||||
(q->state & UBLKSRV_QUEUE_STOPPING));
|
(q->state & UBLKSRV_QUEUE_STOPPING));
|
||||||
|
|
||||||
/* Don't retrieve io in case of target io */
|
/* Don't retrieve io in case of target io */
|
||||||
@ -1022,6 +1039,7 @@ int main(int argc, char *argv[])
|
|||||||
{ "depth", 1, NULL, 'd' },
|
{ "depth", 1, NULL, 'd' },
|
||||||
{ "debug_mask", 1, NULL, 0 },
|
{ "debug_mask", 1, NULL, 0 },
|
||||||
{ "quiet", 0, NULL, 0 },
|
{ "quiet", 0, NULL, 0 },
|
||||||
|
{ "zero_copy", 1, NULL, 'z' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int option_idx, opt;
|
int option_idx, opt;
|
||||||
@ -1038,7 +1056,7 @@ int main(int argc, char *argv[])
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
optind = 2;
|
optind = 2;
|
||||||
while ((opt = getopt_long(argc, argv, "t:n:d:q:a",
|
while ((opt = getopt_long(argc, argv, "t:n:d:q:a:z",
|
||||||
longopts, &option_idx)) != -1) {
|
longopts, &option_idx)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -1057,6 +1075,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'd':
|
case 'd':
|
||||||
ctx.queue_depth = strtol(optarg, NULL, 10);
|
ctx.queue_depth = strtol(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
|
||||||
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
if (!strcmp(longopts[option_idx].name, "debug_mask"))
|
if (!strcmp(longopts[option_idx].name, "debug_mask"))
|
||||||
ublk_dbg_mask = strtol(optarg, NULL, 16);
|
ublk_dbg_mask = strtol(optarg, NULL, 16);
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
#define UBLK_MAX_QUEUES 4
|
#define UBLK_MAX_QUEUES 4
|
||||||
#define UBLK_QUEUE_DEPTH 128
|
#define UBLK_QUEUE_DEPTH 128
|
||||||
|
|
||||||
|
#define UBLK_IO_TGT_NORMAL 0
|
||||||
|
#define UBLK_IO_TGT_ZC_BUF 1
|
||||||
|
#define UBLK_IO_TGT_ZC_OP 2
|
||||||
|
|
||||||
#define UBLK_DBG_DEV (1U << 0)
|
#define UBLK_DBG_DEV (1U << 0)
|
||||||
#define UBLK_DBG_QUEUE (1U << 1)
|
#define UBLK_DBG_QUEUE (1U << 1)
|
||||||
#define UBLK_DBG_IO_CMD (1U << 2)
|
#define UBLK_DBG_IO_CMD (1U << 2)
|
||||||
@ -124,6 +128,7 @@ struct ublk_queue {
|
|||||||
#define UBLKSRV_QUEUE_STOPPING (1U << 0)
|
#define UBLKSRV_QUEUE_STOPPING (1U << 0)
|
||||||
#define UBLKSRV_QUEUE_IDLE (1U << 1)
|
#define UBLKSRV_QUEUE_IDLE (1U << 1)
|
||||||
#define UBLKSRV_NO_BUF (1U << 2)
|
#define UBLKSRV_NO_BUF (1U << 2)
|
||||||
|
#define UBLKSRV_ZC (1U << 3)
|
||||||
unsigned state;
|
unsigned state;
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
@ -180,6 +185,11 @@ static inline unsigned int user_data_to_op(__u64 user_data)
|
|||||||
return (user_data >> 16) & 0xff;
|
return (user_data >> 16) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned int user_data_to_tgt_data(__u64 user_data)
|
||||||
|
{
|
||||||
|
return (user_data >> 24) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void ublk_err(const char *fmt, ...)
|
static inline void ublk_err(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -217,11 +227,66 @@ static inline struct io_uring_sqe *ublk_queue_alloc_sqe(struct ublk_queue *q)
|
|||||||
return io_uring_get_sqe(&q->ring);
|
return io_uring_get_sqe(&q->ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void ublk_queue_alloc_sqe3(struct ublk_queue *q,
|
||||||
|
struct io_uring_sqe **sqe1, struct io_uring_sqe **sqe2,
|
||||||
|
struct io_uring_sqe **sqe3)
|
||||||
|
{
|
||||||
|
struct io_uring *r = &q->ring;
|
||||||
|
unsigned left = io_uring_sq_space_left(r);
|
||||||
|
|
||||||
|
if (left < 3)
|
||||||
|
io_uring_submit(r);
|
||||||
|
|
||||||
|
*sqe1 = io_uring_get_sqe(r);
|
||||||
|
*sqe2 = io_uring_get_sqe(r);
|
||||||
|
*sqe3 = io_uring_get_sqe(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe,
|
||||||
|
int dev_fd, int tag, int q_id, __u64 index)
|
||||||
|
{
|
||||||
|
struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd;
|
||||||
|
|
||||||
|
io_uring_prep_read(sqe, dev_fd, 0, 0, 0);
|
||||||
|
sqe->opcode = IORING_OP_URING_CMD;
|
||||||
|
sqe->flags |= IOSQE_FIXED_FILE;
|
||||||
|
sqe->cmd_op = UBLK_U_IO_REGISTER_IO_BUF;
|
||||||
|
|
||||||
|
cmd->tag = tag;
|
||||||
|
cmd->addr = index;
|
||||||
|
cmd->q_id = q_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe,
|
||||||
|
int dev_fd, int tag, int q_id, __u64 index)
|
||||||
|
{
|
||||||
|
struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd;
|
||||||
|
|
||||||
|
io_uring_prep_read(sqe, dev_fd, 0, 0, 0);
|
||||||
|
sqe->opcode = IORING_OP_URING_CMD;
|
||||||
|
sqe->flags |= IOSQE_FIXED_FILE;
|
||||||
|
sqe->cmd_op = UBLK_U_IO_UNREGISTER_IO_BUF;
|
||||||
|
|
||||||
|
cmd->tag = tag;
|
||||||
|
cmd->addr = index;
|
||||||
|
cmd->q_id = q_id;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe)
|
static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe)
|
||||||
{
|
{
|
||||||
return (void *)&sqe->cmd;
|
return (void *)&sqe->cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void ublk_set_io_res(struct ublk_queue *q, int tag, int res)
|
||||||
|
{
|
||||||
|
q->ios[tag].result = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ublk_get_io_res(const struct ublk_queue *q, unsigned tag)
|
||||||
|
{
|
||||||
|
return q->ios[tag].result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void ublk_mark_io_done(struct ublk_io *io, int res)
|
static inline void ublk_mark_io_done(struct ublk_io *io, int res)
|
||||||
{
|
{
|
||||||
io->flags |= (UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_IO_FREE);
|
io->flags |= (UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_IO_FREE);
|
||||||
@ -250,6 +315,11 @@ static inline int ublk_complete_io(struct ublk_queue *q, unsigned tag, int res)
|
|||||||
return ublk_queue_io_cmd(q, io, tag);
|
return ublk_queue_io_cmd(q, io, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int ublk_queue_use_zc(const struct ublk_queue *q)
|
||||||
|
{
|
||||||
|
return q->state & UBLKSRV_ZC;
|
||||||
|
}
|
||||||
|
|
||||||
extern const struct ublk_tgt_ops null_tgt_ops;
|
extern const struct ublk_tgt_ops null_tgt_ops;
|
||||||
extern const struct ublk_tgt_ops loop_tgt_ops;
|
extern const struct ublk_tgt_ops loop_tgt_ops;
|
||||||
|
|
||||||
|
@ -102,4 +102,12 @@ _add_ublk_dev() {
|
|||||||
echo ${dev_id}
|
echo ${dev_id}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_have_feature()
|
||||||
|
{
|
||||||
|
if $UBLK_PROG "features" | grep $1 > /dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
export UBLK_PROG=$(pwd)/kublk
|
export UBLK_PROG=$(pwd)/kublk
|
||||||
|
33
tools/testing/selftests/ublk/test_loop_03.sh
Executable file
33
tools/testing/selftests/ublk/test_loop_03.sh
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
. test_common.sh
|
||||||
|
|
||||||
|
TID="loop_03"
|
||||||
|
ERR_CODE=0
|
||||||
|
|
||||||
|
_have_feature "ZERO_COPY" || exit 4
|
||||||
|
|
||||||
|
_prep_test "loop" "write and verify over zero copy"
|
||||||
|
|
||||||
|
backfile_0=`_create_backfile 256M`
|
||||||
|
|
||||||
|
dev_id=`_add_ublk_dev -t loop $backfile_0 -z`
|
||||||
|
|
||||||
|
# run fio over the ublk disk
|
||||||
|
fio --name=write_and_verify \
|
||||||
|
--filename=/dev/ublkb${dev_id} \
|
||||||
|
--ioengine=libaio --iodepth=64 \
|
||||||
|
--rw=write \
|
||||||
|
--size=256M \
|
||||||
|
--direct=1 \
|
||||||
|
--verify=crc32c \
|
||||||
|
--do_verify=1 \
|
||||||
|
--bs=4k > /dev/null 2>&1
|
||||||
|
ERR_CODE=$?
|
||||||
|
|
||||||
|
_cleanup_test ${dev_id} "loop"
|
||||||
|
|
||||||
|
_remove_backfile $backfile_0
|
||||||
|
|
||||||
|
_show_result $TID $ERR_CODE
|
22
tools/testing/selftests/ublk/test_loop_04.sh
Executable file
22
tools/testing/selftests/ublk/test_loop_04.sh
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
. test_common.sh
|
||||||
|
|
||||||
|
TID="loop_04"
|
||||||
|
ERR_CODE=0
|
||||||
|
|
||||||
|
_prep_test "loop" "mkfs & mount & umount with zero copy"
|
||||||
|
|
||||||
|
backfile_0=`_create_backfile 256M`
|
||||||
|
|
||||||
|
dev_id=`_add_ublk_dev -t loop -z $backfile_0`
|
||||||
|
|
||||||
|
_mkfs_mount_test /dev/ublkb${dev_id}
|
||||||
|
ERR_CODE=$?
|
||||||
|
|
||||||
|
_cleanup_test ${dev_id} "loop"
|
||||||
|
|
||||||
|
_remove_backfile $backfile_0
|
||||||
|
|
||||||
|
_show_result $TID $ERR_CODE
|
Loading…
Reference in New Issue
Block a user