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