15d95bfb5SMing Lei // SPDX-License-Identifier: GPL-2.0 25d95bfb5SMing Lei 35d95bfb5SMing Lei #include "kublk.h" 45d95bfb5SMing Lei 55d95bfb5SMing Lei static void backing_file_tgt_deinit(struct ublk_dev *dev) 65d95bfb5SMing Lei { 75d95bfb5SMing Lei int i; 85d95bfb5SMing Lei 95d95bfb5SMing Lei for (i = 1; i < dev->nr_fds; i++) { 105d95bfb5SMing Lei fsync(dev->fds[i]); 115d95bfb5SMing Lei close(dev->fds[i]); 125d95bfb5SMing Lei } 135d95bfb5SMing Lei } 145d95bfb5SMing Lei 155d95bfb5SMing Lei static int backing_file_tgt_init(struct ublk_dev *dev) 165d95bfb5SMing Lei { 175d95bfb5SMing Lei int fd, i; 185d95bfb5SMing Lei 195d95bfb5SMing Lei assert(dev->nr_fds == 1); 205d95bfb5SMing Lei 215d95bfb5SMing Lei for (i = 0; i < dev->tgt.nr_backing_files; i++) { 225d95bfb5SMing Lei char *file = dev->tgt.backing_file[i]; 235d95bfb5SMing Lei unsigned long bytes; 245d95bfb5SMing Lei struct stat st; 255d95bfb5SMing Lei 265d95bfb5SMing Lei ublk_dbg(UBLK_DBG_DEV, "%s: file %d: %s\n", __func__, i, file); 275d95bfb5SMing Lei 285d95bfb5SMing Lei fd = open(file, O_RDWR | O_DIRECT); 295d95bfb5SMing Lei if (fd < 0) { 305d95bfb5SMing Lei ublk_err("%s: backing file %s can't be opened: %s\n", 315d95bfb5SMing Lei __func__, file, strerror(errno)); 325d95bfb5SMing Lei return -EBADF; 335d95bfb5SMing Lei } 345d95bfb5SMing Lei 355d95bfb5SMing Lei if (fstat(fd, &st) < 0) { 365d95bfb5SMing Lei close(fd); 375d95bfb5SMing Lei return -EBADF; 385d95bfb5SMing Lei } 395d95bfb5SMing Lei 405d95bfb5SMing Lei if (S_ISREG(st.st_mode)) 415d95bfb5SMing Lei bytes = st.st_size; 425d95bfb5SMing Lei else if (S_ISBLK(st.st_mode)) { 435d95bfb5SMing Lei if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) 445d95bfb5SMing Lei return -1; 455d95bfb5SMing Lei } else { 465d95bfb5SMing Lei return -EINVAL; 475d95bfb5SMing Lei } 485d95bfb5SMing Lei 495d95bfb5SMing Lei dev->tgt.backing_file_size[i] = bytes; 505d95bfb5SMing Lei dev->fds[dev->nr_fds] = fd; 515d95bfb5SMing Lei dev->nr_fds += 1; 525d95bfb5SMing Lei } 535d95bfb5SMing Lei 545d95bfb5SMing Lei return 0; 555d95bfb5SMing Lei } 565d95bfb5SMing Lei 57*bedc9cbcSMing Lei static enum io_uring_op ublk_to_uring_op(const struct ublksrv_io_desc *iod, int zc) 58*bedc9cbcSMing Lei { 59*bedc9cbcSMing Lei unsigned ublk_op = ublksrv_get_op(iod); 60*bedc9cbcSMing Lei 61*bedc9cbcSMing Lei if (ublk_op == UBLK_IO_OP_READ) 62*bedc9cbcSMing Lei return zc ? IORING_OP_READ_FIXED : IORING_OP_READ; 63*bedc9cbcSMing Lei else if (ublk_op == UBLK_IO_OP_WRITE) 64*bedc9cbcSMing Lei return zc ? IORING_OP_WRITE_FIXED : IORING_OP_WRITE; 65*bedc9cbcSMing Lei assert(0); 66*bedc9cbcSMing Lei } 67*bedc9cbcSMing Lei 68*bedc9cbcSMing Lei static int loop_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_desc *iod, int tag) 69*bedc9cbcSMing Lei { 70*bedc9cbcSMing Lei int zc = ublk_queue_use_zc(q); 71*bedc9cbcSMing Lei enum io_uring_op op = ublk_to_uring_op(iod, zc); 72*bedc9cbcSMing Lei struct io_uring_sqe *reg; 73*bedc9cbcSMing Lei struct io_uring_sqe *rw; 74*bedc9cbcSMing Lei struct io_uring_sqe *ureg; 75*bedc9cbcSMing Lei 76*bedc9cbcSMing Lei if (!zc) { 77*bedc9cbcSMing Lei rw = ublk_queue_alloc_sqe(q); 78*bedc9cbcSMing Lei if (!rw) 79*bedc9cbcSMing Lei return -ENOMEM; 80*bedc9cbcSMing Lei 81*bedc9cbcSMing Lei io_uring_prep_rw(op, rw, 1 /*fds[1]*/, 82*bedc9cbcSMing Lei (void *)iod->addr, 83*bedc9cbcSMing Lei iod->nr_sectors << 9, 84*bedc9cbcSMing Lei iod->start_sector << 9); 85*bedc9cbcSMing Lei io_uring_sqe_set_flags(rw, IOSQE_FIXED_FILE); 86*bedc9cbcSMing Lei q->io_inflight++; 87*bedc9cbcSMing Lei /* bit63 marks us as tgt io */ 88*bedc9cbcSMing Lei rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_NORMAL, 1); 89*bedc9cbcSMing Lei return 0; 90*bedc9cbcSMing Lei } 91*bedc9cbcSMing Lei 92*bedc9cbcSMing Lei ublk_queue_alloc_sqe3(q, ®, &rw, &ureg); 93*bedc9cbcSMing Lei 94*bedc9cbcSMing Lei io_uring_prep_buf_register(reg, 0, tag, q->q_id, tag); 95*bedc9cbcSMing Lei reg->user_data = build_user_data(tag, 0xfe, 1, 1); 96*bedc9cbcSMing Lei reg->flags |= IOSQE_CQE_SKIP_SUCCESS; 97*bedc9cbcSMing Lei reg->flags |= IOSQE_IO_LINK; 98*bedc9cbcSMing Lei 99*bedc9cbcSMing Lei io_uring_prep_rw(op, rw, 1 /*fds[1]*/, 0, 100*bedc9cbcSMing Lei iod->nr_sectors << 9, 101*bedc9cbcSMing Lei iod->start_sector << 9); 102*bedc9cbcSMing Lei rw->buf_index = tag; 103*bedc9cbcSMing Lei rw->flags |= IOSQE_FIXED_FILE; 104*bedc9cbcSMing Lei rw->flags |= IOSQE_IO_LINK; 105*bedc9cbcSMing Lei rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_ZC_OP, 1); 106*bedc9cbcSMing Lei q->io_inflight++; 107*bedc9cbcSMing Lei 108*bedc9cbcSMing Lei io_uring_prep_buf_unregister(ureg, 0, tag, q->q_id, tag); 109*bedc9cbcSMing Lei ureg->user_data = build_user_data(tag, 0xff, UBLK_IO_TGT_ZC_BUF, 1); 110*bedc9cbcSMing Lei q->io_inflight++; 111*bedc9cbcSMing Lei 112*bedc9cbcSMing Lei return 0; 113*bedc9cbcSMing Lei } 114*bedc9cbcSMing Lei 1155d95bfb5SMing Lei static int loop_queue_tgt_io(struct ublk_queue *q, int tag) 1165d95bfb5SMing Lei { 1175d95bfb5SMing Lei const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag); 1185d95bfb5SMing Lei unsigned ublk_op = ublksrv_get_op(iod); 119*bedc9cbcSMing Lei struct io_uring_sqe *sqe; 1205d95bfb5SMing Lei 1215d95bfb5SMing Lei switch (ublk_op) { 1225d95bfb5SMing Lei case UBLK_IO_OP_FLUSH: 123*bedc9cbcSMing Lei sqe = ublk_queue_alloc_sqe(q); 124*bedc9cbcSMing Lei if (!sqe) 125*bedc9cbcSMing Lei return -ENOMEM; 1265d95bfb5SMing Lei io_uring_prep_sync_file_range(sqe, 1 /*fds[1]*/, 1275d95bfb5SMing Lei iod->nr_sectors << 9, 1285d95bfb5SMing Lei iod->start_sector << 9, 1295d95bfb5SMing Lei IORING_FSYNC_DATASYNC); 1305d95bfb5SMing Lei io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE); 131*bedc9cbcSMing Lei q->io_inflight++; 132*bedc9cbcSMing Lei sqe->user_data = build_user_data(tag, ublk_op, UBLK_IO_TGT_NORMAL, 1); 1335d95bfb5SMing Lei break; 1345d95bfb5SMing Lei case UBLK_IO_OP_WRITE_ZEROES: 1355d95bfb5SMing Lei case UBLK_IO_OP_DISCARD: 1365d95bfb5SMing Lei return -ENOTSUP; 1375d95bfb5SMing Lei case UBLK_IO_OP_READ: 1385d95bfb5SMing Lei case UBLK_IO_OP_WRITE: 139*bedc9cbcSMing Lei loop_queue_tgt_rw_io(q, iod, tag); 1405d95bfb5SMing Lei break; 1415d95bfb5SMing Lei default: 1425d95bfb5SMing Lei return -EINVAL; 1435d95bfb5SMing Lei } 1445d95bfb5SMing Lei 1455d95bfb5SMing Lei ublk_dbg(UBLK_DBG_IO, "%s: tag %d ublk io %x %llx %u\n", __func__, tag, 1465d95bfb5SMing Lei iod->op_flags, iod->start_sector, iod->nr_sectors << 9); 1475d95bfb5SMing Lei return 1; 1485d95bfb5SMing Lei } 1495d95bfb5SMing Lei 1505d95bfb5SMing Lei static int ublk_loop_queue_io(struct ublk_queue *q, int tag) 1515d95bfb5SMing Lei { 1525d95bfb5SMing Lei int queued = loop_queue_tgt_io(q, tag); 1535d95bfb5SMing Lei 1545d95bfb5SMing Lei if (queued < 0) 1555d95bfb5SMing Lei ublk_complete_io(q, tag, queued); 1565d95bfb5SMing Lei 1575d95bfb5SMing Lei return 0; 1585d95bfb5SMing Lei } 1595d95bfb5SMing Lei 1605d95bfb5SMing Lei static void ublk_loop_io_done(struct ublk_queue *q, int tag, 1615d95bfb5SMing Lei const struct io_uring_cqe *cqe) 1625d95bfb5SMing Lei { 1635d95bfb5SMing Lei int cqe_tag = user_data_to_tag(cqe->user_data); 164*bedc9cbcSMing Lei unsigned tgt_data = user_data_to_tgt_data(cqe->user_data); 165*bedc9cbcSMing Lei int res = cqe->res; 1665d95bfb5SMing Lei 167*bedc9cbcSMing Lei if (res < 0 || tgt_data == UBLK_IO_TGT_NORMAL) 168*bedc9cbcSMing Lei goto complete; 169*bedc9cbcSMing Lei 170*bedc9cbcSMing Lei if (tgt_data == UBLK_IO_TGT_ZC_OP) { 171*bedc9cbcSMing Lei ublk_set_io_res(q, tag, cqe->res); 172*bedc9cbcSMing Lei goto exit; 173*bedc9cbcSMing Lei } 174*bedc9cbcSMing Lei assert(tgt_data == UBLK_IO_TGT_ZC_BUF); 175*bedc9cbcSMing Lei res = ublk_get_io_res(q, tag); 176*bedc9cbcSMing Lei complete: 1775d95bfb5SMing Lei assert(tag == cqe_tag); 178*bedc9cbcSMing Lei ublk_complete_io(q, tag, res); 179*bedc9cbcSMing Lei exit: 1805d95bfb5SMing Lei q->io_inflight--; 1815d95bfb5SMing Lei } 1825d95bfb5SMing Lei 1835d95bfb5SMing Lei static int ublk_loop_tgt_init(struct ublk_dev *dev) 1845d95bfb5SMing Lei { 1855d95bfb5SMing Lei unsigned long long bytes; 1865d95bfb5SMing Lei int ret; 1875d95bfb5SMing Lei struct ublk_params p = { 188*bedc9cbcSMing Lei .types = UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN, 1895d95bfb5SMing Lei .basic = { 1905d95bfb5SMing Lei .logical_bs_shift = 9, 1915d95bfb5SMing Lei .physical_bs_shift = 12, 1925d95bfb5SMing Lei .io_opt_shift = 12, 1935d95bfb5SMing Lei .io_min_shift = 9, 1945d95bfb5SMing Lei .max_sectors = dev->dev_info.max_io_buf_bytes >> 9, 1955d95bfb5SMing Lei }, 196*bedc9cbcSMing Lei .dma = { 197*bedc9cbcSMing Lei .alignment = 511, 198*bedc9cbcSMing Lei }, 1995d95bfb5SMing Lei }; 2005d95bfb5SMing Lei 2015d95bfb5SMing Lei assert(dev->tgt.nr_backing_files == 1); 2025d95bfb5SMing Lei ret = backing_file_tgt_init(dev); 2035d95bfb5SMing Lei if (ret) 2045d95bfb5SMing Lei return ret; 2055d95bfb5SMing Lei 2065d95bfb5SMing Lei bytes = dev->tgt.backing_file_size[0]; 2075d95bfb5SMing Lei dev->tgt.dev_size = bytes; 2085d95bfb5SMing Lei p.basic.dev_sectors = bytes >> 9; 2095d95bfb5SMing Lei dev->tgt.params = p; 2105d95bfb5SMing Lei 2115d95bfb5SMing Lei return 0; 2125d95bfb5SMing Lei } 2135d95bfb5SMing Lei 2145d95bfb5SMing Lei const struct ublk_tgt_ops loop_tgt_ops = { 2155d95bfb5SMing Lei .name = "loop", 2165d95bfb5SMing Lei .init_tgt = ublk_loop_tgt_init, 2175d95bfb5SMing Lei .deinit_tgt = backing_file_tgt_deinit, 2185d95bfb5SMing Lei .queue_io = ublk_loop_queue_io, 2195d95bfb5SMing Lei .tgt_io_done = ublk_loop_io_done, 2205d95bfb5SMing Lei }; 221