1 // SPDX-License-Identifier: MIT or LGPL-2.1-only
2
3 #include <config.h>
4
5 #include <iostream>
6 #include "nlohmann/json.hpp"
7 #include "ublksrv_priv.h"
8
9 #define parse_json(j, jbuf) \
10 try { \
11 j = json::parse(std::string(jbuf)); \
12 } catch (json::parse_error& ex) { \
13 std::cerr << "parse error at byte " << ex.byte << std::endl; \
14 return -EINVAL; \
15 } \
16
17 using json = nlohmann::json;
18
dump_json_to_buf(json & j,char * jbuf,int len)19 static inline int dump_json_to_buf(json &j, char *jbuf, int len)
20 {
21 std::string s;
22 int j_len;
23
24 s = j.dump();
25 j_len = s.length();
26 if (j_len < len) {
27 strcpy(jbuf, s.c_str());
28 return j_len;
29 }
30 return -EINVAL;
31 }
32
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ublksrv_ctrl_dev_info,nr_hw_queues,queue_depth,state,pad0,max_io_buf_bytes,dev_id,ublksrv_pid,pad1,flags,ublksrv_flags,owner_uid,owner_gid,reserved1,reserved2)33 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ublksrv_ctrl_dev_info,
34 nr_hw_queues,
35 queue_depth,
36 state,
37 pad0,
38 max_io_buf_bytes,
39 dev_id,
40 ublksrv_pid,
41 pad1,
42 flags,
43 ublksrv_flags,
44 owner_uid,
45 owner_gid,
46 reserved1,
47 reserved2)
48
49 /*
50 * build one json string with dev_info head, and result is stored
51 * in 'buf'.
52 */
53 int ublksrv_json_write_dev_info(const struct ublksrv_ctrl_dev *cdev,
54 char *jbuf, int len)
55 {
56 const struct ublksrv_ctrl_dev_info *info = &cdev->dev_info;
57 json j_info = *info;
58 json j;
59
60 j["dev_info"] = j_info;
61
62 return dump_json_to_buf(j, jbuf, len);
63 }
64
65 /* Fill 'info' from the json string pointed by 'json_buf' */
ublksrv_json_read_dev_info(const char * jbuf,struct ublksrv_ctrl_dev_info * info)66 int ublksrv_json_read_dev_info(const char *jbuf,
67 struct ublksrv_ctrl_dev_info *info)
68 {
69 json j;
70
71 parse_json(j, jbuf);
72
73 if (!j.contains("dev_info"))
74 return -EINVAL;
75
76 auto sj = j["dev_info"];
77
78 *info = sj.get<struct ublksrv_ctrl_dev_info>();
79
80 return 0;
81 }
82
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_param_basic,attrs,logical_bs_shift,physical_bs_shift,io_opt_shift,io_min_shift,max_sectors,chunk_sectors,dev_sectors,virt_boundary_mask)83 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_param_basic,
84 attrs,
85 logical_bs_shift,
86 physical_bs_shift,
87 io_opt_shift,
88 io_min_shift,
89 max_sectors,
90 chunk_sectors,
91 dev_sectors,
92 virt_boundary_mask)
93
94 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_param_discard,
95 discard_alignment,
96 discard_granularity,
97 max_discard_sectors,
98 max_write_zeroes_sectors,
99 max_discard_segments,
100 reserved0)
101 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(struct ublk_params,
102 len, types, basic, discard)
103
104 int ublksrv_json_write_params(const struct ublk_params *p,
105 char *jbuf, int len)
106 {
107 json j;
108 std::string s;
109
110 parse_json(j, jbuf);
111
112 j["params"] = *p;
113
114 return dump_json_to_buf(j, jbuf, len);
115 }
116
ublksrv_json_read_params(struct ublk_params * p,const char * jbuf)117 int ublksrv_json_read_params(struct ublk_params *p,
118 const char *jbuf)
119 {
120 json j, sj;
121 std::string s;
122
123 parse_json(j, jbuf);
124
125 if (!j.contains("params"))
126 return -EINVAL;
127
128 *p = j["params"];
129
130 return 0;
131 }
132
ublksrv_json_dump_params(const char * jbuf)133 int ublksrv_json_dump_params(const char *jbuf)
134 {
135 json j;
136 std::string s;
137
138 parse_json(j, jbuf);
139
140 if (!j.contains("params"))
141 return -EINVAL;
142
143 std::cout << std::setw(4) << j["params"] << '\n';
144
145 return 0;
146 }
147
ublksrv_json_read_target_str_info(const char * jbuf,int len,const char * name,char * val)148 int ublksrv_json_read_target_str_info(const char *jbuf, int len,
149 const char *name, char *val)
150 {
151 json j;
152 std::string s;
153
154 parse_json(j, jbuf);
155
156 if (!j.contains("target"))
157 return -EINVAL;
158
159 auto tj = j["target"];
160
161 if (!tj.contains(name))
162 return -EINVAL;
163
164 std::string str = tj[std::string(name)];
165 if (str.length() < (unsigned)len) {
166 strcpy(val, str.c_str());
167 return 0;
168 }
169
170 return -EINVAL;
171 }
172
ublksrv_json_read_target_ulong_info(const char * jbuf,const char * name,long * val)173 int ublksrv_json_read_target_ulong_info(const char *jbuf,
174 const char *name, long *val)
175 {
176 json j;
177 std::string s;
178
179 parse_json(j, jbuf);
180
181 if (!j.contains("target"))
182 return -EINVAL;
183
184 auto tj = j["target"];
185
186 if (!tj.contains(name))
187 return -EINVAL;
188
189 *val = tj[std::string(name)];
190
191 return 0;
192 }
193
ublksrv_json_write_target_str_info(char * jbuf,int len,const char * name,const char * val)194 int ublksrv_json_write_target_str_info(char *jbuf, int len,
195 const char *name, const char *val)
196 {
197 json j;
198 std::string s;
199
200 parse_json(j, jbuf);
201
202 j["target"][std::string(name)] = val;;
203
204 return dump_json_to_buf(j, jbuf, len);
205 }
206
ublksrv_json_write_target_long_info(char * jbuf,int len,const char * name,long val)207 int ublksrv_json_write_target_long_info(char *jbuf, int len,
208 const char *name, long val)
209 {
210 json j;
211 std::string s;
212
213 parse_json(j, jbuf);
214
215 j["target"][std::string(name)] = val;;
216
217 return dump_json_to_buf(j, jbuf, len);
218 }
219
ublksrv_json_write_target_ulong_info(char * jbuf,int len,const char * name,unsigned long val)220 int ublksrv_json_write_target_ulong_info(char *jbuf, int len, const char *name,
221 unsigned long val)
222 {
223 json j;
224 std::string s;
225
226 parse_json(j, jbuf);
227
228 j["target"][std::string(name)] = val;;
229
230 return dump_json_to_buf(j, jbuf, len);
231 }
232
ublksrv_json_write_target_base_info(char * jbuf,int len,const struct ublksrv_tgt_base_json * tgt)233 int ublksrv_json_write_target_base_info(char *jbuf, int len,
234 const struct ublksrv_tgt_base_json *tgt)
235 {
236 json j;
237 std::string s;
238
239 parse_json(j, jbuf);
240
241 j["target"]["name"] = tgt->name;
242 j["target"]["type"] = tgt->type;
243 j["target"]["dev_size"] = tgt->dev_size;
244
245 return dump_json_to_buf(j, jbuf, len);
246 }
247
ublksrv_json_read_target_base_info(const char * jbuf,struct ublksrv_tgt_base_json * tgt)248 int ublksrv_json_read_target_base_info(const char *jbuf,
249 struct ublksrv_tgt_base_json *tgt)
250 {
251 json j;
252 std::string s;
253
254 parse_json(j, jbuf);
255
256 if (!j.contains("target"))
257 return -EINVAL;
258
259 auto tj = j["target"];
260
261 if (!tj.contains("name") || !tj.contains("type") ||
262 !tj.contains("dev_size"))
263 return -EINVAL;
264
265 std::string str = tj["name"];
266 if (str.length() >= UBLKSRV_TGT_NAME_MAX_LEN)
267 return -EINVAL;
268 strcpy(tgt->name, str.c_str());
269 tgt->type = tj["type"];
270 tgt->dev_size = tj["dev_size"];
271
272 return 0;
273 }
274
ublksrv_json_read_target_info(const char * jbuf,char * tgt_buf,int len)275 int ublksrv_json_read_target_info(const char *jbuf, char *tgt_buf, int len)
276 {
277 json j;
278
279 parse_json(j, jbuf);
280
281 if (j.contains("target")) {
282 auto tj = j["target"];
283
284 return dump_json_to_buf(tj, tgt_buf, len);
285 }
286 return 0;
287 }
288
ublksrv_json_write_queue_info(const struct ublksrv_ctrl_dev * cdev,char * jbuf,int len,int qid,int ubq_daemon_tid)289 int ublksrv_json_write_queue_info(const struct ublksrv_ctrl_dev *cdev,
290 char *jbuf, int len, int qid, int ubq_daemon_tid)
291 {
292 json j;
293 std::string s;
294 char name[16];
295 char cpus[4096];
296 cpu_set_t *cpuset = ublksrv_get_queue_affinity(cdev, qid);
297
298 parse_json(j, jbuf);
299
300 snprintf(name, 16, "%d", qid);
301
302 ublksrv_build_cpu_str(cpus, 512, cpuset);
303
304 j["queues"][std::string(name)]["qid"] = qid;
305 j["queues"][std::string(name)]["tid"] = ubq_daemon_tid;
306 j["queues"][std::string(name)]["affinity"] = cpus;
307
308 return dump_json_to_buf(j, jbuf, len);
309 }
310
ublksrv_json_read_queue_info(const char * jbuf,int qid,unsigned * tid,char * affinity_buf,int len)311 int ublksrv_json_read_queue_info(const char *jbuf, int qid, unsigned *tid,
312 char *affinity_buf, int len)
313 {
314 json j;
315 char name[16];
316 std::string str;
317
318 parse_json(j, jbuf);
319
320 snprintf(name, 16, "%d", qid);
321
322 auto qj = j["queues"][name];
323
324 *tid = qj["tid"];
325 str = qj["affinity"];
326
327 if (str.length() < (unsigned)len) {
328 strcpy(affinity_buf, str.c_str());
329 return 0;
330 }
331 return -EINVAL;
332 }
333
ublksrv_json_dump(const char * jbuf)334 void ublksrv_json_dump(const char *jbuf)
335 {
336 auto j = json::parse(jbuf);
337
338 std::cout << std::setw(4) << j << '\n';
339 }
340
341 /* the end null character is always counted */
ublksrv_json_get_length(const char * jbuf)342 int ublksrv_json_get_length(const char *jbuf)
343 {
344 auto j = json::parse(jbuf);
345
346 return j.dump().length() + 1;
347 }
348