Skip to content

Commit 24f8a44

Browse files
calebsanderaxboe
authored andcommitted
selftests: ublk: implement integrity user copy in kublk
If integrity data is enabled for kublk, allocate an integrity buffer for each I/O. Extend ublk_user_copy() to copy the integrity data between the ublk request and the integrity buffer if the ublksrv_io_desc indicates that the request has integrity data. Signed-off-by: Caleb Sander Mateos <csander@purestorage.com> Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 6ed6476 commit 24f8a44

2 files changed

Lines changed: 50 additions & 5 deletions

File tree

tools/testing/selftests/ublk/kublk.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,10 @@ static void ublk_queue_deinit(struct ublk_queue *q)
416416
if (q->io_cmd_buf)
417417
munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q));
418418

419-
for (i = 0; i < nr_ios; i++)
419+
for (i = 0; i < nr_ios; i++) {
420420
free(q->ios[i].buf_addr);
421+
free(q->ios[i].integrity_buf);
422+
}
421423
}
422424

423425
static void ublk_thread_deinit(struct ublk_thread *t)
@@ -433,19 +435,21 @@ static void ublk_thread_deinit(struct ublk_thread *t)
433435
}
434436
}
435437

436-
static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags)
438+
static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags,
439+
__u8 metadata_size)
437440
{
438441
struct ublk_dev *dev = q->dev;
439442
int depth = dev->dev_info.queue_depth;
440443
int i;
441-
int cmd_buf_size, io_buf_size;
444+
int cmd_buf_size, io_buf_size, integrity_size;
442445
unsigned long off;
443446

444447
q->tgt_ops = dev->tgt.ops;
445448
q->flags = 0;
446449
q->q_depth = depth;
447450
q->flags = dev->dev_info.flags;
448451
q->flags |= extra_flags;
452+
q->metadata_size = metadata_size;
449453

450454
/* Cache fd in queue for fast path access */
451455
q->ublk_fd = dev->fds[0];
@@ -461,11 +465,23 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags)
461465
}
462466

463467
io_buf_size = dev->dev_info.max_io_buf_bytes;
468+
integrity_size = ublk_integrity_len(q, io_buf_size);
464469
for (i = 0; i < q->q_depth; i++) {
465470
q->ios[i].buf_addr = NULL;
466471
q->ios[i].flags = UBLKS_IO_NEED_FETCH_RQ | UBLKS_IO_FREE;
467472
q->ios[i].tag = i;
468473

474+
if (integrity_size) {
475+
q->ios[i].integrity_buf = malloc(integrity_size);
476+
if (!q->ios[i].integrity_buf) {
477+
ublk_err("ublk dev %d queue %d io %d malloc(%d) failed: %m\n",
478+
dev->dev_info.dev_id, q->q_id, i,
479+
integrity_size);
480+
goto fail;
481+
}
482+
}
483+
484+
469485
if (ublk_queue_no_buf(q))
470486
continue;
471487

@@ -608,13 +624,13 @@ static void ublk_user_copy(const struct ublk_io *io, __u8 match_ublk_op)
608624
__u8 ublk_op = ublksrv_get_op(iod);
609625
__u32 len = iod->nr_sectors << 9;
610626
void *addr = io->buf_addr;
627+
ssize_t copied;
611628

612629
if (ublk_op != match_ublk_op)
613630
return;
614631

615632
while (len) {
616633
__u32 copy_len = min(len, UBLK_USER_COPY_LEN);
617-
ssize_t copied;
618634

619635
if (ublk_op == UBLK_IO_OP_WRITE)
620636
copied = pread(q->ublk_fd, addr, copy_len, off);
@@ -627,6 +643,20 @@ static void ublk_user_copy(const struct ublk_io *io, __u8 match_ublk_op)
627643
off += copy_len;
628644
len -= copy_len;
629645
}
646+
647+
if (!(iod->op_flags & UBLK_IO_F_INTEGRITY))
648+
return;
649+
650+
len = ublk_integrity_len(q, iod->nr_sectors << 9);
651+
off = ublk_user_copy_offset(q->q_id, io->tag);
652+
off |= UBLKSRV_IO_INTEGRITY_FLAG;
653+
if (ublk_op == UBLK_IO_OP_WRITE)
654+
copied = pread(q->ublk_fd, io->integrity_buf, len, off);
655+
else if (ublk_op == UBLK_IO_OP_READ)
656+
copied = pwrite(q->ublk_fd, io->integrity_buf, len, off);
657+
else
658+
assert(0);
659+
assert(copied == (ssize_t)len);
630660
}
631661

632662
int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io)
@@ -1013,7 +1043,8 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev)
10131043
dev->q[i].dev = dev;
10141044
dev->q[i].q_id = i;
10151045

1016-
ret = ublk_queue_init(&dev->q[i], extra_flags);
1046+
ret = ublk_queue_init(&dev->q[i], extra_flags,
1047+
ctx->metadata_size);
10171048
if (ret) {
10181049
ublk_err("ublk dev %d queue %d init queue failed\n",
10191050
dinfo->dev_id, i);

tools/testing/selftests/ublk/kublk.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct ublk_ctrl_cmd_data {
112112

113113
struct ublk_io {
114114
char *buf_addr;
115+
void *integrity_buf;
115116

116117
#define UBLKS_IO_NEED_FETCH_RQ (1UL << 0)
117118
#define UBLKS_IO_NEED_COMMIT_RQ_COMP (1UL << 1)
@@ -175,6 +176,7 @@ struct ublk_queue {
175176
#define UBLKS_Q_NO_UBLK_FIXED_FD (1ULL << 62)
176177
__u64 flags;
177178
int ublk_fd; /* cached ublk char device fd */
179+
__u8 metadata_size;
178180
struct ublk_io ios[UBLK_QUEUE_DEPTH];
179181
};
180182

@@ -224,6 +226,18 @@ static inline void ublk_set_integrity_params(const struct dev_ctx *ctx,
224226
};
225227
}
226228

229+
static inline size_t ublk_integrity_len(const struct ublk_queue *q, size_t len)
230+
{
231+
/* All targets currently use interval_exp = logical_bs_shift = 9 */
232+
return (len >> 9) * q->metadata_size;
233+
}
234+
235+
static inline size_t
236+
ublk_integrity_data_len(const struct ublk_queue *q, size_t integrity_len)
237+
{
238+
return (integrity_len / q->metadata_size) << 9;
239+
}
240+
227241
static inline int ublk_io_auto_zc_fallback(const struct ublksrv_io_desc *iod)
228242
{
229243
return !!(iod->op_flags & UBLK_IO_F_NEED_REG_BUF);

0 commit comments

Comments
 (0)