xref: /linux/tools/testing/selftests/ublk/file_backed.c (revision bedc9cbc5f9709b97646fe3423dbf530b74b09d5)
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, &reg, &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