xref: /spdk/lib/vhost/vhost_rpc.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
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 struct vhost_delete_ctrlr_context {
327 	struct spdk_jsonrpc_request *request;
328 	const struct spdk_json_val *params;
329 };
330 
331 static void _rpc_vhost_delete_controller(void *arg);
332 
333 static void
334 rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request,
335 			    const struct spdk_json_val *params)
336 {
337 	struct rpc_delete_vhost_ctrlr req = {0};
338 	struct spdk_vhost_dev *vdev;
339 	int rc;
340 
341 	if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder,
342 				    SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) {
343 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
344 		rc = -EINVAL;
345 		goto invalid;
346 	}
347 
348 	spdk_vhost_lock();
349 	vdev = spdk_vhost_dev_find(req.ctrlr);
350 	if (vdev == NULL) {
351 		spdk_vhost_unlock();
352 		rc = -ENODEV;
353 		goto invalid;
354 	}
355 	spdk_vhost_unlock();
356 
357 	rc = spdk_vhost_dev_remove(vdev);
358 	if (rc < 0) {
359 		if (rc == -EBUSY) {
360 			struct vhost_delete_ctrlr_context *ctx;
361 
362 			ctx = calloc(1, sizeof(*ctx));
363 			if (ctx == NULL) {
364 				SPDK_ERRLOG("Failed to allocate memory for vhost_delete_ctrlr context\n");
365 				rc = -ENOMEM;
366 				goto invalid;
367 			}
368 			ctx->request = request;
369 			ctx->params = params;
370 			spdk_thread_send_msg(spdk_get_thread(), _rpc_vhost_delete_controller, ctx);
371 			free_rpc_delete_vhost_ctrlr(&req);
372 			return;
373 		}
374 		goto invalid;
375 	}
376 
377 	free_rpc_delete_vhost_ctrlr(&req);
378 
379 	spdk_jsonrpc_send_bool_response(request, true);
380 	return;
381 
382 invalid:
383 	free_rpc_delete_vhost_ctrlr(&req);
384 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
385 					 spdk_strerror(-rc));
386 
387 }
388 SPDK_RPC_REGISTER("vhost_delete_controller", rpc_vhost_delete_controller, SPDK_RPC_RUNTIME)
389 
390 static void _rpc_vhost_delete_controller(void *arg)
391 {
392 	struct vhost_delete_ctrlr_context *ctx = arg;
393 
394 	rpc_vhost_delete_controller(ctx->request, ctx->params);
395 	free(ctx);
396 }
397 
398 struct rpc_get_vhost_ctrlrs {
399 	char *name;
400 };
401 
402 static void
403 _rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
404 {
405 	uint32_t delay_base_us, iops_threshold;
406 
407 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
408 
409 	spdk_json_write_object_begin(w);
410 
411 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
412 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s",
413 					 spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
414 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
415 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
416 	spdk_json_write_named_string(w, "socket", vdev->path);
417 	spdk_json_write_named_array_begin(w, "sessions");
418 	vhost_session_info_json(vdev, w);
419 	spdk_json_write_array_end(w);
420 
421 	spdk_json_write_named_object_begin(w, "backend_specific");
422 	vhost_dump_info_json(vdev, w);
423 	spdk_json_write_object_end(w);
424 
425 	spdk_json_write_object_end(w);
426 }
427 
428 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
429 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
430 };
431 
432 static void
433 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req)
434 {
435 	free(req->name);
436 }
437 
438 static void
439 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request,
440 			  const struct spdk_json_val *params)
441 {
442 	struct rpc_get_vhost_ctrlrs req = {0};
443 	struct spdk_json_write_ctx *w;
444 	struct spdk_vhost_dev *vdev;
445 	int rc;
446 
447 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
448 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) {
449 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
450 		rc = -EINVAL;
451 		goto invalid;
452 	}
453 
454 	spdk_vhost_lock();
455 	if (req.name != NULL) {
456 		vdev = spdk_vhost_dev_find(req.name);
457 		if (vdev == NULL) {
458 			spdk_vhost_unlock();
459 			rc = -ENODEV;
460 			goto invalid;
461 		}
462 
463 		free_rpc_get_vhost_ctrlrs(&req);
464 
465 		w = spdk_jsonrpc_begin_result(request);
466 		spdk_json_write_array_begin(w);
467 
468 		_rpc_get_vhost_controller(w, vdev);
469 		spdk_vhost_unlock();
470 
471 		spdk_json_write_array_end(w);
472 		spdk_jsonrpc_end_result(request, w);
473 		return;
474 	}
475 
476 	free_rpc_get_vhost_ctrlrs(&req);
477 
478 	w = spdk_jsonrpc_begin_result(request);
479 	spdk_json_write_array_begin(w);
480 
481 	vdev = spdk_vhost_dev_next(NULL);
482 	while (vdev != NULL) {
483 		_rpc_get_vhost_controller(w, vdev);
484 		vdev = spdk_vhost_dev_next(vdev);
485 	}
486 	spdk_vhost_unlock();
487 
488 	spdk_json_write_array_end(w);
489 	spdk_jsonrpc_end_result(request, w);
490 	return;
491 
492 invalid:
493 	free_rpc_get_vhost_ctrlrs(&req);
494 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
495 					 spdk_strerror(-rc));
496 }
497 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME)
498 
499 
500 struct rpc_vhost_ctrlr_coalescing {
501 	char *ctrlr;
502 	uint32_t delay_base_us;
503 	uint32_t iops_threshold;
504 };
505 
506 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
507 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
508 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
509 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
510 };
511 
512 static void
513 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
514 {
515 	free(req->ctrlr);
516 }
517 
518 static void
519 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request,
520 				    const struct spdk_json_val *params)
521 {
522 	struct rpc_vhost_ctrlr_coalescing req = {0};
523 	struct spdk_vhost_dev *vdev;
524 	int rc;
525 
526 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
527 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) {
528 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
529 		rc = -EINVAL;
530 		goto invalid;
531 	}
532 
533 	spdk_vhost_lock();
534 	vdev = spdk_vhost_dev_find(req.ctrlr);
535 	if (vdev == NULL) {
536 		spdk_vhost_unlock();
537 		rc = -ENODEV;
538 		goto invalid;
539 	}
540 
541 	rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold);
542 	spdk_vhost_unlock();
543 	if (rc) {
544 		goto invalid;
545 	}
546 
547 	free_rpc_set_vhost_controllers_event_coalescing(&req);
548 
549 	spdk_jsonrpc_send_bool_response(request, true);
550 	return;
551 
552 invalid:
553 	free_rpc_set_vhost_controllers_event_coalescing(&req);
554 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
555 					 spdk_strerror(-rc));
556 }
557 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
558 		  SPDK_RPC_RUNTIME)
559 
560 struct rpc_get_transport {
561 	char *name;
562 };
563 
564 static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = {
565 	{"name", offsetof(struct rpc_get_transport, name), spdk_json_decode_string, true},
566 };
567 
568 static void
569 rpc_virtio_blk_get_transports(struct spdk_jsonrpc_request *request,
570 			      const struct spdk_json_val *params)
571 {
572 	struct rpc_get_transport req = { 0 };
573 	struct spdk_json_write_ctx *w;
574 	struct spdk_virtio_blk_transport *transport = NULL;
575 
576 	if (params) {
577 		if (spdk_json_decode_object(params, rpc_get_transport_decoders,
578 					    SPDK_COUNTOF(rpc_get_transport_decoders),
579 					    &req)) {
580 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
581 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
582 			return;
583 		}
584 	}
585 
586 	if (req.name) {
587 		transport = virtio_blk_tgt_get_transport(req.name);
588 		if (transport == NULL) {
589 			SPDK_ERRLOG("transport '%s' does not exist\n", req.name);
590 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
591 			free(req.name);
592 			return;
593 		}
594 	}
595 
596 	w = spdk_jsonrpc_begin_result(request);
597 	spdk_json_write_array_begin(w);
598 
599 	if (transport) {
600 		virtio_blk_transport_dump_opts(transport, w);
601 	} else {
602 		for (transport = virtio_blk_transport_get_first(); transport != NULL;
603 		     transport = virtio_blk_transport_get_next(transport)) {
604 			virtio_blk_transport_dump_opts(transport, w);
605 		}
606 	}
607 
608 	spdk_json_write_array_end(w);
609 	spdk_jsonrpc_end_result(request, w);
610 	free(req.name);
611 }
612 SPDK_RPC_REGISTER("virtio_blk_get_transports", rpc_virtio_blk_get_transports, SPDK_RPC_RUNTIME)
613 
614 struct rpc_virtio_blk_create_transport {
615 	char *name;
616 };
617 
618 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = {
619 	{"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string},
620 };
621 
622 static void
623 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req)
624 {
625 	free(req->name);
626 }
627 
628 static void
629 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request,
630 				const struct spdk_json_val *params)
631 {
632 	struct rpc_virtio_blk_create_transport req = {0};
633 	int rc;
634 
635 	if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport,
636 					    SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) {
637 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
638 		rc = -EINVAL;
639 		goto invalid;
640 	}
641 
642 	spdk_vhost_lock();
643 	rc = virtio_blk_transport_create(req.name, params);
644 	spdk_vhost_unlock();
645 	if (rc != 0) {
646 		goto invalid;
647 	}
648 
649 	free_rpc_virtio_blk_create_transport(&req);
650 	spdk_jsonrpc_send_bool_response(request, true);
651 	return;
652 
653 invalid:
654 	free_rpc_virtio_blk_create_transport(&req);
655 	spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
656 }
657 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport,
658 		  SPDK_RPC_RUNTIME)
659 
660 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc)
661