xref: /spdk/lib/vhost/vhost_rpc.c (revision bbcb35f58b3a9e78b7b69adf4179e2cbd7beb7b3)
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_construct_vhost_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_construct_vhost_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_construct_vhost_ctrlr,
73 				    SPDK_COUNTOF(rpc_construct_vhost_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 	if (w == NULL) {
89 		return;
90 	}
91 
92 	spdk_json_write_bool(w, true);
93 	spdk_jsonrpc_end_result(request, w);
94 	return;
95 
96 invalid:
97 	free_rpc_vhost_scsi_ctrlr(&req);
98 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
99 					 spdk_strerror(-rc));
100 }
101 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller,
102 		  SPDK_RPC_RUNTIME)
103 
104 struct rpc_add_vhost_scsi_ctrlr_lun {
105 	char *ctrlr;
106 	uint32_t scsi_target_num;
107 	char *bdev_name;
108 
109 	struct spdk_jsonrpc_request *request;
110 };
111 
112 static void
113 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req)
114 {
115 	free(req->ctrlr);
116 	free(req->bdev_name);
117 	free(req);
118 }
119 
120 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = {
121 	{"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string },
122 	{"scsi_target_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_target_num), spdk_json_decode_uint32},
123 	{"bdev_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, bdev_name), spdk_json_decode_string },
124 };
125 
126 static int
127 spdk_rpc_add_vhost_scsi_lun_cb(struct spdk_vhost_dev *vdev, void *arg)
128 {
129 	struct rpc_add_vhost_scsi_ctrlr_lun *rpc = arg;
130 	struct spdk_jsonrpc_request *request = rpc->request;
131 	struct spdk_json_write_ctx *w;
132 	int rc;
133 
134 	if (vdev == NULL) {
135 		rc = -ENODEV;
136 		goto invalid;
137 	}
138 
139 	rc = spdk_vhost_scsi_dev_add_tgt(vdev, rpc->scsi_target_num, rpc->bdev_name);
140 	if (rc < 0) {
141 		goto invalid;
142 	}
143 
144 	free_rpc_add_vhost_scsi_ctrlr_lun(rpc);
145 
146 	w = spdk_jsonrpc_begin_result(request);
147 	if (w == NULL) {
148 		return -1;
149 	}
150 
151 	spdk_json_write_bool(w, true);
152 	spdk_jsonrpc_end_result(request, w);
153 	return 0;
154 
155 invalid:
156 	free_rpc_add_vhost_scsi_ctrlr_lun(rpc);
157 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
158 					 spdk_strerror(-rc));
159 	return rc;
160 }
161 
162 static void
163 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request,
164 			    const struct spdk_json_val *params)
165 {
166 	struct rpc_add_vhost_scsi_ctrlr_lun *req;
167 	int rc;
168 
169 	req = calloc(1, sizeof(*req));
170 	if (req == NULL) {
171 		rc = -ENOMEM;
172 		goto invalid;
173 	}
174 
175 	req->request = request;
176 	if (spdk_json_decode_object(params, rpc_vhost_add_lun,
177 				    SPDK_COUNTOF(rpc_vhost_add_lun),
178 				    req)) {
179 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
180 		rc = -EINVAL;
181 		goto invalid;
182 	}
183 
184 	if (req->ctrlr == NULL) {
185 		SPDK_ERRLOG("No controller name\n");
186 		rc = -EINVAL;
187 		goto invalid;
188 	}
189 
190 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_add_vhost_scsi_lun_cb, req);
191 
192 	return;
193 
194 invalid:
195 	if (req) {
196 		free_rpc_add_vhost_scsi_ctrlr_lun(req);
197 	}
198 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
199 					 spdk_strerror(-rc));
200 }
201 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun, SPDK_RPC_RUNTIME)
202 
203 struct rpc_remove_vhost_scsi_ctrlr_target {
204 	char *ctrlr;
205 	uint32_t scsi_target_num;
206 
207 	struct spdk_jsonrpc_request *request;
208 };
209 
210 static void
211 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req)
212 {
213 	free(req->ctrlr);
214 	free(req);
215 }
216 
217 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = {
218 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string },
219 	{"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32},
220 };
221 
222 static int
223 spdk_rpc_remove_vhost_scsi_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
224 {
225 	struct rpc_remove_vhost_scsi_ctrlr_target *rpc = arg;
226 	struct spdk_jsonrpc_request *request = rpc->request;
227 	struct spdk_json_write_ctx *w;
228 
229 	free_rpc_remove_vhost_scsi_ctrlr_target(rpc);
230 
231 	w = spdk_jsonrpc_begin_result(request);
232 	if (w == NULL) {
233 		return -1;
234 	}
235 
236 	spdk_json_write_bool(w, true);
237 	spdk_jsonrpc_end_result(request, w);
238 	return 0;
239 }
240 
241 static int
242 spdk_rpc_remove_vhost_scsi_target_cb(struct spdk_vhost_dev *vdev, void *arg)
243 {
244 	struct rpc_remove_vhost_scsi_ctrlr_target *rpc = arg;
245 	struct spdk_jsonrpc_request *request = rpc->request;
246 	int rc;
247 
248 	if (vdev == NULL) {
249 		rc = -ENODEV;
250 		goto invalid;
251 	}
252 
253 	rc = spdk_vhost_scsi_dev_remove_tgt(vdev, rpc->scsi_target_num,
254 					    spdk_rpc_remove_vhost_scsi_target_finish_cb, rpc);
255 	if (rc < 0) {
256 		goto invalid;
257 	}
258 
259 	return 0;
260 
261 invalid:
262 	free_rpc_remove_vhost_scsi_ctrlr_target(rpc);
263 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
264 	return rc;
265 }
266 
267 static void
268 spdk_rpc_remove_vhost_scsi_target(struct spdk_jsonrpc_request *request,
269 				  const struct spdk_json_val *params)
270 {
271 	struct rpc_remove_vhost_scsi_ctrlr_target *req;
272 	int rc;
273 
274 	req = calloc(1, sizeof(*req));
275 	if (req == NULL) {
276 		rc = -ENOMEM;
277 		goto invalid;
278 	}
279 
280 	req->request = request;
281 	if (spdk_json_decode_object(params, rpc_vhost_remove_target,
282 				    SPDK_COUNTOF(rpc_vhost_remove_target),
283 				    req)) {
284 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
285 		rc = -EINVAL;
286 		goto invalid;
287 	}
288 
289 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_remove_vhost_scsi_target_cb, req);
290 
291 	return;
292 
293 invalid:
294 	if (req) {
295 		free_rpc_remove_vhost_scsi_ctrlr_target(req);
296 	}
297 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
298 					 spdk_strerror(-rc));
299 }
300 
301 SPDK_RPC_REGISTER("remove_vhost_scsi_target", spdk_rpc_remove_vhost_scsi_target, SPDK_RPC_RUNTIME)
302 
303 struct rpc_vhost_blk_ctrlr {
304 	char *ctrlr;
305 	char *dev_name;
306 	char *cpumask;
307 	bool readonly;
308 };
309 
310 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
311 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
312 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
313 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
314 	{"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true},
315 };
316 
317 static void
318 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
319 {
320 	free(req->ctrlr);
321 	free(req->dev_name);
322 	free(req->cpumask);
323 }
324 
325 static void
326 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request,
327 					const struct spdk_json_val *params)
328 {
329 	struct rpc_vhost_blk_ctrlr req = {0};
330 	struct spdk_json_write_ctx *w;
331 	int rc;
332 
333 	if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr,
334 				    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
335 				    &req)) {
336 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
337 		rc = -EINVAL;
338 		goto invalid;
339 	}
340 
341 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.readonly);
342 	if (rc < 0) {
343 		goto invalid;
344 	}
345 
346 	free_rpc_vhost_blk_ctrlr(&req);
347 
348 	w = spdk_jsonrpc_begin_result(request);
349 	if (w == NULL) {
350 		return;
351 	}
352 
353 	spdk_json_write_bool(w, true);
354 	spdk_jsonrpc_end_result(request, w);
355 	return;
356 
357 invalid:
358 	free_rpc_vhost_blk_ctrlr(&req);
359 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
360 					 spdk_strerror(-rc));
361 
362 }
363 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller,
364 		  SPDK_RPC_RUNTIME)
365 
366 struct rpc_remove_vhost_ctrlr {
367 	char *ctrlr;
368 
369 	struct spdk_jsonrpc_request *request;
370 };
371 
372 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = {
373 	{"ctrlr", offsetof(struct rpc_remove_vhost_ctrlr, ctrlr), spdk_json_decode_string },
374 };
375 
376 static void
377 free_rpc_remove_vhost_ctrlr(struct rpc_remove_vhost_ctrlr *req)
378 {
379 	free(req->ctrlr);
380 	free(req);
381 }
382 
383 static int
384 spdk_rpc_remove_vhost_controller_cb(struct spdk_vhost_dev *vdev, void *arg)
385 {
386 	struct rpc_remove_vhost_ctrlr *ctx = arg;
387 	struct spdk_jsonrpc_request *request = ctx->request;
388 	struct spdk_json_write_ctx *w;
389 	int rc;
390 
391 	if (vdev == NULL) {
392 		rc = -ENODEV;
393 		goto invalid;
394 	}
395 
396 	rc = spdk_vhost_dev_remove(vdev);
397 	if (rc < 0) {
398 		goto invalid;
399 	}
400 
401 	free_rpc_remove_vhost_ctrlr(ctx);
402 
403 	w = spdk_jsonrpc_begin_result(request);
404 	if (w == NULL) {
405 		return 0;
406 	}
407 
408 	spdk_json_write_bool(w, true);
409 	spdk_jsonrpc_end_result(request, w);
410 	return 0;
411 
412 invalid:
413 	free_rpc_remove_vhost_ctrlr(ctx);
414 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
415 					 spdk_strerror(-rc));
416 	return -1;
417 }
418 
419 static void
420 spdk_rpc_remove_vhost_controller(struct spdk_jsonrpc_request *request,
421 				 const struct spdk_json_val *params)
422 {
423 	struct rpc_remove_vhost_ctrlr *req;
424 	int rc;
425 
426 	req = calloc(1, sizeof(*req));
427 	if (req == NULL) {
428 		rc = -ENOMEM;
429 		goto invalid;
430 	}
431 
432 	req->request = request;
433 	if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr,
434 				    SPDK_COUNTOF(rpc_remove_vhost_ctrlr), req)) {
435 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
436 		rc = -EINVAL;
437 		goto invalid;
438 	}
439 
440 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_remove_vhost_controller_cb, req);
441 	return;
442 
443 invalid:
444 	if (req) {
445 		free_rpc_remove_vhost_ctrlr(req);
446 	}
447 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
448 					 spdk_strerror(-rc));
449 
450 }
451 SPDK_RPC_REGISTER("remove_vhost_controller", spdk_rpc_remove_vhost_controller, SPDK_RPC_RUNTIME)
452 
453 struct rpc_get_vhost_ctrlrs {
454 	char *name;
455 	struct spdk_json_write_ctx *w;
456 	struct spdk_jsonrpc_request *request;
457 };
458 
459 static void
460 _spdk_rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
461 {
462 	uint32_t delay_base_us, iops_threshold;
463 
464 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
465 
466 	spdk_json_write_object_begin(w);
467 
468 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
469 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s", spdk_cpuset_fmt(vdev->cpumask));
470 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
471 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
472 	spdk_json_write_named_string(w, "socket", vdev->path);
473 
474 	spdk_json_write_named_object_begin(w, "backend_specific");
475 	spdk_vhost_dump_info_json(vdev, w);
476 	spdk_json_write_object_end(w);
477 
478 	spdk_json_write_object_end(w);
479 }
480 
481 static int
482 spdk_rpc_get_vhost_controllers_cb(struct spdk_vhost_dev *vdev, void *arg)
483 {
484 	struct rpc_get_vhost_ctrlrs *ctx = arg;
485 
486 	assert(ctx->name == NULL);
487 
488 	if (vdev == NULL) {
489 		spdk_json_write_array_end(ctx->w);
490 		spdk_jsonrpc_end_result(ctx->request, ctx->w);
491 		free(ctx);
492 		return 0;
493 	}
494 
495 	_spdk_rpc_get_vhost_controller(ctx->w, vdev);
496 	return 0;
497 }
498 
499 static int
500 spdk_rpc_get_vhost_controller_cb(struct spdk_vhost_dev *vdev, void *arg)
501 {
502 	struct rpc_get_vhost_ctrlrs *ctx = arg;
503 
504 	assert(ctx->name != NULL);
505 
506 	if (vdev == NULL) {
507 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
508 						 spdk_strerror(ENODEV));
509 		goto free_name_ctx;
510 	}
511 
512 	ctx->w = spdk_jsonrpc_begin_result(ctx->request);
513 	if (ctx->w == NULL) {
514 		goto free_name_ctx;
515 	}
516 
517 	spdk_json_write_array_begin(ctx->w);
518 	_spdk_rpc_get_vhost_controller(ctx->w, vdev);
519 	spdk_json_write_array_end(ctx->w);
520 
521 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
522 
523 free_name_ctx:
524 	free(ctx->name);
525 	free(ctx);
526 	return 0;
527 }
528 
529 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
530 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
531 };
532 
533 static void
534 spdk_rpc_get_vhost_controllers(struct spdk_jsonrpc_request *request,
535 			       const struct spdk_json_val *params)
536 {
537 	struct rpc_get_vhost_ctrlrs *ctx;
538 	struct spdk_json_write_ctx *w;
539 
540 	ctx = calloc(1, sizeof(*ctx));
541 	if (ctx == NULL) {
542 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
543 						 spdk_strerror(ENOMEM));
544 		return;
545 	}
546 
547 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
548 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), ctx)) {
549 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
550 		free(ctx);
551 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
552 						 "Invalid parameters");
553 		return;
554 	}
555 
556 	if (ctx->name) {
557 		ctx->request = request;
558 		spdk_vhost_call_external_event(ctx->name, spdk_rpc_get_vhost_controller_cb, ctx);
559 		return;
560 	}
561 
562 	w = spdk_jsonrpc_begin_result(request);
563 	if (w == NULL) {
564 		free(ctx);
565 		return;
566 	}
567 
568 	spdk_json_write_array_begin(w);
569 
570 	ctx->w = w;
571 	ctx->request = request;
572 	spdk_vhost_call_external_event_foreach(spdk_rpc_get_vhost_controllers_cb, ctx);
573 }
574 SPDK_RPC_REGISTER("get_vhost_controllers", spdk_rpc_get_vhost_controllers, SPDK_RPC_RUNTIME)
575 
576 
577 struct rpc_vhost_ctrlr_coalescing {
578 	char *ctrlr;
579 	uint32_t delay_base_us;
580 	uint32_t iops_threshold;
581 	struct spdk_jsonrpc_request *request;
582 };
583 
584 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
585 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
586 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
587 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
588 };
589 
590 static void
591 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
592 {
593 	if (!req) {
594 		return;
595 	}
596 
597 	free(req->ctrlr);
598 	free(req);
599 }
600 
601 static int
602 spdk_rpc_set_vhost_controller_coalescing_cb(struct spdk_vhost_dev *vdev, void *arg)
603 {
604 	struct rpc_vhost_ctrlr_coalescing *req = arg;
605 	struct spdk_json_write_ctx *w;
606 	int rc;
607 
608 	if (vdev == NULL) {
609 		rc = -ENODEV;
610 		goto invalid;
611 	}
612 
613 	rc = spdk_vhost_set_coalescing(vdev, req->delay_base_us, req->iops_threshold);
614 	if (rc) {
615 		goto invalid;
616 	}
617 
618 	w = spdk_jsonrpc_begin_result(req->request);
619 	if (w != NULL) {
620 		spdk_json_write_bool(w, true);
621 		spdk_jsonrpc_end_result(req->request, w);
622 	}
623 
624 	free_rpc_set_vhost_controllers_event_coalescing(req);
625 	return 0;
626 
627 invalid:
628 	spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
629 					 spdk_strerror(-rc));
630 	free_rpc_set_vhost_controllers_event_coalescing(req);
631 	return 0;
632 }
633 
634 static void
635 spdk_rpc_set_vhost_controller_coalescing(struct spdk_jsonrpc_request *request,
636 		const struct spdk_json_val *params)
637 {
638 	struct rpc_vhost_ctrlr_coalescing *req;
639 	int rc;
640 
641 	req = calloc(1, sizeof(struct rpc_vhost_ctrlr_coalescing));
642 	if (!req) {
643 		rc = -ENOMEM;
644 		goto invalid;
645 	}
646 
647 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
648 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), req)) {
649 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
650 		rc = -EINVAL;
651 		goto invalid;
652 	}
653 
654 	req->request = request;
655 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_set_vhost_controller_coalescing_cb, req);
656 	return;
657 
658 invalid:
659 	free_rpc_set_vhost_controllers_event_coalescing(req);
660 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
661 					 spdk_strerror(-rc));
662 }
663 SPDK_RPC_REGISTER("set_vhost_controller_coalescing", spdk_rpc_set_vhost_controller_coalescing,
664 		  SPDK_RPC_RUNTIME)
665 
666 struct rpc_vhost_nvme_ctrlr {
667 	char *ctrlr;
668 	uint32_t io_queues;
669 	char *cpumask;
670 };
671 
672 static const struct spdk_json_object_decoder rpc_construct_vhost_nvme_ctrlr[] = {
673 	{"ctrlr", offsetof(struct rpc_vhost_nvme_ctrlr, ctrlr), spdk_json_decode_string },
674 	{"io_queues", offsetof(struct rpc_vhost_nvme_ctrlr, io_queues), spdk_json_decode_uint32},
675 	{"cpumask", offsetof(struct rpc_vhost_nvme_ctrlr, cpumask), spdk_json_decode_string, true},
676 };
677 
678 static void
679 free_rpc_vhost_nvme_ctrlr(struct rpc_vhost_nvme_ctrlr *req)
680 {
681 	free(req->ctrlr);
682 	free(req->cpumask);
683 }
684 
685 static void
686 spdk_rpc_construct_vhost_nvme_controller(struct spdk_jsonrpc_request *request,
687 		const struct spdk_json_val *params)
688 {
689 	struct rpc_vhost_nvme_ctrlr req = {};
690 	struct spdk_json_write_ctx *w;
691 	int rc;
692 
693 	if (spdk_json_decode_object(params, rpc_construct_vhost_nvme_ctrlr,
694 				    SPDK_COUNTOF(rpc_construct_vhost_nvme_ctrlr),
695 				    &req)) {
696 		rc = -EINVAL;
697 		goto invalid;
698 	}
699 
700 	rc = spdk_vhost_nvme_dev_construct(req.ctrlr, req.cpumask, req.io_queues);
701 	if (rc < 0) {
702 		goto invalid;
703 	}
704 
705 	free_rpc_vhost_nvme_ctrlr(&req);
706 
707 	w = spdk_jsonrpc_begin_result(request);
708 	if (w == NULL) {
709 		return;
710 	}
711 
712 	spdk_json_write_bool(w, true);
713 	spdk_jsonrpc_end_result(request, w);
714 	return;
715 
716 invalid:
717 	free_rpc_vhost_nvme_ctrlr(&req);
718 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
719 					 spdk_strerror(-rc));
720 
721 }
722 SPDK_RPC_REGISTER("construct_vhost_nvme_controller", spdk_rpc_construct_vhost_nvme_controller,
723 		  SPDK_RPC_RUNTIME)
724 
725 struct rpc_add_vhost_nvme_ctrlr_ns {
726 	char *ctrlr;
727 	char *bdev_name;
728 	struct spdk_jsonrpc_request *request;
729 };
730 
731 static void
732 free_rpc_add_vhost_nvme_ctrlr_ns(struct rpc_add_vhost_nvme_ctrlr_ns *req)
733 {
734 	free(req->ctrlr);
735 	free(req->bdev_name);
736 	free(req);
737 }
738 
739 static const struct spdk_json_object_decoder rpc_vhost_nvme_add_ns[] = {
740 	{"ctrlr", offsetof(struct rpc_add_vhost_nvme_ctrlr_ns, ctrlr), spdk_json_decode_string },
741 	{"bdev_name", offsetof(struct rpc_add_vhost_nvme_ctrlr_ns, bdev_name), spdk_json_decode_string },
742 };
743 
744 static int
745 spdk_rpc_add_vhost_nvme_ns_cb(struct spdk_vhost_dev *vdev, void *arg)
746 {
747 	struct rpc_add_vhost_nvme_ctrlr_ns *rpc = arg;
748 	struct spdk_jsonrpc_request *request = rpc->request;
749 	struct spdk_json_write_ctx *w;
750 	int rc;
751 
752 	if (vdev == NULL) {
753 		rc = -ENODEV;
754 		goto invalid;
755 	}
756 
757 	rc = spdk_vhost_nvme_dev_add_ns(vdev, rpc->bdev_name);
758 	if (rc < 0) {
759 		goto invalid;
760 	}
761 	free_rpc_add_vhost_nvme_ctrlr_ns(rpc);
762 
763 	w = spdk_jsonrpc_begin_result(request);
764 	if (w == NULL) {
765 		return -1;
766 	}
767 
768 	spdk_json_write_bool(w, true);
769 	spdk_jsonrpc_end_result(request, w);
770 	return 0;
771 
772 invalid:
773 	free_rpc_add_vhost_nvme_ctrlr_ns(rpc);
774 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
775 					 spdk_strerror(-rc));
776 	return rc;
777 }
778 
779 static void
780 spdk_rpc_add_vhost_nvme_ns(struct spdk_jsonrpc_request *request,
781 			   const struct spdk_json_val *params)
782 {
783 	struct rpc_add_vhost_nvme_ctrlr_ns *req;
784 	int rc;
785 
786 	req = calloc(1, sizeof(*req));
787 	if (req == NULL) {
788 		rc = -ENOMEM;
789 		goto invalid;
790 	}
791 
792 	req->request = request;
793 	if (spdk_json_decode_object(params, rpc_vhost_nvme_add_ns,
794 				    SPDK_COUNTOF(rpc_vhost_nvme_add_ns),
795 				    req)) {
796 		SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n");
797 		rc = -EINVAL;
798 		goto invalid;
799 	}
800 
801 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_add_vhost_nvme_ns_cb, req);
802 	return;
803 
804 invalid:
805 	if (req) {
806 		free_rpc_add_vhost_nvme_ctrlr_ns(req);
807 	}
808 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
809 					 spdk_strerror(-rc));
810 }
811 SPDK_RPC_REGISTER("add_vhost_nvme_ns", spdk_rpc_add_vhost_nvme_ns, SPDK_RPC_RUNTIME)
812 
813 
814 SPDK_LOG_REGISTER_COMPONENT("vhost_rpc", SPDK_LOG_VHOST_RPC)
815