Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests: ublk: add integrity data support to loop target

To perform and end-to-end test of integrity information through a ublk
device, we need to actually store it somewhere and retrieve it. Add this
support to kublk's loop target. It uses a second backing file for the
integrity data corresponding to the data stored in the first file.
The integrity file is initialized with byte 0xFF, which ensures the app
and reference tags are set to the "escape" pattern to disable the
bio-integrity-auto guard and reftag checks until the blocks are written.
The integrity file is opened without O_DIRECT since it will be accessed
at sub-block granularity. Each incoming read/write results in a pair of
reads/writes, one to the data file, and one to the integrity file. If
either backing I/O fails, the error is propagated to the ublk request.
If both backing I/Os read/write some bytes, the ublk request is
completed with the smaller of the number of blocks accessed by each I/O.

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>

authored by

Caleb Sander Mateos and committed by
Jens Axboe
f48250dc a1805442

+74 -18
+74 -18
tools/testing/selftests/ublk/file_backed.c
··· 35 35 unsigned auto_zc = ublk_queue_use_auto_zc(q); 36 36 enum io_uring_op op = ublk_to_uring_op(iod, zc | auto_zc); 37 37 struct ublk_io *io = ublk_get_io(q, tag); 38 + __u64 offset = iod->start_sector << 9; 39 + __u32 len = iod->nr_sectors << 9; 38 40 struct io_uring_sqe *sqe[3]; 39 41 void *addr = io->buf_addr; 42 + 43 + if (iod->op_flags & UBLK_IO_F_INTEGRITY) { 44 + ublk_io_alloc_sqes(t, sqe, 1); 45 + /* Use second backing file for integrity data */ 46 + io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 2), 47 + io->integrity_buf, 48 + ublk_integrity_len(q, len), 49 + ublk_integrity_len(q, offset)); 50 + sqe[0]->flags = IOSQE_FIXED_FILE; 51 + /* tgt_data = 1 indicates integrity I/O */ 52 + sqe[0]->user_data = build_user_data(tag, ublk_op, 1, q->q_id, 1); 53 + } 40 54 41 55 if (!zc || auto_zc) { 42 56 ublk_io_alloc_sqes(t, sqe, 1); ··· 59 45 60 46 io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/, 61 47 addr, 62 - iod->nr_sectors << 9, 63 - iod->start_sector << 9); 48 + len, 49 + offset); 64 50 if (auto_zc) 65 51 sqe[0]->buf_index = tag; 66 52 io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); 67 53 /* bit63 marks us as tgt io */ 68 54 sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); 69 - return 1; 55 + return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 1; 70 56 } 71 57 72 58 ublk_io_alloc_sqes(t, sqe, 3); ··· 77 63 ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); 78 64 79 65 io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0, 80 - iod->nr_sectors << 9, 81 - iod->start_sector << 9); 66 + len, 67 + offset); 82 68 sqe[1]->buf_index = tag; 83 69 sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK; 84 70 sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); ··· 86 72 io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, io->buf_index); 87 73 sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1); 88 74 89 - return 2; 75 + return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 2; 90 76 } 91 77 92 78 static int loop_queue_tgt_io(struct ublk_thread *t, struct ublk_queue *q, int tag) ··· 133 119 unsigned op = user_data_to_op(cqe->user_data); 134 120 struct ublk_io *io = ublk_get_io(q, tag); 135 121 136 - if (cqe->res < 0 || op != ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) { 137 - if (!io->result) 138 - io->result = cqe->res; 139 - if (cqe->res < 0) 140 - ublk_err("%s: io failed op %x user_data %lx\n", 141 - __func__, op, cqe->user_data); 122 + if (cqe->res < 0) { 123 + io->result = cqe->res; 124 + ublk_err("%s: io failed op %x user_data %lx\n", 125 + __func__, op, cqe->user_data); 126 + } else if (op != ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) { 127 + __s32 data_len = user_data_to_tgt_data(cqe->user_data) 128 + ? ublk_integrity_data_len(q, cqe->res) 129 + : cqe->res; 130 + 131 + if (!io->result || data_len < io->result) 132 + io->result = data_len; 142 133 } 143 134 144 135 /* buffer register op is IOSQE_CQE_SKIP_SUCCESS */ ··· 154 135 ublk_complete_io(t, q, tag, io->result); 155 136 } 156 137 138 + static int ublk_loop_memset_file(int fd, __u8 byte, size_t len) 139 + { 140 + off_t offset = 0; 141 + __u8 buf[4096]; 142 + 143 + memset(buf, byte, sizeof(buf)); 144 + while (len) { 145 + int ret = pwrite(fd, buf, min(len, sizeof(buf)), offset); 146 + 147 + if (ret < 0) 148 + return -errno; 149 + if (!ret) 150 + return -EIO; 151 + 152 + len -= ret; 153 + offset += ret; 154 + } 155 + return 0; 156 + } 157 + 157 158 static int ublk_loop_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev) 158 159 { 159 160 unsigned long long bytes; 161 + unsigned long blocks; 160 162 int ret; 161 163 struct ublk_params p = { 162 164 .types = UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN, ··· 194 154 }, 195 155 }; 196 156 157 + ublk_set_integrity_params(ctx, &p); 197 158 if (ctx->auto_zc_fallback) { 198 159 ublk_err("%s: not support auto_zc_fallback\n", __func__); 199 160 return -EINVAL; 200 161 } 201 - if (ctx->metadata_size) { 202 - ublk_err("%s: integrity not supported\n", __func__); 203 - return -EINVAL; 204 - } 205 162 163 + /* Use O_DIRECT only for data file */ 206 164 ret = backing_file_tgt_init(dev, 1); 207 165 if (ret) 208 166 return ret; 209 167 210 - if (dev->tgt.nr_backing_files != 1) 168 + /* Expect a second file for integrity data */ 169 + if (dev->tgt.nr_backing_files != 1 + !!ctx->metadata_size) 211 170 return -EINVAL; 212 171 213 - bytes = dev->tgt.backing_file_size[0]; 172 + blocks = dev->tgt.backing_file_size[0] >> p.basic.logical_bs_shift; 173 + if (ctx->metadata_size) { 174 + unsigned long metadata_blocks = 175 + dev->tgt.backing_file_size[1] / ctx->metadata_size; 176 + unsigned long integrity_len; 177 + 178 + /* Ensure both data and integrity data fit in backing files */ 179 + blocks = min(blocks, metadata_blocks); 180 + integrity_len = blocks * ctx->metadata_size; 181 + /* 182 + * Initialize PI app tag and ref tag to 0xFF 183 + * to disable bio-integrity-auto checks 184 + */ 185 + ret = ublk_loop_memset_file(dev->fds[2], 0xFF, integrity_len); 186 + if (ret) 187 + return ret; 188 + } 189 + bytes = blocks << p.basic.logical_bs_shift; 214 190 dev->tgt.dev_size = bytes; 215 191 p.basic.dev_sectors = bytes >> 9; 216 192 dev->tgt.params = p;