xref: /spdk/lib/vhost/vhost_rpc.c (revision f8abbede89d30584d2a4f8427b13896f8591b873)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/log.h"
9 #include "spdk/rpc.h"
10 #include "spdk/util.h"
11 #include "spdk/string.h"
12 #include "spdk/env.h"
13 #include "spdk/log.h"
14 #include "spdk/scsi.h"
15 #include "spdk/vhost.h"
16 #include "vhost_internal.h"
17 #include "spdk/bdev.h"
18 
19 struct rpc_vhost_scsi_ctrlr {
20 	char *ctrlr;
21 	char *cpumask;
22 	bool delay;
23 };
24 
25 static void
26 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
27 {
28 	free(req->ctrlr);
29 	free(req->cpumask);
30 }
31 
32 static const struct spdk_json_object_decoder rpc_vhost_create_scsi_ctrlr[] = {
33 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
34 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
35 	{"delay", offsetof(struct rpc_vhost_scsi_ctrlr, delay), spdk_json_decode_bool, true},
36 };
37 
38 static void
39 rpc_vhost_create_scsi_controller(struct spdk_jsonrpc_request *request,
40 				 const struct spdk_json_val *params)
41 {
42 	struct rpc_vhost_scsi_ctrlr req = {0};
43 	int rc;
44 
45 	if (spdk_json_decode_object(params, rpc_vhost_create_scsi_ctrlr,
46 				    SPDK_COUNTOF(rpc_vhost_create_scsi_ctrlr),
47 				    &req)) {
48 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
49 		rc = -EINVAL;
50 		goto invalid;
51 	}
52 
53 	if (req.delay) {
54 		rc = spdk_vhost_scsi_dev_construct_no_start(req.ctrlr, req.cpumask);
55 	} else {
56 		rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask);
57 	}
58 	if (rc < 0) {
59 		goto invalid;
60 	}
61 
62 	free_rpc_vhost_scsi_ctrlr(&req);
63 
64 	spdk_jsonrpc_send_bool_response(request, true);
65 	return;
66 
67 invalid:
68 	free_rpc_vhost_scsi_ctrlr(&req);
69 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
70 					 spdk_strerror(-rc));
71 }
72 SPDK_RPC_REGISTER("vhost_create_scsi_controller", rpc_vhost_create_scsi_controller,
73 		  SPDK_RPC_RUNTIME)
74 
75 struct rpc_start_vhost_scsi_ctrlr {
76 	char *ctrlr;
77 };
78 
79 static void
80 free_rpc_start_vhost_scsi_ctrlr(struct rpc_start_vhost_scsi_ctrlr *req)
81 {
82 	free(req->ctrlr);
83 }
84 
85 static const struct spdk_json_object_decoder rpc_start_vhost_scsi_ctrlr_decoder[] = {
86 	{"ctrlr", offsetof(struct rpc_start_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
87 };
88 
89 static void
90 rpc_vhost_start_scsi_controller(struct spdk_jsonrpc_request *request,
91 				const struct spdk_json_val *params)
92 {
93 	struct rpc_start_vhost_scsi_ctrlr req = {0};
94 	int rc;
95 
96 	if (spdk_json_decode_object(params, rpc_start_vhost_scsi_ctrlr_decoder,
97 				    SPDK_COUNTOF(rpc_start_vhost_scsi_ctrlr_decoder),
98 				    &req)) {
99 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
100 		rc = -EINVAL;
101 		goto invalid;
102 	}
103 
104 	rc = vhost_scsi_controller_start(req.ctrlr);
105 	if (rc < 0) {
106 		goto invalid;
107 	}
108 
109 	free_rpc_start_vhost_scsi_ctrlr(&req);
110 
111 	spdk_jsonrpc_send_bool_response(request, true);
112 	return;
113 
114 invalid:
115 	free_rpc_start_vhost_scsi_ctrlr(&req);
116 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
117 					 spdk_strerror(-rc));
118 }
119 SPDK_RPC_REGISTER("vhost_start_scsi_controller", rpc_vhost_start_scsi_controller,
120 		  SPDK_RPC_RUNTIME)
121 
122 struct rpc_vhost_scsi_ctrlr_add_target {
123 	char *ctrlr;
124 	int32_t scsi_target_num;
125 	char *bdev_name;
126 };
127 
128 static void
129 free_rpc_vhost_scsi_ctrlr_add_target(struct rpc_vhost_scsi_ctrlr_add_target *req)
130 {
131 	free(req->ctrlr);
132 	free(req->bdev_name);
133 }
134 
135 static const struct spdk_json_object_decoder rpc_vhost_scsi_ctrlr_add_target[] = {
136 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, ctrlr), spdk_json_decode_string },
137 	{"scsi_target_num", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, scsi_target_num), spdk_json_decode_int32},
138 	{"bdev_name", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, bdev_name), spdk_json_decode_string },
139 };
140 
141 static void
142 rpc_vhost_scsi_controller_add_target(struct spdk_jsonrpc_request *request,
143 				     const struct spdk_json_val *params)
144 {
145 	struct rpc_vhost_scsi_ctrlr_add_target req = {0};
146 	struct spdk_json_write_ctx *w;
147 	struct spdk_vhost_dev *vdev;
148 	int rc;
149 
150 	if (spdk_json_decode_object(params, rpc_vhost_scsi_ctrlr_add_target,
151 				    SPDK_COUNTOF(rpc_vhost_scsi_ctrlr_add_target),
152 				    &req)) {
153 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
154 		rc = -EINVAL;
155 		goto invalid;
156 	}
157 
158 	spdk_vhost_lock();
159 	vdev = spdk_vhost_dev_find(req.ctrlr);
160 	if (vdev == NULL) {
161 		spdk_vhost_unlock();
162 		rc = -ENODEV;
163 		goto invalid;
164 	}
165 
166 	rc = spdk_vhost_scsi_dev_add_tgt(vdev, req.scsi_target_num, req.bdev_name);
167 	spdk_vhost_unlock();
168 	if (rc < 0) {
169 		goto invalid;
170 	}
171 
172 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
173 
174 	w = spdk_jsonrpc_begin_result(request);
175 	spdk_json_write_int32(w, rc);
176 	spdk_jsonrpc_end_result(request, w);
177 	return;
178 
179 invalid:
180 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
181 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
182 					 spdk_strerror(-rc));
183 }
184 SPDK_RPC_REGISTER("vhost_scsi_controller_add_target", rpc_vhost_scsi_controller_add_target,
185 		  SPDK_RPC_RUNTIME)
186 
187 struct rpc_remove_vhost_scsi_ctrlr_target {
188 	char *ctrlr;
189 	uint32_t scsi_target_num;
190 };
191 
192 static void
193 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req)
194 {
195 	free(req->ctrlr);
196 }
197 
198 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = {
199 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string },
200 	{"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32},
201 };
202 
203 static int
204 rpc_vhost_scsi_controller_remove_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
205 {
206 	struct spdk_jsonrpc_request *request = arg;
207 
208 	spdk_jsonrpc_send_bool_response(request, true);
209 	return 0;
210 }
211 
212 static void
213 rpc_vhost_scsi_controller_remove_target(struct spdk_jsonrpc_request *request,
214 					const struct spdk_json_val *params)
215 {
216 	struct rpc_remove_vhost_scsi_ctrlr_target req = {0};
217 	struct spdk_vhost_dev *vdev;
218 	int rc;
219 
220 	if (spdk_json_decode_object(params, rpc_vhost_remove_target,
221 				    SPDK_COUNTOF(rpc_vhost_remove_target),
222 				    &req)) {
223 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
224 		rc = -EINVAL;
225 		goto invalid;
226 	}
227 
228 	spdk_vhost_lock();
229 	vdev = spdk_vhost_dev_find(req.ctrlr);
230 	if (vdev == NULL) {
231 		spdk_vhost_unlock();
232 		rc = -ENODEV;
233 		goto invalid;
234 	}
235 
236 	rc = spdk_vhost_scsi_dev_remove_tgt(vdev, req.scsi_target_num,
237 					    rpc_vhost_scsi_controller_remove_target_finish_cb,
238 					    request);
239 	spdk_vhost_unlock();
240 	if (rc < 0) {
241 		goto invalid;
242 	}
243 
244 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
245 	return;
246 
247 invalid:
248 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
249 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
250 					 spdk_strerror(-rc));
251 }
252 
253 SPDK_RPC_REGISTER("vhost_scsi_controller_remove_target",
254 		  rpc_vhost_scsi_controller_remove_target, SPDK_RPC_RUNTIME)
255 
256 struct rpc_vhost_blk_ctrlr {
257 	char *ctrlr;
258 	char *dev_name;
259 	char *cpumask;
260 	char *transport;
261 };
262 
263 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
264 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
265 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
266 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
267 	{"transport", offsetof(struct rpc_vhost_blk_ctrlr, transport), spdk_json_decode_string, true},
268 };
269 
270 static void
271 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
272 {
273 	free(req->ctrlr);
274 	free(req->dev_name);
275 	free(req->cpumask);
276 	free(req->transport);
277 }
278 
279 static void
280 rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
281 				const struct spdk_json_val *params)
282 {
283 	struct rpc_vhost_blk_ctrlr req = {0};
284 	int rc;
285 
286 	if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk_ctrlr,
287 					    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
288 					    &req)) {
289 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
290 		rc = -EINVAL;
291 		goto invalid;
292 	}
293 
294 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.transport, params);
295 	if (rc < 0) {
296 		goto invalid;
297 	}
298 
299 	free_rpc_vhost_blk_ctrlr(&req);
300 
301 	spdk_jsonrpc_send_bool_response(request, true);
302 	return;
303 
304 invalid:
305 	free_rpc_vhost_blk_ctrlr(&req);
306 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
307 					 spdk_strerror(-rc));
308 
309 }
310 SPDK_RPC_REGISTER("vhost_create_blk_controller", rpc_vhost_create_blk_controller,
311 		  SPDK_RPC_RUNTIME)
312 
313 struct rpc_delete_vhost_ctrlr {
314 	char *ctrlr;
315 };
316 
317 static const struct spdk_json_object_decoder rpc_delete_vhost_ctrlr_decoder[] = {
318 	{"ctrlr", offsetof(struct rpc_delete_vhost_ctrlr, ctrlr), spdk_json_decode_string },
319 };
320 
321 static void
322 free_rpc_delete_vhost_ctrlr(struct rpc_delete_vhost_ctrlr *req)
323 {
324 	free(req->ctrlr);
325 }
326 
327 static void
328 rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request,
329 			    const struct spdk_json_val *params)
330 {
331 	struct rpc_delete_vhost_ctrlr req = {0};
332 	struct spdk_vhost_dev *vdev;
333 	int rc;
334 
335 	if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder,
336 				    SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) {
337 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
338 		rc = -EINVAL;
339 		goto invalid;
340 	}
341 
342 	spdk_vhost_lock();
343 	vdev = spdk_vhost_dev_find(req.ctrlr);
344 	if (vdev == NULL) {
345 		spdk_vhost_unlock();
346 		rc = -ENODEV;
347 		goto invalid;
348 	}
349 	spdk_vhost_unlock();
350 
351 	rc = spdk_vhost_dev_remove(vdev);
352 	if (rc < 0) {
353 		goto invalid;
354 	}
355 
356 	free_rpc_delete_vhost_ctrlr(&req);
357 
358 	spdk_jsonrpc_send_bool_response(request, true);
359 	return;
360 
361 invalid:
362 	free_rpc_delete_vhost_ctrlr(&req);
363 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
364 					 spdk_strerror(-rc));
365 
366 }
367 SPDK_RPC_REGISTER("vhost_delete_controller", rpc_vhost_delete_controller, SPDK_RPC_RUNTIME)
368 
369 struct rpc_get_vhost_ctrlrs {
370 	char *name;
371 };
372 
373 static void
374 _rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
375 {
376 	uint32_t delay_base_us, iops_threshold;
377 
378 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
379 
380 	spdk_json_write_object_begin(w);
381 
382 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
383 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s",
384 					 spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
385 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
386 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
387 	spdk_json_write_named_string(w, "socket", vdev->path);
388 	spdk_json_write_named_array_begin(w, "sessions");
389 	vhost_session_info_json(vdev, w);
390 	spdk_json_write_array_end(w);
391 
392 	spdk_json_write_named_object_begin(w, "backend_specific");
393 	vhost_dump_info_json(vdev, w);
394 	spdk_json_write_object_end(w);
395 
396 	spdk_json_write_object_end(w);
397 }
398 
399 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
400 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
401 };
402 
403 static void
404 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req)
405 {
406 	free(req->name);
407 }
408 
409 static void
410 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request,
411 			  const struct spdk_json_val *params)
412 {
413 	struct rpc_get_vhost_ctrlrs req = {0};
414 	struct spdk_json_write_ctx *w;
415 	struct spdk_vhost_dev *vdev;
416 	int rc;
417 
418 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
419 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) {
420 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
421 		rc = -EINVAL;
422 		goto invalid;
423 	}
424 
425 	spdk_vhost_lock();
426 	if (req.name != NULL) {
427 		vdev = spdk_vhost_dev_find(req.name);
428 		if (vdev == NULL) {
429 			spdk_vhost_unlock();
430 			rc = -ENODEV;
431 			goto invalid;
432 		}
433 
434 		free_rpc_get_vhost_ctrlrs(&req);
435 
436 		w = spdk_jsonrpc_begin_result(request);
437 		spdk_json_write_array_begin(w);
438 
439 		_rpc_get_vhost_controller(w, vdev);
440 		spdk_vhost_unlock();
441 
442 		spdk_json_write_array_end(w);
443 		spdk_jsonrpc_end_result(request, w);
444 		return;
445 	}
446 
447 	free_rpc_get_vhost_ctrlrs(&req);
448 
449 	w = spdk_jsonrpc_begin_result(request);
450 	spdk_json_write_array_begin(w);
451 
452 	vdev = spdk_vhost_dev_next(NULL);
453 	while (vdev != NULL) {
454 		_rpc_get_vhost_controller(w, vdev);
455 		vdev = spdk_vhost_dev_next(vdev);
456 	}
457 	spdk_vhost_unlock();
458 
459 	spdk_json_write_array_end(w);
460 	spdk_jsonrpc_end_result(request, w);
461 	return;
462 
463 invalid:
464 	free_rpc_get_vhost_ctrlrs(&req);
465 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
466 					 spdk_strerror(-rc));
467 }
468 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME)
469 
470 
471 struct rpc_vhost_ctrlr_coalescing {
472 	char *ctrlr;
473 	uint32_t delay_base_us;
474 	uint32_t iops_threshold;
475 };
476 
477 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
478 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
479 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
480 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
481 };
482 
483 static void
484 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
485 {
486 	free(req->ctrlr);
487 }
488 
489 static void
490 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request,
491 				    const struct spdk_json_val *params)
492 {
493 	struct rpc_vhost_ctrlr_coalescing req = {0};
494 	struct spdk_vhost_dev *vdev;
495 	int rc;
496 
497 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
498 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) {
499 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
500 		rc = -EINVAL;
501 		goto invalid;
502 	}
503 
504 	spdk_vhost_lock();
505 	vdev = spdk_vhost_dev_find(req.ctrlr);
506 	if (vdev == NULL) {
507 		spdk_vhost_unlock();
508 		rc = -ENODEV;
509 		goto invalid;
510 	}
511 
512 	rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold);
513 	spdk_vhost_unlock();
514 	if (rc) {
515 		goto invalid;
516 	}
517 
518 	free_rpc_set_vhost_controllers_event_coalescing(&req);
519 
520 	spdk_jsonrpc_send_bool_response(request, true);
521 	return;
522 
523 invalid:
524 	free_rpc_set_vhost_controllers_event_coalescing(&req);
525 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
526 					 spdk_strerror(-rc));
527 }
528 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
529 		  SPDK_RPC_RUNTIME)
530 
531 struct rpc_get_transport {
532 	char *name;
533 };
534 
535 static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = {
536 	{"name", offsetof(struct rpc_get_transport, name), spdk_json_decode_string, true},
537 };
538 
539 static void
540 rpc_virtio_blk_get_transports(struct spdk_jsonrpc_request *request,
541 			      const struct spdk_json_val *params)
542 {
543 	struct rpc_get_transport req = { 0 };
544 	struct spdk_json_write_ctx *w;
545 	struct spdk_virtio_blk_transport *transport = NULL;
546 
547 	if (params) {
548 		if (spdk_json_decode_object(params, rpc_get_transport_decoders,
549 					    SPDK_COUNTOF(rpc_get_transport_decoders),
550 					    &req)) {
551 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
552 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
553 			return;
554 		}
555 	}
556 
557 	if (req.name) {
558 		transport = virtio_blk_tgt_get_transport(req.name);
559 		if (transport == NULL) {
560 			SPDK_ERRLOG("transport '%s' does not exist\n", req.name);
561 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
562 			free(req.name);
563 			return;
564 		}
565 	}
566 
567 	w = spdk_jsonrpc_begin_result(request);
568 	spdk_json_write_array_begin(w);
569 
570 	if (transport) {
571 		virtio_blk_transport_dump_opts(transport, w);
572 	} else {
573 		for (transport = virtio_blk_transport_get_first(); transport != NULL;
574 		     transport = virtio_blk_transport_get_next(transport)) {
575 			virtio_blk_transport_dump_opts(transport, w);
576 		}
577 	}
578 
579 	spdk_json_write_array_end(w);
580 	spdk_jsonrpc_end_result(request, w);
581 	free(req.name);
582 }
583 SPDK_RPC_REGISTER("virtio_blk_get_transports", rpc_virtio_blk_get_transports, SPDK_RPC_RUNTIME)
584 
585 struct rpc_virtio_blk_create_transport {
586 	char *name;
587 };
588 
589 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = {
590 	{"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string},
591 };
592 
593 static void
594 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req)
595 {
596 	free(req->name);
597 }
598 
599 static void
600 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request,
601 				const struct spdk_json_val *params)
602 {
603 	struct rpc_virtio_blk_create_transport req = {0};
604 	int rc;
605 
606 	if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport,
607 					    SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) {
608 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
609 		rc = -EINVAL;
610 		goto invalid;
611 	}
612 
613 	spdk_vhost_lock();
614 	rc = virtio_blk_transport_create(req.name, params);
615 	spdk_vhost_unlock();
616 	if (rc != 0) {
617 		goto invalid;
618 	}
619 
620 	free_rpc_virtio_blk_create_transport(&req);
621 	spdk_jsonrpc_send_bool_response(request, true);
622 	return;
623 
624 invalid:
625 	free_rpc_virtio_blk_create_transport(&req);
626 	spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
627 }
628 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport,
629 		  SPDK_RPC_RUNTIME)
630 
631 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc)
632