xref: /aosp_15_r20/external/ublksrv/include/ublksrv_tgt.h (revision 94c4a1e103eb1715230460aab379dff275992c20)
1*94c4a1e1SFrank Piva // SPDX-License-Identifier: MIT or GPL-2.0-only
2*94c4a1e1SFrank Piva 
3*94c4a1e1SFrank Piva #ifndef UBLKSRV_TGT_INC_H
4*94c4a1e1SFrank Piva #define UBLKSRV_TGT_INC_H
5*94c4a1e1SFrank Piva 
6*94c4a1e1SFrank Piva #include <unistd.h>
7*94c4a1e1SFrank Piva #include <stdlib.h>
8*94c4a1e1SFrank Piva #include <pthread.h>
9*94c4a1e1SFrank Piva #include <getopt.h>
10*94c4a1e1SFrank Piva #include <string.h>
11*94c4a1e1SFrank Piva #include <stdarg.h>
12*94c4a1e1SFrank Piva #include <limits.h>
13*94c4a1e1SFrank Piva #include <sys/types.h>
14*94c4a1e1SFrank Piva #include <sys/stat.h>
15*94c4a1e1SFrank Piva #include <sys/ioctl.h>
16*94c4a1e1SFrank Piva 
17*94c4a1e1SFrank Piva #include <libgen.h>
18*94c4a1e1SFrank Piva #include <coroutine>
19*94c4a1e1SFrank Piva #include <iostream>
20*94c4a1e1SFrank Piva #include <type_traits>
21*94c4a1e1SFrank Piva 
22*94c4a1e1SFrank Piva #include "ublksrv_utils.h"
23*94c4a1e1SFrank Piva #include "ublksrv.h"
24*94c4a1e1SFrank Piva 
25*94c4a1e1SFrank Piva #define ublk_assert(x)  do { \
26*94c4a1e1SFrank Piva 	if (!(x)) {	\
27*94c4a1e1SFrank Piva 		ublk_err("%s %d: assert!\n", __func__, __LINE__); \
28*94c4a1e1SFrank Piva 		assert(x);	\
29*94c4a1e1SFrank Piva 	}	\
30*94c4a1e1SFrank Piva } while (0)
31*94c4a1e1SFrank Piva 
ilog2(unsigned x)32*94c4a1e1SFrank Piva static inline unsigned ilog2(unsigned x)
33*94c4a1e1SFrank Piva {
34*94c4a1e1SFrank Piva     return sizeof(unsigned) * 8 - 1 - __builtin_clz(x);
35*94c4a1e1SFrank Piva }
36*94c4a1e1SFrank Piva 
37*94c4a1e1SFrank Piva #define MAX_NR_UBLK_DEVS	128
38*94c4a1e1SFrank Piva #define UBLKSRV_PID_DIR  "/tmp/ublksrvd"
39*94c4a1e1SFrank Piva 
40*94c4a1e1SFrank Piva /* json device data is stored at this offset of pid file */
41*94c4a1e1SFrank Piva #define JSON_OFFSET   32
42*94c4a1e1SFrank Piva 
43*94c4a1e1SFrank Piva char *ublksrv_tgt_return_json_buf(struct ublksrv_dev *dev, int *size);
44*94c4a1e1SFrank Piva char *ublksrv_tgt_realloc_json_buf(struct ublksrv_dev *dev, int *size);
45*94c4a1e1SFrank Piva 
ublksrv_convert_cmd_op(const struct ublksrv_io_desc * iod)46*94c4a1e1SFrank Piva static inline unsigned ublksrv_convert_cmd_op(const struct ublksrv_io_desc *iod)
47*94c4a1e1SFrank Piva {
48*94c4a1e1SFrank Piva 	unsigned ublk_op = ublksrv_get_op(iod);
49*94c4a1e1SFrank Piva 
50*94c4a1e1SFrank Piva 	switch (ublk_op) {
51*94c4a1e1SFrank Piva 	case UBLK_IO_OP_READ:
52*94c4a1e1SFrank Piva 		return IORING_OP_READ;
53*94c4a1e1SFrank Piva 	case UBLK_IO_OP_WRITE:
54*94c4a1e1SFrank Piva 		return IORING_OP_WRITE;
55*94c4a1e1SFrank Piva 	case UBLK_IO_OP_FLUSH:
56*94c4a1e1SFrank Piva 		return IORING_OP_FSYNC;
57*94c4a1e1SFrank Piva 	case UBLK_IO_OP_DISCARD:
58*94c4a1e1SFrank Piva 	case UBLK_IO_OP_WRITE_SAME:
59*94c4a1e1SFrank Piva 	case UBLK_IO_OP_WRITE_ZEROES:
60*94c4a1e1SFrank Piva 		return IORING_OP_FALLOCATE;
61*94c4a1e1SFrank Piva 	default:
62*94c4a1e1SFrank Piva 		return -1;
63*94c4a1e1SFrank Piva 	}
64*94c4a1e1SFrank Piva }
65*94c4a1e1SFrank Piva 
66*94c4a1e1SFrank Piva /*
67*94c4a1e1SFrank Piva  * Our convention is to use this macro instead of raw `co_await` to make it
68*94c4a1e1SFrank Piva  * easy to log `tag` when debugging coroutine issues.
69*94c4a1e1SFrank Piva  */
70*94c4a1e1SFrank Piva #define co_await__suspend_always(tag) {                                       \
71*94c4a1e1SFrank Piva 	static_assert(std::is_same<decltype(tag), int>::value, "tag not int");\
72*94c4a1e1SFrank Piva 	co_await std::suspend_always();                                       \
73*94c4a1e1SFrank Piva }
74*94c4a1e1SFrank Piva 
75*94c4a1e1SFrank Piva using co_handle_type = std::coroutine_handle<>;
76*94c4a1e1SFrank Piva struct co_io_job {
77*94c4a1e1SFrank Piva     struct promise_type {
get_return_objectco_io_job::promise_type78*94c4a1e1SFrank Piva         co_io_job get_return_object() {
79*94c4a1e1SFrank Piva             return {std::coroutine_handle<promise_type>::from_promise(*this)};
80*94c4a1e1SFrank Piva         }
initial_suspendco_io_job::promise_type81*94c4a1e1SFrank Piva         std::suspend_never initial_suspend() {
82*94c4a1e1SFrank Piva             return {};
83*94c4a1e1SFrank Piva         }
final_suspendco_io_job::promise_type84*94c4a1e1SFrank Piva         std::suspend_never final_suspend() noexcept {
85*94c4a1e1SFrank Piva             return {};
86*94c4a1e1SFrank Piva         }
return_voidco_io_job::promise_type87*94c4a1e1SFrank Piva         void return_void() {}
unhandled_exceptionco_io_job::promise_type88*94c4a1e1SFrank Piva         void unhandled_exception() {}
89*94c4a1e1SFrank Piva     };
90*94c4a1e1SFrank Piva 
91*94c4a1e1SFrank Piva     co_handle_type coro;
92*94c4a1e1SFrank Piva 
co_io_jobco_io_job93*94c4a1e1SFrank Piva     co_io_job(co_handle_type h): coro(h) {}
94*94c4a1e1SFrank Piva 
co_handle_typeco_io_job95*94c4a1e1SFrank Piva     operator co_handle_type() const { return coro; }
96*94c4a1e1SFrank Piva };
97*94c4a1e1SFrank Piva 
98*94c4a1e1SFrank Piva struct ublk_io_tgt {
99*94c4a1e1SFrank Piva 	co_handle_type co;
100*94c4a1e1SFrank Piva 	const struct io_uring_cqe *tgt_io_cqe;
101*94c4a1e1SFrank Piva 	int queued_tgt_io;	/* obsolete */
102*94c4a1e1SFrank Piva };
103*94c4a1e1SFrank Piva 
__ublk_get_io_tgt_data(const struct ublk_io_data * io)104*94c4a1e1SFrank Piva static inline struct ublk_io_tgt *__ublk_get_io_tgt_data(const struct ublk_io_data *io)
105*94c4a1e1SFrank Piva {
106*94c4a1e1SFrank Piva 	return (struct ublk_io_tgt *)io->private_data;
107*94c4a1e1SFrank Piva }
108*94c4a1e1SFrank Piva 
ublk_get_io_tgt_data(const struct ublksrv_queue * q,int tag)109*94c4a1e1SFrank Piva static inline struct ublk_io_tgt *ublk_get_io_tgt_data(
110*94c4a1e1SFrank Piva 		const struct ublksrv_queue *q, int tag)
111*94c4a1e1SFrank Piva {
112*94c4a1e1SFrank Piva 	return (struct ublk_io_tgt *)ublksrv_io_private_data(q, tag);
113*94c4a1e1SFrank Piva }
114*94c4a1e1SFrank Piva 
ublksrv_tgt_set_io_data_size(struct ublksrv_tgt_info * tgt)115*94c4a1e1SFrank Piva static inline void ublksrv_tgt_set_io_data_size(struct ublksrv_tgt_info *tgt)
116*94c4a1e1SFrank Piva {
117*94c4a1e1SFrank Piva 	tgt->io_data_size = sizeof(struct ublk_io_tgt);
118*94c4a1e1SFrank Piva }
119*94c4a1e1SFrank Piva 
120*94c4a1e1SFrank Piva //static_assert(sizeof(struct ublk_io_tgt) == sizeof(struct ublk_io), "ublk_io is defined as wrong");
121*94c4a1e1SFrank Piva 
122*94c4a1e1SFrank Piva enum {
123*94c4a1e1SFrank Piva 	/* evaluate communication cost, ublksrv_null vs /dev/nullb0 */
124*94c4a1e1SFrank Piva 	UBLKSRV_TGT_TYPE_NULL,
125*94c4a1e1SFrank Piva 
126*94c4a1e1SFrank Piva 	/* ublksrv_loop vs. /dev/loop */
127*94c4a1e1SFrank Piva 	UBLKSRV_TGT_TYPE_LOOP,
128*94c4a1e1SFrank Piva 
129*94c4a1e1SFrank Piva 	UBLKSRV_TGT_TYPE_QCOW2,
130*94c4a1e1SFrank Piva 
131*94c4a1e1SFrank Piva 	UBLKSRV_TGT_TYPE_NBD,
132*94c4a1e1SFrank Piva 
133*94c4a1e1SFrank Piva 	UBLKSRV_TGT_TYPE_MAX = 256,
134*94c4a1e1SFrank Piva };
135*94c4a1e1SFrank Piva extern int ublksrv_register_tgt_type(struct ublksrv_tgt_type *type);
136*94c4a1e1SFrank Piva extern void ublksrv_unregister_tgt_type(struct ublksrv_tgt_type *type);
137*94c4a1e1SFrank Piva 
138*94c4a1e1SFrank Piva enum {
139*94c4a1e1SFrank Piva 	UBLK_UNIQUE_TAG_BITS = 16,
140*94c4a1e1SFrank Piva 	UBLK_UNIQUE_TAG_MASK = (1 << UBLK_UNIQUE_TAG_BITS) - 1,
141*94c4a1e1SFrank Piva };
142*94c4a1e1SFrank Piva 
ublk_unique_tag(unsigned short hwq,unsigned short tag)143*94c4a1e1SFrank Piva static inline unsigned int ublk_unique_tag(unsigned short hwq,
144*94c4a1e1SFrank Piva 		unsigned short tag)
145*94c4a1e1SFrank Piva {
146*94c4a1e1SFrank Piva 	return (hwq << UBLK_UNIQUE_TAG_BITS) | (tag & UBLK_UNIQUE_TAG_MASK);
147*94c4a1e1SFrank Piva }
148*94c4a1e1SFrank Piva 
ublk_unique_tag_to_hwq(unsigned int unique_tag)149*94c4a1e1SFrank Piva static inline unsigned short ublk_unique_tag_to_hwq(unsigned int unique_tag)
150*94c4a1e1SFrank Piva {
151*94c4a1e1SFrank Piva         return unique_tag >> UBLK_UNIQUE_TAG_BITS;
152*94c4a1e1SFrank Piva }
153*94c4a1e1SFrank Piva 
ublk_unique_tag_to_tag(unsigned int unique_tag)154*94c4a1e1SFrank Piva static inline unsigned short ublk_unique_tag_to_tag(unsigned int unique_tag)
155*94c4a1e1SFrank Piva {
156*94c4a1e1SFrank Piva         return unique_tag & UBLK_UNIQUE_TAG_MASK;
157*94c4a1e1SFrank Piva }
158*94c4a1e1SFrank Piva 
ublk_param_is_valid(const struct ublk_params * p)159*94c4a1e1SFrank Piva static inline bool ublk_param_is_valid(const struct ublk_params *p)
160*94c4a1e1SFrank Piva {
161*94c4a1e1SFrank Piva 	if (p->basic.logical_bs_shift < 9 || p->basic.physical_bs_shift > 12)
162*94c4a1e1SFrank Piva 		return false;
163*94c4a1e1SFrank Piva 	if (p->basic.logical_bs_shift > p->basic.physical_bs_shift)
164*94c4a1e1SFrank Piva 		return false;
165*94c4a1e1SFrank Piva 	return true;
166*94c4a1e1SFrank Piva }
167*94c4a1e1SFrank Piva 
168*94c4a1e1SFrank Piva int ublk_json_write_tgt_str(struct ublksrv_dev *dev, char **jbuf,
169*94c4a1e1SFrank Piva 		int *len, const char *name, const char *val);
170*94c4a1e1SFrank Piva int ublk_json_write_tgt_long(struct ublksrv_dev *dev, char **jbuf,
171*94c4a1e1SFrank Piva 		int *len, const char *name, long val);
172*94c4a1e1SFrank Piva int ublk_json_write_tgt_ulong(struct ublksrv_dev *dev, char **jbuf,
173*94c4a1e1SFrank Piva 		int *len, const char *name, unsigned long val);
174*94c4a1e1SFrank Piva int ublk_json_write_dev_info(struct ublksrv_dev *dev, char **jbuf, int *len);
175*94c4a1e1SFrank Piva int ublk_json_write_params(struct ublksrv_dev *dev, char **jbuf, int *len,
176*94c4a1e1SFrank Piva 		const struct ublk_params *p);
177*94c4a1e1SFrank Piva int ublk_json_write_target_base(struct ublksrv_dev *dev, char **jbuf, int *len,
178*94c4a1e1SFrank Piva 		const struct ublksrv_tgt_base_json *tgt);
179*94c4a1e1SFrank Piva 
ublk_get_sqe_pair(struct io_uring * r,struct io_uring_sqe ** sqe,struct io_uring_sqe ** sqe2)180*94c4a1e1SFrank Piva static inline void ublk_get_sqe_pair(struct io_uring *r,
181*94c4a1e1SFrank Piva 		struct io_uring_sqe **sqe, struct io_uring_sqe **sqe2)
182*94c4a1e1SFrank Piva {
183*94c4a1e1SFrank Piva 	unsigned left = io_uring_sq_space_left(r);
184*94c4a1e1SFrank Piva 
185*94c4a1e1SFrank Piva 	if (left < 2)
186*94c4a1e1SFrank Piva 		io_uring_submit(r);
187*94c4a1e1SFrank Piva 	*sqe = io_uring_get_sqe(r);
188*94c4a1e1SFrank Piva 	if (sqe2)
189*94c4a1e1SFrank Piva 		*sqe2 = io_uring_get_sqe(r);
190*94c4a1e1SFrank Piva }
191*94c4a1e1SFrank Piva 
192*94c4a1e1SFrank Piva #endif
193