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