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/log.h" 14 #include "spdk/scsi.h" 15 #include "spdk/vhost.h" 16 #include "vhost_internal.h" 17 #include "spdk/bdev.h" 18 19 struct rpc_vhost_scsi_ctrlr { 20 char *ctrlr; 21 char *cpumask; 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 }; 35 36 static void 37 rpc_vhost_create_scsi_controller(struct spdk_jsonrpc_request *request, 38 const struct spdk_json_val *params) 39 { 40 struct rpc_vhost_scsi_ctrlr req = {0}; 41 int rc; 42 43 if (spdk_json_decode_object(params, rpc_vhost_create_scsi_ctrlr, 44 SPDK_COUNTOF(rpc_vhost_create_scsi_ctrlr), 45 &req)) { 46 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 47 rc = -EINVAL; 48 goto invalid; 49 } 50 51 rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask); 52 if (rc < 0) { 53 goto invalid; 54 } 55 56 free_rpc_vhost_scsi_ctrlr(&req); 57 58 spdk_jsonrpc_send_bool_response(request, true); 59 return; 60 61 invalid: 62 free_rpc_vhost_scsi_ctrlr(&req); 63 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 64 spdk_strerror(-rc)); 65 } 66 SPDK_RPC_REGISTER("vhost_create_scsi_controller", rpc_vhost_create_scsi_controller, 67 SPDK_RPC_RUNTIME) 68 69 struct rpc_vhost_scsi_ctrlr_add_target { 70 char *ctrlr; 71 int32_t scsi_target_num; 72 char *bdev_name; 73 }; 74 75 static void 76 free_rpc_vhost_scsi_ctrlr_add_target(struct rpc_vhost_scsi_ctrlr_add_target *req) 77 { 78 free(req->ctrlr); 79 free(req->bdev_name); 80 } 81 82 static const struct spdk_json_object_decoder rpc_vhost_scsi_ctrlr_add_target[] = { 83 {"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, ctrlr), spdk_json_decode_string }, 84 {"scsi_target_num", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, scsi_target_num), spdk_json_decode_int32}, 85 {"bdev_name", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, bdev_name), spdk_json_decode_string }, 86 }; 87 88 static void 89 rpc_vhost_scsi_controller_add_target(struct spdk_jsonrpc_request *request, 90 const struct spdk_json_val *params) 91 { 92 struct rpc_vhost_scsi_ctrlr_add_target req = {0}; 93 struct spdk_json_write_ctx *w; 94 struct spdk_vhost_dev *vdev; 95 int rc; 96 97 if (spdk_json_decode_object(params, rpc_vhost_scsi_ctrlr_add_target, 98 SPDK_COUNTOF(rpc_vhost_scsi_ctrlr_add_target), 99 &req)) { 100 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 101 rc = -EINVAL; 102 goto invalid; 103 } 104 105 spdk_vhost_lock(); 106 vdev = spdk_vhost_dev_find(req.ctrlr); 107 if (vdev == NULL) { 108 spdk_vhost_unlock(); 109 rc = -ENODEV; 110 goto invalid; 111 } 112 113 rc = spdk_vhost_scsi_dev_add_tgt(vdev, req.scsi_target_num, req.bdev_name); 114 spdk_vhost_unlock(); 115 if (rc < 0) { 116 goto invalid; 117 } 118 119 free_rpc_vhost_scsi_ctrlr_add_target(&req); 120 121 w = spdk_jsonrpc_begin_result(request); 122 spdk_json_write_int32(w, rc); 123 spdk_jsonrpc_end_result(request, w); 124 return; 125 126 invalid: 127 free_rpc_vhost_scsi_ctrlr_add_target(&req); 128 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 129 spdk_strerror(-rc)); 130 } 131 SPDK_RPC_REGISTER("vhost_scsi_controller_add_target", rpc_vhost_scsi_controller_add_target, 132 SPDK_RPC_RUNTIME) 133 134 struct rpc_remove_vhost_scsi_ctrlr_target { 135 char *ctrlr; 136 uint32_t scsi_target_num; 137 }; 138 139 static void 140 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req) 141 { 142 free(req->ctrlr); 143 } 144 145 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = { 146 {"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string }, 147 {"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32}, 148 }; 149 150 static int 151 rpc_vhost_scsi_controller_remove_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg) 152 { 153 struct spdk_jsonrpc_request *request = arg; 154 155 spdk_jsonrpc_send_bool_response(request, true); 156 return 0; 157 } 158 159 static void 160 rpc_vhost_scsi_controller_remove_target(struct spdk_jsonrpc_request *request, 161 const struct spdk_json_val *params) 162 { 163 struct rpc_remove_vhost_scsi_ctrlr_target req = {0}; 164 struct spdk_vhost_dev *vdev; 165 int rc; 166 167 if (spdk_json_decode_object(params, rpc_vhost_remove_target, 168 SPDK_COUNTOF(rpc_vhost_remove_target), 169 &req)) { 170 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 171 rc = -EINVAL; 172 goto invalid; 173 } 174 175 spdk_vhost_lock(); 176 vdev = spdk_vhost_dev_find(req.ctrlr); 177 if (vdev == NULL) { 178 spdk_vhost_unlock(); 179 rc = -ENODEV; 180 goto invalid; 181 } 182 183 rc = spdk_vhost_scsi_dev_remove_tgt(vdev, req.scsi_target_num, 184 rpc_vhost_scsi_controller_remove_target_finish_cb, 185 request); 186 spdk_vhost_unlock(); 187 if (rc < 0) { 188 goto invalid; 189 } 190 191 free_rpc_remove_vhost_scsi_ctrlr_target(&req); 192 return; 193 194 invalid: 195 free_rpc_remove_vhost_scsi_ctrlr_target(&req); 196 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 197 spdk_strerror(-rc)); 198 } 199 200 SPDK_RPC_REGISTER("vhost_scsi_controller_remove_target", 201 rpc_vhost_scsi_controller_remove_target, SPDK_RPC_RUNTIME) 202 203 struct rpc_vhost_blk_ctrlr { 204 char *ctrlr; 205 char *dev_name; 206 char *cpumask; 207 char *transport; 208 }; 209 210 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = { 211 {"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string }, 212 {"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string }, 213 {"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true}, 214 {"transport", offsetof(struct rpc_vhost_blk_ctrlr, transport), spdk_json_decode_string, true}, 215 }; 216 217 static void 218 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req) 219 { 220 free(req->ctrlr); 221 free(req->dev_name); 222 free(req->cpumask); 223 free(req->transport); 224 } 225 226 static void 227 rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request, 228 const struct spdk_json_val *params) 229 { 230 struct rpc_vhost_blk_ctrlr req = {0}; 231 int rc; 232 233 if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk_ctrlr, 234 SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr), 235 &req)) { 236 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 237 rc = -EINVAL; 238 goto invalid; 239 } 240 241 rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.transport, params); 242 if (rc < 0) { 243 goto invalid; 244 } 245 246 free_rpc_vhost_blk_ctrlr(&req); 247 248 spdk_jsonrpc_send_bool_response(request, true); 249 return; 250 251 invalid: 252 free_rpc_vhost_blk_ctrlr(&req); 253 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 254 spdk_strerror(-rc)); 255 256 } 257 SPDK_RPC_REGISTER("vhost_create_blk_controller", rpc_vhost_create_blk_controller, 258 SPDK_RPC_RUNTIME) 259 260 struct rpc_delete_vhost_ctrlr { 261 char *ctrlr; 262 }; 263 264 static const struct spdk_json_object_decoder rpc_delete_vhost_ctrlr_decoder[] = { 265 {"ctrlr", offsetof(struct rpc_delete_vhost_ctrlr, ctrlr), spdk_json_decode_string }, 266 }; 267 268 static void 269 free_rpc_delete_vhost_ctrlr(struct rpc_delete_vhost_ctrlr *req) 270 { 271 free(req->ctrlr); 272 } 273 274 static void 275 rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request, 276 const struct spdk_json_val *params) 277 { 278 struct rpc_delete_vhost_ctrlr req = {0}; 279 struct spdk_vhost_dev *vdev; 280 int rc; 281 282 if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder, 283 SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) { 284 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 285 rc = -EINVAL; 286 goto invalid; 287 } 288 289 spdk_vhost_lock(); 290 vdev = spdk_vhost_dev_find(req.ctrlr); 291 if (vdev == NULL) { 292 spdk_vhost_unlock(); 293 rc = -ENODEV; 294 goto invalid; 295 } 296 spdk_vhost_unlock(); 297 298 rc = spdk_vhost_dev_remove(vdev); 299 if (rc < 0) { 300 goto invalid; 301 } 302 303 free_rpc_delete_vhost_ctrlr(&req); 304 305 spdk_jsonrpc_send_bool_response(request, true); 306 return; 307 308 invalid: 309 free_rpc_delete_vhost_ctrlr(&req); 310 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 311 spdk_strerror(-rc)); 312 313 } 314 SPDK_RPC_REGISTER("vhost_delete_controller", rpc_vhost_delete_controller, SPDK_RPC_RUNTIME) 315 316 struct rpc_get_vhost_ctrlrs { 317 char *name; 318 }; 319 320 static void 321 _rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev) 322 { 323 uint32_t delay_base_us, iops_threshold; 324 325 spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold); 326 327 spdk_json_write_object_begin(w); 328 329 spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev)); 330 spdk_json_write_named_string_fmt(w, "cpumask", "0x%s", 331 spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread))); 332 spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us); 333 spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold); 334 spdk_json_write_named_string(w, "socket", vdev->path); 335 spdk_json_write_named_array_begin(w, "sessions"); 336 vhost_session_info_json(vdev, w); 337 spdk_json_write_array_end(w); 338 339 spdk_json_write_named_object_begin(w, "backend_specific"); 340 vhost_dump_info_json(vdev, w); 341 spdk_json_write_object_end(w); 342 343 spdk_json_write_object_end(w); 344 } 345 346 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = { 347 {"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true}, 348 }; 349 350 static void 351 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req) 352 { 353 free(req->name); 354 } 355 356 static void 357 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request, 358 const struct spdk_json_val *params) 359 { 360 struct rpc_get_vhost_ctrlrs req = {0}; 361 struct spdk_json_write_ctx *w; 362 struct spdk_vhost_dev *vdev; 363 int rc; 364 365 if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders, 366 SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) { 367 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 368 rc = -EINVAL; 369 goto invalid; 370 } 371 372 spdk_vhost_lock(); 373 if (req.name != NULL) { 374 vdev = spdk_vhost_dev_find(req.name); 375 if (vdev == NULL) { 376 spdk_vhost_unlock(); 377 rc = -ENODEV; 378 goto invalid; 379 } 380 381 free_rpc_get_vhost_ctrlrs(&req); 382 383 w = spdk_jsonrpc_begin_result(request); 384 spdk_json_write_array_begin(w); 385 386 _rpc_get_vhost_controller(w, vdev); 387 spdk_vhost_unlock(); 388 389 spdk_json_write_array_end(w); 390 spdk_jsonrpc_end_result(request, w); 391 return; 392 } 393 394 free_rpc_get_vhost_ctrlrs(&req); 395 396 w = spdk_jsonrpc_begin_result(request); 397 spdk_json_write_array_begin(w); 398 399 vdev = spdk_vhost_dev_next(NULL); 400 while (vdev != NULL) { 401 _rpc_get_vhost_controller(w, vdev); 402 vdev = spdk_vhost_dev_next(vdev); 403 } 404 spdk_vhost_unlock(); 405 406 spdk_json_write_array_end(w); 407 spdk_jsonrpc_end_result(request, w); 408 return; 409 410 invalid: 411 free_rpc_get_vhost_ctrlrs(&req); 412 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 413 spdk_strerror(-rc)); 414 } 415 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME) 416 417 418 struct rpc_vhost_ctrlr_coalescing { 419 char *ctrlr; 420 uint32_t delay_base_us; 421 uint32_t iops_threshold; 422 }; 423 424 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = { 425 {"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string }, 426 {"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32}, 427 {"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32}, 428 }; 429 430 static void 431 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req) 432 { 433 free(req->ctrlr); 434 } 435 436 static void 437 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request, 438 const struct spdk_json_val *params) 439 { 440 struct rpc_vhost_ctrlr_coalescing req = {0}; 441 struct spdk_vhost_dev *vdev; 442 int rc; 443 444 if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing, 445 SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) { 446 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 447 rc = -EINVAL; 448 goto invalid; 449 } 450 451 spdk_vhost_lock(); 452 vdev = spdk_vhost_dev_find(req.ctrlr); 453 if (vdev == NULL) { 454 spdk_vhost_unlock(); 455 rc = -ENODEV; 456 goto invalid; 457 } 458 459 rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold); 460 spdk_vhost_unlock(); 461 if (rc) { 462 goto invalid; 463 } 464 465 free_rpc_set_vhost_controllers_event_coalescing(&req); 466 467 spdk_jsonrpc_send_bool_response(request, true); 468 return; 469 470 invalid: 471 free_rpc_set_vhost_controllers_event_coalescing(&req); 472 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 473 spdk_strerror(-rc)); 474 } 475 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing, 476 SPDK_RPC_RUNTIME) 477 478 struct rpc_get_transport { 479 char *name; 480 }; 481 482 static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = { 483 {"name", offsetof(struct rpc_get_transport, name), spdk_json_decode_string, true}, 484 }; 485 486 static void 487 rpc_virtio_blk_get_transports(struct spdk_jsonrpc_request *request, 488 const struct spdk_json_val *params) 489 { 490 struct rpc_get_transport req = { 0 }; 491 struct spdk_json_write_ctx *w; 492 struct spdk_virtio_blk_transport *transport = NULL; 493 494 if (params) { 495 if (spdk_json_decode_object(params, rpc_get_transport_decoders, 496 SPDK_COUNTOF(rpc_get_transport_decoders), 497 &req)) { 498 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 499 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 500 return; 501 } 502 } 503 504 if (req.name) { 505 transport = virtio_blk_tgt_get_transport(req.name); 506 if (transport == NULL) { 507 SPDK_ERRLOG("transport '%s' does not exist\n", req.name); 508 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 509 free(req.name); 510 return; 511 } 512 } 513 514 w = spdk_jsonrpc_begin_result(request); 515 spdk_json_write_array_begin(w); 516 517 if (transport) { 518 virtio_blk_transport_dump_opts(transport, w); 519 } else { 520 for (transport = virtio_blk_transport_get_first(); transport != NULL; 521 transport = virtio_blk_transport_get_next(transport)) { 522 virtio_blk_transport_dump_opts(transport, w); 523 } 524 } 525 526 spdk_json_write_array_end(w); 527 spdk_jsonrpc_end_result(request, w); 528 free(req.name); 529 } 530 SPDK_RPC_REGISTER("virtio_blk_get_transports", rpc_virtio_blk_get_transports, SPDK_RPC_RUNTIME) 531 532 struct rpc_virtio_blk_create_transport { 533 char *name; 534 }; 535 536 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = { 537 {"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string}, 538 }; 539 540 static void 541 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req) 542 { 543 free(req->name); 544 } 545 546 static void 547 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request, 548 const struct spdk_json_val *params) 549 { 550 struct rpc_virtio_blk_create_transport req = {0}; 551 int rc; 552 553 if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport, 554 SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) { 555 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 556 rc = -EINVAL; 557 goto invalid; 558 } 559 560 spdk_vhost_lock(); 561 rc = virtio_blk_transport_create(req.name, params); 562 spdk_vhost_unlock(); 563 if (rc != 0) { 564 goto invalid; 565 } 566 567 free_rpc_virtio_blk_create_transport(&req); 568 spdk_jsonrpc_send_bool_response(request, true); 569 return; 570 571 invalid: 572 free_rpc_virtio_blk_create_transport(&req); 573 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 574 } 575 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport, 576 SPDK_RPC_RUNTIME) 577 578 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc) 579