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