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 57bedc9cbcSMing Lei static enum io_uring_op ublk_to_uring_op(const struct ublksrv_io_desc *iod, int zc) 58bedc9cbcSMing Lei { 59bedc9cbcSMing Lei unsigned ublk_op = ublksrv_get_op(iod); 60bedc9cbcSMing Lei 61bedc9cbcSMing Lei if (ublk_op == UBLK_IO_OP_READ) 62bedc9cbcSMing Lei return zc ? IORING_OP_READ_FIXED : IORING_OP_READ; 63bedc9cbcSMing Lei else if (ublk_op == UBLK_IO_OP_WRITE) 64bedc9cbcSMing Lei return zc ? IORING_OP_WRITE_FIXED : IORING_OP_WRITE; 65bedc9cbcSMing Lei assert(0); 66bedc9cbcSMing Lei } 67bedc9cbcSMing Lei 68bedc9cbcSMing Lei static int loop_queue_tgt_rw_io(struct ublk_queue *q, const struct ublksrv_io_desc *iod, int tag) 69bedc9cbcSMing Lei { 70bedc9cbcSMing Lei int zc = ublk_queue_use_zc(q); 71bedc9cbcSMing Lei enum io_uring_op op = ublk_to_uring_op(iod, zc); 72*f2639ed1SMing Lei struct io_uring_sqe *sqe[3]; 73bedc9cbcSMing Lei 74bedc9cbcSMing Lei if (!zc) { 75*f2639ed1SMing Lei ublk_queue_alloc_sqes(q, sqe, 1); 76*f2639ed1SMing Lei if (!sqe[0]) 77bedc9cbcSMing Lei return -ENOMEM; 78bedc9cbcSMing Lei 79*f2639ed1SMing Lei io_uring_prep_rw(op, sqe[0], 1 /*fds[1]*/, 80bedc9cbcSMing Lei (void *)iod->addr, 81bedc9cbcSMing Lei iod->nr_sectors << 9, 82bedc9cbcSMing Lei iod->start_sector << 9); 83*f2639ed1SMing Lei io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); 84bedc9cbcSMing Lei q->io_inflight++; 85bedc9cbcSMing Lei /* bit63 marks us as tgt io */ 86*f2639ed1SMing Lei sqe[0]->user_data = build_user_data(tag, op, UBLK_IO_TGT_NORMAL, 1); 87bedc9cbcSMing Lei return 0; 88bedc9cbcSMing Lei } 89bedc9cbcSMing Lei 90*f2639ed1SMing Lei ublk_queue_alloc_sqes(q, sqe, 3); 91bedc9cbcSMing Lei 92*f2639ed1SMing Lei io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, tag); 93*f2639ed1SMing Lei sqe[0]->user_data = build_user_data(tag, 0xfe, 1, 1); 94*f2639ed1SMing Lei sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS; 95*f2639ed1SMing Lei sqe[0]->flags |= IOSQE_IO_LINK; 96bedc9cbcSMing Lei 97*f2639ed1SMing Lei io_uring_prep_rw(op, sqe[1], 1 /*fds[1]*/, 0, 98bedc9cbcSMing Lei iod->nr_sectors << 9, 99bedc9cbcSMing Lei iod->start_sector << 9); 100*f2639ed1SMing Lei sqe[1]->buf_index = tag; 101*f2639ed1SMing Lei sqe[1]->flags |= IOSQE_FIXED_FILE; 102*f2639ed1SMing Lei sqe[1]->flags |= IOSQE_IO_LINK; 103*f2639ed1SMing Lei sqe[1]->user_data = build_user_data(tag, op, UBLK_IO_TGT_ZC_OP, 1); 104bedc9cbcSMing Lei q->io_inflight++; 105bedc9cbcSMing Lei 106*f2639ed1SMing Lei io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, tag); 107*f2639ed1SMing Lei sqe[2]->user_data = build_user_data(tag, 0xff, UBLK_IO_TGT_ZC_BUF, 1); 108bedc9cbcSMing Lei q->io_inflight++; 109bedc9cbcSMing Lei 110bedc9cbcSMing Lei return 0; 111bedc9cbcSMing Lei } 112bedc9cbcSMing Lei 1135d95bfb5SMing Lei static int loop_queue_tgt_io(struct ublk_queue *q, int tag) 1145d95bfb5SMing Lei { 1155d95bfb5SMing Lei const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag); 1165d95bfb5SMing Lei unsigned ublk_op = ublksrv_get_op(iod); 117*f2639ed1SMing Lei struct io_uring_sqe *sqe[1]; 1185d95bfb5SMing Lei 1195d95bfb5SMing Lei switch (ublk_op) { 1205d95bfb5SMing Lei case UBLK_IO_OP_FLUSH: 121*f2639ed1SMing Lei ublk_queue_alloc_sqes(q, sqe, 1); 122*f2639ed1SMing Lei if (!sqe[0]) 123bedc9cbcSMing Lei return -ENOMEM; 124*f2639ed1SMing Lei io_uring_prep_fsync(sqe[0], 1 /*fds[1]*/, IORING_FSYNC_DATASYNC); 125*f2639ed1SMing Lei io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); 126bedc9cbcSMing Lei q->io_inflight++; 127*f2639ed1SMing Lei sqe[0]->user_data = build_user_data(tag, ublk_op, UBLK_IO_TGT_NORMAL, 1); 1285d95bfb5SMing Lei break; 1295d95bfb5SMing Lei case UBLK_IO_OP_WRITE_ZEROES: 1305d95bfb5SMing Lei case UBLK_IO_OP_DISCARD: 1315d95bfb5SMing Lei return -ENOTSUP; 1325d95bfb5SMing Lei case UBLK_IO_OP_READ: 1335d95bfb5SMing Lei case UBLK_IO_OP_WRITE: 134bedc9cbcSMing Lei loop_queue_tgt_rw_io(q, iod, tag); 1355d95bfb5SMing Lei break; 1365d95bfb5SMing Lei default: 1375d95bfb5SMing Lei return -EINVAL; 1385d95bfb5SMing Lei } 1395d95bfb5SMing Lei 1405d95bfb5SMing Lei ublk_dbg(UBLK_DBG_IO, "%s: tag %d ublk io %x %llx %u\n", __func__, tag, 1415d95bfb5SMing Lei iod->op_flags, iod->start_sector, iod->nr_sectors << 9); 1425d95bfb5SMing Lei return 1; 1435d95bfb5SMing Lei } 1445d95bfb5SMing Lei 1455d95bfb5SMing Lei static int ublk_loop_queue_io(struct ublk_queue *q, int tag) 1465d95bfb5SMing Lei { 1475d95bfb5SMing Lei int queued = loop_queue_tgt_io(q, tag); 1485d95bfb5SMing Lei 1495d95bfb5SMing Lei if (queued < 0) 1505d95bfb5SMing Lei ublk_complete_io(q, tag, queued); 1515d95bfb5SMing Lei 1525d95bfb5SMing Lei return 0; 1535d95bfb5SMing Lei } 1545d95bfb5SMing Lei 1555d95bfb5SMing Lei static void ublk_loop_io_done(struct ublk_queue *q, int tag, 1565d95bfb5SMing Lei const struct io_uring_cqe *cqe) 1575d95bfb5SMing Lei { 1585d95bfb5SMing Lei int cqe_tag = user_data_to_tag(cqe->user_data); 159bedc9cbcSMing Lei unsigned tgt_data = user_data_to_tgt_data(cqe->user_data); 160bedc9cbcSMing Lei int res = cqe->res; 1615d95bfb5SMing Lei 162bedc9cbcSMing Lei if (res < 0 || tgt_data == UBLK_IO_TGT_NORMAL) 163bedc9cbcSMing Lei goto complete; 164bedc9cbcSMing Lei 165bedc9cbcSMing Lei if (tgt_data == UBLK_IO_TGT_ZC_OP) { 166bedc9cbcSMing Lei ublk_set_io_res(q, tag, cqe->res); 167bedc9cbcSMing Lei goto exit; 168bedc9cbcSMing Lei } 169bedc9cbcSMing Lei assert(tgt_data == UBLK_IO_TGT_ZC_BUF); 170bedc9cbcSMing Lei res = ublk_get_io_res(q, tag); 171bedc9cbcSMing Lei complete: 1725d95bfb5SMing Lei assert(tag == cqe_tag); 173bedc9cbcSMing Lei ublk_complete_io(q, tag, res); 174bedc9cbcSMing Lei exit: 1755d95bfb5SMing Lei q->io_inflight--; 1765d95bfb5SMing Lei } 1775d95bfb5SMing Lei 1785d95bfb5SMing Lei static int ublk_loop_tgt_init(struct ublk_dev *dev) 1795d95bfb5SMing Lei { 1805d95bfb5SMing Lei unsigned long long bytes; 1815d95bfb5SMing Lei int ret; 1825d95bfb5SMing Lei struct ublk_params p = { 183bedc9cbcSMing Lei .types = UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN, 1845d95bfb5SMing Lei .basic = { 18596af5af4SMing Lei .attrs = UBLK_ATTR_VOLATILE_CACHE, 1865d95bfb5SMing Lei .logical_bs_shift = 9, 1875d95bfb5SMing Lei .physical_bs_shift = 12, 1885d95bfb5SMing Lei .io_opt_shift = 12, 1895d95bfb5SMing Lei .io_min_shift = 9, 1905d95bfb5SMing Lei .max_sectors = dev->dev_info.max_io_buf_bytes >> 9, 1915d95bfb5SMing Lei }, 192bedc9cbcSMing Lei .dma = { 193bedc9cbcSMing Lei .alignment = 511, 194bedc9cbcSMing Lei }, 1955d95bfb5SMing Lei }; 1965d95bfb5SMing Lei 1975d95bfb5SMing Lei ret = backing_file_tgt_init(dev); 1985d95bfb5SMing Lei if (ret) 1995d95bfb5SMing Lei return ret; 2005d95bfb5SMing Lei 201ffde32a4SMing Lei if (dev->tgt.nr_backing_files != 1) 202ffde32a4SMing Lei return -EINVAL; 203ffde32a4SMing Lei 2045d95bfb5SMing Lei bytes = dev->tgt.backing_file_size[0]; 2055d95bfb5SMing Lei dev->tgt.dev_size = bytes; 2065d95bfb5SMing Lei p.basic.dev_sectors = bytes >> 9; 2075d95bfb5SMing Lei dev->tgt.params = p; 2085d95bfb5SMing Lei 2095d95bfb5SMing Lei return 0; 2105d95bfb5SMing Lei } 2115d95bfb5SMing Lei 2125d95bfb5SMing Lei const struct ublk_tgt_ops loop_tgt_ops = { 2135d95bfb5SMing Lei .name = "loop", 2145d95bfb5SMing Lei .init_tgt = ublk_loop_tgt_init, 2155d95bfb5SMing Lei .deinit_tgt = backing_file_tgt_deinit, 2165d95bfb5SMing Lei .queue_io = ublk_loop_queue_io, 2175d95bfb5SMing Lei .tgt_io_done = ublk_loop_io_done, 2185d95bfb5SMing Lei }; 219