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