xref: /spdk/lib/vhost/vhost_rpc.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk_internal/log.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 #include "spdk/string.h"
40 #include "spdk/env.h"
41 
42 #include "spdk/scsi.h"
43 #include "spdk/vhost.h"
44 #include "vhost_internal.h"
45 #include "spdk/bdev.h"
46 
47 struct rpc_vhost_scsi_ctrlr {
48 	char *ctrlr;
49 	char *cpumask;
50 };
51 
52 static void
53 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
54 {
55 	free(req->ctrlr);
56 	free(req->cpumask);
57 }
58 
59 static const struct spdk_json_object_decoder rpc_vhost_create_scsi_ctrlr[] = {
60 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
61 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
62 };
63 
64 static void
65 spdk_rpc_vhost_create_scsi_controller(struct spdk_jsonrpc_request *request,
66 				      const struct spdk_json_val *params)
67 {
68 	struct rpc_vhost_scsi_ctrlr req = {0};
69 	struct spdk_json_write_ctx *w;
70 	int rc;
71 
72 	if (spdk_json_decode_object(params, rpc_vhost_create_scsi_ctrlr,
73 				    SPDK_COUNTOF(rpc_vhost_create_scsi_ctrlr),
74 				    &req)) {
75 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
76 		rc = -EINVAL;
77 		goto invalid;
78 	}
79 
80 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask);
81 	if (rc < 0) {
82 		goto invalid;
83 	}
84 
85 	free_rpc_vhost_scsi_ctrlr(&req);
86 
87 	w = spdk_jsonrpc_begin_result(request);
88 	spdk_json_write_bool(w, true);
89 	spdk_jsonrpc_end_result(request, w);
90 	return;
91 
92 invalid:
93 	free_rpc_vhost_scsi_ctrlr(&req);
94 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
95 					 spdk_strerror(-rc));
96 }
97 SPDK_RPC_REGISTER("vhost_create_scsi_controller", spdk_rpc_vhost_create_scsi_controller,
98 		  SPDK_RPC_RUNTIME)
99 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_create_scsi_controller, construct_vhost_scsi_controller)
100 
101 struct rpc_vhost_scsi_ctrlr_add_target {
102 	char *ctrlr;
103 	int32_t scsi_target_num;
104 	char *bdev_name;
105 };
106 
107 static void
108 free_rpc_vhost_scsi_ctrlr_add_target(struct rpc_vhost_scsi_ctrlr_add_target *req)
109 {
110 	free(req->ctrlr);
111 	free(req->bdev_name);
112 }
113 
114 static const struct spdk_json_object_decoder rpc_vhost_scsi_ctrlr_add_target[] = {
115 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, ctrlr), spdk_json_decode_string },
116 	{"scsi_target_num", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, scsi_target_num), spdk_json_decode_int32},
117 	{"bdev_name", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, bdev_name), spdk_json_decode_string },
118 };
119 
120 static void
121 spdk_rpc_vhost_scsi_controller_add_target(struct spdk_jsonrpc_request *request,
122 		const struct spdk_json_val *params)
123 {
124 	struct rpc_vhost_scsi_ctrlr_add_target req = {0};
125 	struct spdk_json_write_ctx *w;
126 	struct spdk_vhost_dev *vdev;
127 	int rc;
128 
129 	if (spdk_json_decode_object(params, rpc_vhost_scsi_ctrlr_add_target,
130 				    SPDK_COUNTOF(rpc_vhost_scsi_ctrlr_add_target),
131 				    &req)) {
132 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
133 		rc = -EINVAL;
134 		goto invalid;
135 	}
136 
137 	spdk_vhost_lock();
138 	vdev = spdk_vhost_dev_find(req.ctrlr);
139 	if (vdev == NULL) {
140 		spdk_vhost_unlock();
141 		rc = -ENODEV;
142 		goto invalid;
143 	}
144 
145 	rc = spdk_vhost_scsi_dev_add_tgt(vdev, req.scsi_target_num, req.bdev_name);
146 	spdk_vhost_unlock();
147 	if (rc < 0) {
148 		goto invalid;
149 	}
150 
151 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
152 
153 	w = spdk_jsonrpc_begin_result(request);
154 	spdk_json_write_int32(w, rc);
155 	spdk_jsonrpc_end_result(request, w);
156 	return;
157 
158 invalid:
159 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
160 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
161 					 spdk_strerror(-rc));
162 }
163 SPDK_RPC_REGISTER("vhost_scsi_controller_add_target", spdk_rpc_vhost_scsi_controller_add_target,
164 		  SPDK_RPC_RUNTIME)
165 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_scsi_controller_add_target, add_vhost_scsi_lun)
166 
167 struct rpc_remove_vhost_scsi_ctrlr_target {
168 	char *ctrlr;
169 	uint32_t scsi_target_num;
170 };
171 
172 static void
173 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req)
174 {
175 	free(req->ctrlr);
176 }
177 
178 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = {
179 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string },
180 	{"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32},
181 };
182 
183 static int
184 spdk_rpc_vhost_scsi_controller_remove_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
185 {
186 	struct spdk_jsonrpc_request *request = arg;
187 	struct spdk_json_write_ctx *w;
188 
189 	w = spdk_jsonrpc_begin_result(request);
190 	spdk_json_write_bool(w, true);
191 	spdk_jsonrpc_end_result(request, w);
192 	return 0;
193 }
194 
195 static void
196 spdk_rpc_vhost_scsi_controller_remove_target(struct spdk_jsonrpc_request *request,
197 		const struct spdk_json_val *params)
198 {
199 	struct rpc_remove_vhost_scsi_ctrlr_target req = {0};
200 	struct spdk_vhost_dev *vdev;
201 	int rc;
202 
203 	if (spdk_json_decode_object(params, rpc_vhost_remove_target,
204 				    SPDK_COUNTOF(rpc_vhost_remove_target),
205 				    &req)) {
206 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
207 		rc = -EINVAL;
208 		goto invalid;
209 	}
210 
211 	spdk_vhost_lock();
212 	vdev = spdk_vhost_dev_find(req.ctrlr);
213 	if (vdev == NULL) {
214 		spdk_vhost_unlock();
215 		rc = -ENODEV;
216 		goto invalid;
217 	}
218 
219 	rc = spdk_vhost_scsi_dev_remove_tgt(vdev, req.scsi_target_num,
220 					    spdk_rpc_vhost_scsi_controller_remove_target_finish_cb,
221 					    request);
222 	spdk_vhost_unlock();
223 	if (rc < 0) {
224 		goto invalid;
225 	}
226 
227 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
228 	return;
229 
230 invalid:
231 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
232 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
233 					 spdk_strerror(-rc));
234 }
235 
236 SPDK_RPC_REGISTER("vhost_scsi_controller_remove_target",
237 		  spdk_rpc_vhost_scsi_controller_remove_target, SPDK_RPC_RUNTIME)
238 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_scsi_controller_remove_target, remove_vhost_scsi_target)
239 
240 struct rpc_vhost_blk_ctrlr {
241 	char *ctrlr;
242 	char *dev_name;
243 	char *cpumask;
244 	bool readonly;
245 };
246 
247 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
248 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
249 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
250 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
251 	{"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true},
252 };
253 
254 static void
255 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
256 {
257 	free(req->ctrlr);
258 	free(req->dev_name);
259 	free(req->cpumask);
260 }
261 
262 static void
263 spdk_rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
264 				     const struct spdk_json_val *params)
265 {
266 	struct rpc_vhost_blk_ctrlr req = {0};
267 	struct spdk_json_write_ctx *w;
268 	int rc;
269 
270 	if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr,
271 				    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
272 				    &req)) {
273 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
274 		rc = -EINVAL;
275 		goto invalid;
276 	}
277 
278 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.readonly);
279 	if (rc < 0) {
280 		goto invalid;
281 	}
282 
283 	free_rpc_vhost_blk_ctrlr(&req);
284 
285 	w = spdk_jsonrpc_begin_result(request);
286 	spdk_json_write_bool(w, true);
287 	spdk_jsonrpc_end_result(request, w);
288 	return;
289 
290 invalid:
291 	free_rpc_vhost_blk_ctrlr(&req);
292 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
293 					 spdk_strerror(-rc));
294 
295 }
296 SPDK_RPC_REGISTER("vhost_create_blk_controller", spdk_rpc_vhost_create_blk_controller,
297 		  SPDK_RPC_RUNTIME)
298 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_create_blk_controller, construct_vhost_blk_controller)
299 
300 struct rpc_delete_vhost_ctrlr {
301 	char *ctrlr;
302 };
303 
304 static const struct spdk_json_object_decoder rpc_delete_vhost_ctrlr_decoder[] = {
305 	{"ctrlr", offsetof(struct rpc_delete_vhost_ctrlr, ctrlr), spdk_json_decode_string },
306 };
307 
308 static void
309 free_rpc_delete_vhost_ctrlr(struct rpc_delete_vhost_ctrlr *req)
310 {
311 	free(req->ctrlr);
312 }
313 
314 static void
315 spdk_rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request,
316 				 const struct spdk_json_val *params)
317 {
318 	struct rpc_delete_vhost_ctrlr req = {0};
319 	struct spdk_json_write_ctx *w;
320 	struct spdk_vhost_dev *vdev;
321 	int rc;
322 
323 	if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder,
324 				    SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) {
325 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
326 		rc = -EINVAL;
327 		goto invalid;
328 	}
329 
330 	spdk_vhost_lock();
331 	vdev = spdk_vhost_dev_find(req.ctrlr);
332 	if (vdev == NULL) {
333 		spdk_vhost_unlock();
334 		rc = -ENODEV;
335 		goto invalid;
336 	}
337 
338 	rc = spdk_vhost_dev_remove(vdev);
339 	spdk_vhost_unlock();
340 	if (rc < 0) {
341 		goto invalid;
342 	}
343 
344 	free_rpc_delete_vhost_ctrlr(&req);
345 
346 	w = spdk_jsonrpc_begin_result(request);
347 	spdk_json_write_bool(w, true);
348 	spdk_jsonrpc_end_result(request, w);
349 
350 	return;
351 
352 invalid:
353 	free_rpc_delete_vhost_ctrlr(&req);
354 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
355 					 spdk_strerror(-rc));
356 
357 }
358 SPDK_RPC_REGISTER("vhost_delete_controller", spdk_rpc_vhost_delete_controller, SPDK_RPC_RUNTIME)
359 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_delete_controller, remove_vhost_controller)
360 
361 struct rpc_get_vhost_ctrlrs {
362 	char *name;
363 };
364 
365 static void
366 _spdk_rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
367 {
368 	uint32_t delay_base_us, iops_threshold;
369 
370 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
371 
372 	spdk_json_write_object_begin(w);
373 
374 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
375 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s", spdk_cpuset_fmt(vdev->cpumask));
376 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
377 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
378 	spdk_json_write_named_string(w, "socket", vdev->path);
379 
380 	spdk_json_write_named_object_begin(w, "backend_specific");
381 	vhost_dump_info_json(vdev, w);
382 	spdk_json_write_object_end(w);
383 
384 	spdk_json_write_object_end(w);
385 }
386 
387 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
388 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
389 };
390 
391 static void
392 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req)
393 {
394 	free(req->name);
395 }
396 
397 static void
398 spdk_rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request,
399 			       const struct spdk_json_val *params)
400 {
401 	struct rpc_get_vhost_ctrlrs req = {0};
402 	struct spdk_json_write_ctx *w;
403 	struct spdk_vhost_dev *vdev;
404 	int rc;
405 
406 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
407 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) {
408 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
409 		rc = -EINVAL;
410 		goto invalid;
411 	}
412 
413 	spdk_vhost_lock();
414 	if (req.name != NULL) {
415 		vdev = spdk_vhost_dev_find(req.name);
416 		if (vdev == NULL) {
417 			spdk_vhost_unlock();
418 			rc = -ENODEV;
419 			goto invalid;
420 		}
421 
422 		free_rpc_get_vhost_ctrlrs(&req);
423 
424 		w = spdk_jsonrpc_begin_result(request);
425 		spdk_json_write_array_begin(w);
426 
427 		_spdk_rpc_get_vhost_controller(w, vdev);
428 		spdk_vhost_unlock();
429 
430 		spdk_json_write_array_end(w);
431 		spdk_jsonrpc_end_result(request, w);
432 		return;
433 	}
434 
435 	free_rpc_get_vhost_ctrlrs(&req);
436 
437 	w = spdk_jsonrpc_begin_result(request);
438 	spdk_json_write_array_begin(w);
439 
440 	vdev = spdk_vhost_dev_next(NULL);
441 	while (vdev != NULL) {
442 		_spdk_rpc_get_vhost_controller(w, vdev);
443 		vdev = spdk_vhost_dev_next(vdev);
444 	}
445 	spdk_vhost_unlock();
446 
447 	spdk_json_write_array_end(w);
448 	spdk_jsonrpc_end_result(request, w);
449 	return;
450 
451 invalid:
452 	free_rpc_get_vhost_ctrlrs(&req);
453 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
454 					 spdk_strerror(-rc));
455 }
456 SPDK_RPC_REGISTER("vhost_get_controllers", spdk_rpc_vhost_get_controllers, SPDK_RPC_RUNTIME)
457 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_get_controllers, get_vhost_controllers)
458 
459 
460 struct rpc_vhost_ctrlr_coalescing {
461 	char *ctrlr;
462 	uint32_t delay_base_us;
463 	uint32_t iops_threshold;
464 };
465 
466 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
467 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
468 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
469 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
470 };
471 
472 static void
473 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
474 {
475 	free(req->ctrlr);
476 }
477 
478 static void
479 spdk_rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request,
480 		const struct spdk_json_val *params)
481 {
482 	struct rpc_vhost_ctrlr_coalescing req = {0};
483 	struct spdk_json_write_ctx *w;
484 	struct spdk_vhost_dev *vdev;
485 	int rc;
486 
487 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
488 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) {
489 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
490 		rc = -EINVAL;
491 		goto invalid;
492 	}
493 
494 	spdk_vhost_lock();
495 	vdev = spdk_vhost_dev_find(req.ctrlr);
496 	if (vdev == NULL) {
497 		spdk_vhost_unlock();
498 		rc = -ENODEV;
499 		goto invalid;
500 	}
501 
502 	rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold);
503 	spdk_vhost_unlock();
504 	if (rc) {
505 		goto invalid;
506 	}
507 
508 	free_rpc_set_vhost_controllers_event_coalescing(&req);
509 
510 	w = spdk_jsonrpc_begin_result(request);
511 	spdk_json_write_bool(w, true);
512 	spdk_jsonrpc_end_result(request, w);
513 
514 	return;
515 
516 invalid:
517 	free_rpc_set_vhost_controllers_event_coalescing(&req);
518 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
519 					 spdk_strerror(-rc));
520 }
521 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", spdk_rpc_vhost_controller_set_coalescing,
522 		  SPDK_RPC_RUNTIME)
523 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_controller_set_coalescing, set_vhost_controller_coalescing)
524 
525 #ifdef SPDK_CONFIG_VHOST_INTERNAL_LIB
526 
527 struct rpc_vhost_nvme_ctrlr {
528 	char *ctrlr;
529 	uint32_t io_queues;
530 	char *cpumask;
531 };
532 
533 static const struct spdk_json_object_decoder rpc_construct_vhost_nvme_ctrlr[] = {
534 	{"ctrlr", offsetof(struct rpc_vhost_nvme_ctrlr, ctrlr), spdk_json_decode_string },
535 	{"io_queues", offsetof(struct rpc_vhost_nvme_ctrlr, io_queues), spdk_json_decode_uint32},
536 	{"cpumask", offsetof(struct rpc_vhost_nvme_ctrlr, cpumask), spdk_json_decode_string, true},
537 };
538 
539 static void
540 free_rpc_vhost_nvme_ctrlr(struct rpc_vhost_nvme_ctrlr *req)
541 {
542 	free(req->ctrlr);
543 	free(req->cpumask);
544 }
545 
546 static void
547 spdk_rpc_vhost_create_nvme_controller(struct spdk_jsonrpc_request *request,
548 				      const struct spdk_json_val *params)
549 {
550 	struct rpc_vhost_nvme_ctrlr req = {};
551 	struct spdk_json_write_ctx *w;
552 	int rc;
553 
554 	if (spdk_json_decode_object(params, rpc_construct_vhost_nvme_ctrlr,
555 				    SPDK_COUNTOF(rpc_construct_vhost_nvme_ctrlr),
556 				    &req)) {
557 		rc = -EINVAL;
558 		goto invalid;
559 	}
560 
561 	rc = vhost_nvme_dev_construct(req.ctrlr, req.cpumask, req.io_queues);
562 	if (rc < 0) {
563 		goto invalid;
564 	}
565 
566 	free_rpc_vhost_nvme_ctrlr(&req);
567 
568 	w = spdk_jsonrpc_begin_result(request);
569 	spdk_json_write_bool(w, true);
570 	spdk_jsonrpc_end_result(request, w);
571 	return;
572 
573 invalid:
574 	free_rpc_vhost_nvme_ctrlr(&req);
575 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
576 					 spdk_strerror(-rc));
577 
578 }
579 SPDK_RPC_REGISTER("vhost_create_nvme_controller", spdk_rpc_vhost_create_nvme_controller,
580 		  SPDK_RPC_RUNTIME)
581 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_create_nvme_controller, construct_vhost_nvme_controller)
582 
583 struct rpc_vhost_nvme_ctrlr_add_ns {
584 	char *ctrlr;
585 	char *bdev_name;
586 };
587 
588 static void
589 free_rpc_vhost_nvme_ctrlr_add_ns(struct rpc_vhost_nvme_ctrlr_add_ns *req)
590 {
591 	free(req->ctrlr);
592 	free(req->bdev_name);
593 }
594 
595 static const struct spdk_json_object_decoder rpc_vhost_nvme_add_ns[] = {
596 	{"ctrlr", offsetof(struct rpc_vhost_nvme_ctrlr_add_ns, ctrlr), spdk_json_decode_string },
597 	{"bdev_name", offsetof(struct rpc_vhost_nvme_ctrlr_add_ns, bdev_name), spdk_json_decode_string },
598 };
599 
600 static void
601 spdk_rpc_vhost_nvme_controller_add_ns(struct spdk_jsonrpc_request *request,
602 				      const struct spdk_json_val *params)
603 {
604 	struct rpc_vhost_nvme_ctrlr_add_ns req = {0};
605 	struct spdk_json_write_ctx *w;
606 	struct spdk_vhost_dev *vdev;
607 	int rc;
608 
609 	if (spdk_json_decode_object(params, rpc_vhost_nvme_add_ns,
610 				    SPDK_COUNTOF(rpc_vhost_nvme_add_ns),
611 				    &req)) {
612 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
613 		rc = -EINVAL;
614 		goto invalid;
615 	}
616 
617 	spdk_vhost_lock();
618 	vdev = spdk_vhost_dev_find(req.ctrlr);
619 	if (vdev == NULL) {
620 		spdk_vhost_unlock();
621 		rc = -ENODEV;
622 		goto invalid;
623 	}
624 
625 	rc = vhost_nvme_dev_add_ns(vdev, req.bdev_name);
626 	spdk_vhost_unlock();
627 	if (rc < 0) {
628 		goto invalid;
629 	}
630 	free_rpc_vhost_nvme_ctrlr_add_ns(&req);
631 
632 	w = spdk_jsonrpc_begin_result(request);
633 	spdk_json_write_bool(w, true);
634 	spdk_jsonrpc_end_result(request, w);
635 	return;
636 
637 invalid:
638 	free_rpc_vhost_nvme_ctrlr_add_ns(&req);
639 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
640 					 spdk_strerror(-rc));
641 }
642 SPDK_RPC_REGISTER("vhost_nvme_controller_add_ns", spdk_rpc_vhost_nvme_controller_add_ns,
643 		  SPDK_RPC_RUNTIME)
644 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(vhost_nvme_controller_add_ns, add_vhost_nvme_ns)
645 
646 #endif /* SPDK_CONFIG_VHOST_INTERNAL_LIB */
647 
648 SPDK_LOG_REGISTER_COMPONENT("vhost_rpc", SPDK_LOG_VHOST_RPC)
649