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 struct spdk_json_write_ctx *w; 455 struct spdk_jsonrpc_request *request; 456 }; 457 458 static int 459 spdk_rpc_get_vhost_controllers_cb(struct spdk_vhost_dev *vdev, void *arg) 460 { 461 struct rpc_get_vhost_ctrlrs *ctx = arg; 462 uint32_t delay_base_us, iops_threshold; 463 464 465 if (vdev == NULL) { 466 spdk_json_write_array_end(ctx->w); 467 spdk_jsonrpc_end_result(ctx->request, ctx->w); 468 free(ctx); 469 return 0; 470 } 471 472 spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold); 473 474 spdk_json_write_object_begin(ctx->w); 475 476 spdk_json_write_named_string(ctx->w, "ctrlr", spdk_vhost_dev_get_name(vdev)); 477 spdk_json_write_named_string_fmt(ctx->w, "cpumask", "0x%s", spdk_cpuset_fmt(vdev->cpumask)); 478 spdk_json_write_named_uint32(ctx->w, "delay_base_us", delay_base_us); 479 spdk_json_write_named_uint32(ctx->w, "iops_threshold", iops_threshold); 480 spdk_json_write_named_string(ctx->w, "socket", vdev->path); 481 482 spdk_json_write_named_object_begin(ctx->w, "backend_specific"); 483 spdk_vhost_dump_info_json(vdev, ctx->w); 484 spdk_json_write_object_end(ctx->w); 485 486 spdk_json_write_object_end(ctx->w); 487 return 0; 488 } 489 490 491 static void 492 spdk_rpc_get_vhost_controllers(struct spdk_jsonrpc_request *request, 493 const struct spdk_json_val *params) 494 { 495 struct rpc_get_vhost_ctrlrs *ctx; 496 struct spdk_json_write_ctx *w; 497 498 if (params != NULL) { 499 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 500 "get_vhost_controllers requires no parameters"); 501 return; 502 } 503 504 ctx = calloc(1, sizeof(*ctx)); 505 if (ctx == NULL) { 506 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 507 spdk_strerror(ENOMEM)); 508 return; 509 } 510 511 w = spdk_jsonrpc_begin_result(request); 512 if (w == NULL) { 513 free(ctx); 514 return; 515 } 516 517 spdk_json_write_array_begin(w); 518 519 ctx->w = w; 520 ctx->request = request; 521 spdk_vhost_call_external_event_foreach(spdk_rpc_get_vhost_controllers_cb, ctx); 522 } 523 SPDK_RPC_REGISTER("get_vhost_controllers", spdk_rpc_get_vhost_controllers, SPDK_RPC_RUNTIME) 524 525 526 struct rpc_vhost_ctrlr_coalescing { 527 char *ctrlr; 528 uint32_t delay_base_us; 529 uint32_t iops_threshold; 530 struct spdk_jsonrpc_request *request; 531 }; 532 533 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = { 534 {"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string }, 535 {"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32}, 536 {"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32}, 537 }; 538 539 static void 540 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req) 541 { 542 if (!req) { 543 return; 544 } 545 546 free(req->ctrlr); 547 free(req); 548 } 549 550 static int 551 spdk_rpc_set_vhost_controller_coalescing_cb(struct spdk_vhost_dev *vdev, void *arg) 552 { 553 struct rpc_vhost_ctrlr_coalescing *req = arg; 554 struct spdk_json_write_ctx *w; 555 int rc; 556 557 if (vdev == NULL) { 558 rc = -ENODEV; 559 goto invalid; 560 } 561 562 rc = spdk_vhost_set_coalescing(vdev, req->delay_base_us, req->iops_threshold); 563 if (rc) { 564 goto invalid; 565 } 566 567 w = spdk_jsonrpc_begin_result(req->request); 568 if (w != NULL) { 569 spdk_json_write_bool(w, true); 570 spdk_jsonrpc_end_result(req->request, w); 571 } 572 573 free_rpc_set_vhost_controllers_event_coalescing(req); 574 return 0; 575 576 invalid: 577 spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 578 spdk_strerror(-rc)); 579 free_rpc_set_vhost_controllers_event_coalescing(req); 580 return 0; 581 } 582 583 static void 584 spdk_rpc_set_vhost_controller_coalescing(struct spdk_jsonrpc_request *request, 585 const struct spdk_json_val *params) 586 { 587 struct rpc_vhost_ctrlr_coalescing *req; 588 int rc; 589 590 req = calloc(1, sizeof(struct rpc_vhost_ctrlr_coalescing)); 591 if (!req) { 592 rc = -ENOMEM; 593 goto invalid; 594 } 595 596 if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing, 597 SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), req)) { 598 SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n"); 599 rc = -EINVAL; 600 goto invalid; 601 } 602 603 req->request = request; 604 spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_set_vhost_controller_coalescing_cb, req); 605 return; 606 607 invalid: 608 free_rpc_set_vhost_controllers_event_coalescing(req); 609 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 610 spdk_strerror(-rc)); 611 } 612 SPDK_RPC_REGISTER("set_vhost_controller_coalescing", spdk_rpc_set_vhost_controller_coalescing, 613 SPDK_RPC_RUNTIME) 614 615 struct rpc_vhost_nvme_ctrlr { 616 char *ctrlr; 617 uint32_t io_queues; 618 char *cpumask; 619 }; 620 621 static const struct spdk_json_object_decoder rpc_construct_vhost_nvme_ctrlr[] = { 622 {"ctrlr", offsetof(struct rpc_vhost_nvme_ctrlr, ctrlr), spdk_json_decode_string }, 623 {"io_queues", offsetof(struct rpc_vhost_nvme_ctrlr, io_queues), spdk_json_decode_uint32}, 624 {"cpumask", offsetof(struct rpc_vhost_nvme_ctrlr, cpumask), spdk_json_decode_string, true}, 625 }; 626 627 static void 628 free_rpc_vhost_nvme_ctrlr(struct rpc_vhost_nvme_ctrlr *req) 629 { 630 free(req->ctrlr); 631 free(req->cpumask); 632 } 633 634 static void 635 spdk_rpc_construct_vhost_nvme_controller(struct spdk_jsonrpc_request *request, 636 const struct spdk_json_val *params) 637 { 638 struct rpc_vhost_nvme_ctrlr req = {0}; 639 struct spdk_json_write_ctx *w; 640 int rc; 641 642 if (spdk_json_decode_object(params, rpc_construct_vhost_nvme_ctrlr, 643 SPDK_COUNTOF(rpc_construct_vhost_nvme_ctrlr), 644 &req)) { 645 rc = -EINVAL; 646 goto invalid; 647 } 648 649 rc = spdk_vhost_nvme_dev_construct(req.ctrlr, req.cpumask, req.io_queues); 650 if (rc < 0) { 651 free_rpc_vhost_nvme_ctrlr(&req); 652 goto invalid; 653 } 654 655 free_rpc_vhost_nvme_ctrlr(&req); 656 657 w = spdk_jsonrpc_begin_result(request); 658 if (w == NULL) { 659 return; 660 } 661 662 spdk_json_write_bool(w, true); 663 spdk_jsonrpc_end_result(request, w); 664 return; 665 666 invalid: 667 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 668 spdk_strerror(-rc)); 669 670 } 671 SPDK_RPC_REGISTER("construct_vhost_nvme_controller", spdk_rpc_construct_vhost_nvme_controller, 672 SPDK_RPC_RUNTIME) 673 674 struct rpc_add_vhost_nvme_ctrlr_ns { 675 char *ctrlr; 676 char *bdev_name; 677 struct spdk_jsonrpc_request *request; 678 }; 679 680 static void 681 free_rpc_add_vhost_nvme_ctrlr_ns(struct rpc_add_vhost_nvme_ctrlr_ns *req) 682 { 683 free(req->ctrlr); 684 free(req->bdev_name); 685 free(req); 686 } 687 688 static const struct spdk_json_object_decoder rpc_vhost_nvme_add_ns[] = { 689 {"ctrlr", offsetof(struct rpc_add_vhost_nvme_ctrlr_ns, ctrlr), spdk_json_decode_string }, 690 {"bdev_name", offsetof(struct rpc_add_vhost_nvme_ctrlr_ns, bdev_name), spdk_json_decode_string }, 691 }; 692 693 static int 694 spdk_rpc_add_vhost_nvme_ns_cb(struct spdk_vhost_dev *vdev, void *arg) 695 { 696 struct rpc_add_vhost_nvme_ctrlr_ns *rpc = arg; 697 struct spdk_jsonrpc_request *request = rpc->request; 698 struct spdk_json_write_ctx *w; 699 int rc; 700 701 if (vdev == NULL) { 702 rc = -ENODEV; 703 goto invalid; 704 } 705 706 rc = spdk_vhost_nvme_dev_add_ns(vdev, rpc->bdev_name); 707 if (rc < 0) { 708 goto invalid; 709 } 710 free_rpc_add_vhost_nvme_ctrlr_ns(rpc); 711 712 w = spdk_jsonrpc_begin_result(request); 713 if (w == NULL) { 714 return -1; 715 } 716 717 spdk_json_write_bool(w, true); 718 spdk_jsonrpc_end_result(request, w); 719 return 0; 720 721 invalid: 722 free_rpc_add_vhost_nvme_ctrlr_ns(rpc); 723 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 724 spdk_strerror(-rc)); 725 return rc; 726 } 727 728 static void 729 spdk_rpc_add_vhost_nvme_ns(struct spdk_jsonrpc_request *request, 730 const struct spdk_json_val *params) 731 { 732 struct rpc_add_vhost_nvme_ctrlr_ns *req; 733 int rc; 734 735 req = calloc(1, sizeof(*req)); 736 if (req == NULL) { 737 rc = -ENOMEM; 738 goto invalid; 739 } 740 741 req->request = request; 742 if (spdk_json_decode_object(params, rpc_vhost_nvme_add_ns, 743 SPDK_COUNTOF(rpc_vhost_nvme_add_ns), 744 req)) { 745 SPDK_DEBUGLOG(SPDK_LOG_VHOST_RPC, "spdk_json_decode_object failed\n"); 746 rc = -EINVAL; 747 goto invalid; 748 } 749 750 spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_add_vhost_nvme_ns_cb, req); 751 return; 752 753 invalid: 754 if (req) { 755 free_rpc_add_vhost_nvme_ctrlr_ns(req); 756 } 757 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 758 spdk_strerror(-rc)); 759 } 760 SPDK_RPC_REGISTER("add_vhost_nvme_ns", spdk_rpc_add_vhost_nvme_ns, SPDK_RPC_RUNTIME) 761 762 763 SPDK_LOG_REGISTER_COMPONENT("vhost_rpc", SPDK_LOG_VHOST_RPC) 764