unsigned auto_zc = ublk_queue_use_auto_zc(q);
enum io_uring_op op = ublk_to_uring_op(iod, zc | auto_zc);
struct ublk_io *io = ublk_get_io(q, tag);
+ __u64 offset = iod->start_sector << 9;
+ __u32 len = iod->nr_sectors << 9;
struct io_uring_sqe *sqe[3];
void *addr = io->buf_addr;
+ if (iod->op_flags & UBLK_IO_F_INTEGRITY) {
+ ublk_io_alloc_sqes(t, sqe, 1);
+ /* Use second backing file for integrity data */
+ io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 2),
+ io->integrity_buf,
+ ublk_integrity_len(q, len),
+ ublk_integrity_len(q, offset));
+ sqe[0]->flags = IOSQE_FIXED_FILE;
+ /* tgt_data = 1 indicates integrity I/O */
+ sqe[0]->user_data = build_user_data(tag, ublk_op, 1, q->q_id, 1);
+ }
+
if (!zc || auto_zc) {
ublk_io_alloc_sqes(t, sqe, 1);
if (!sqe[0])
io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/,
addr,
- iod->nr_sectors << 9,
- iod->start_sector << 9);
+ len,
+ offset);
if (auto_zc)
sqe[0]->buf_index = tag;
io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE);
/* bit63 marks us as tgt io */
sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1);
- return 1;
+ return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 1;
}
ublk_io_alloc_sqes(t, sqe, 3);
ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1);
io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0,
- iod->nr_sectors << 9,
- iod->start_sector << 9);
+ len,
+ offset);
sqe[1]->buf_index = tag;
sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK;
sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1);
io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, io->buf_index);
sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1);
- return 2;
+ return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 2;
}
static int loop_queue_tgt_io(struct ublk_thread *t, struct ublk_queue *q, int tag)
unsigned op = user_data_to_op(cqe->user_data);
struct ublk_io *io = ublk_get_io(q, tag);
- if (cqe->res < 0 || op != ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) {
- if (!io->result)
- io->result = cqe->res;
- if (cqe->res < 0)
- ublk_err("%s: io failed op %x user_data %lx\n",
- __func__, op, cqe->user_data);
+ if (cqe->res < 0) {
+ io->result = cqe->res;
+ ublk_err("%s: io failed op %x user_data %lx\n",
+ __func__, op, cqe->user_data);
+ } else if (op != ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) {
+ __s32 data_len = user_data_to_tgt_data(cqe->user_data)
+ ? ublk_integrity_data_len(q, cqe->res)
+ : cqe->res;
+
+ if (!io->result || data_len < io->result)
+ io->result = data_len;
}
/* buffer register op is IOSQE_CQE_SKIP_SUCCESS */
ublk_complete_io(t, q, tag, io->result);
}
+static int ublk_loop_memset_file(int fd, __u8 byte, size_t len)
+{
+ off_t offset = 0;
+ __u8 buf[4096];
+
+ memset(buf, byte, sizeof(buf));
+ while (len) {
+ int ret = pwrite(fd, buf, min(len, sizeof(buf)), offset);
+
+ if (ret < 0)
+ return -errno;
+ if (!ret)
+ return -EIO;
+
+ len -= ret;
+ offset += ret;
+ }
+ return 0;
+}
+
static int ublk_loop_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
{
unsigned long long bytes;
+ unsigned long blocks;
int ret;
struct ublk_params p = {
.types = UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN,
},
};
+ ublk_set_integrity_params(ctx, &p);
if (ctx->auto_zc_fallback) {
ublk_err("%s: not support auto_zc_fallback\n", __func__);
return -EINVAL;
}
- if (ctx->metadata_size) {
- ublk_err("%s: integrity not supported\n", __func__);
- return -EINVAL;
- }
+ /* Use O_DIRECT only for data file */
ret = backing_file_tgt_init(dev, 1);
if (ret)
return ret;
- if (dev->tgt.nr_backing_files != 1)
+ /* Expect a second file for integrity data */
+ if (dev->tgt.nr_backing_files != 1 + !!ctx->metadata_size)
return -EINVAL;
- bytes = dev->tgt.backing_file_size[0];
+ blocks = dev->tgt.backing_file_size[0] >> p.basic.logical_bs_shift;
+ if (ctx->metadata_size) {
+ unsigned long metadata_blocks =
+ dev->tgt.backing_file_size[1] / ctx->metadata_size;
+ unsigned long integrity_len;
+
+ /* Ensure both data and integrity data fit in backing files */
+ blocks = min(blocks, metadata_blocks);
+ integrity_len = blocks * ctx->metadata_size;
+ /*
+ * Initialize PI app tag and ref tag to 0xFF
+ * to disable bio-integrity-auto checks
+ */
+ ret = ublk_loop_memset_file(dev->fds[2], 0xFF, integrity_len);
+ if (ret)
+ return ret;
+ }
+ bytes = blocks << p.basic.logical_bs_shift;
dev->tgt.dev_size = bytes;
p.basic.dev_sectors = bytes >> 9;
dev->tgt.params = p;