xref: /aosp_15_r20/external/ublksrv/lib/ublksrv_json.cpp (revision 94c4a1e103eb1715230460aab379dff275992c20)
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