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 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 297 rc = spdk_vhost_dev_remove(vdev); 298 spdk_vhost_unlock(); 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 336 spdk_json_write_named_object_begin(w, "backend_specific"); 337 vhost_dump_info_json(vdev, w); 338 spdk_json_write_object_end(w); 339 340 spdk_json_write_object_end(w); 341 } 342 343 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = { 344 {"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true}, 345 }; 346 347 static void 348 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req) 349 { 350 free(req->name); 351 } 352 353 static void 354 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request, 355 const struct spdk_json_val *params) 356 { 357 struct rpc_get_vhost_ctrlrs req = {0}; 358 struct spdk_json_write_ctx *w; 359 struct spdk_vhost_dev *vdev; 360 int rc; 361 362 if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders, 363 SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) { 364 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 365 rc = -EINVAL; 366 goto invalid; 367 } 368 369 spdk_vhost_lock(); 370 if (req.name != NULL) { 371 vdev = spdk_vhost_dev_find(req.name); 372 if (vdev == NULL) { 373 spdk_vhost_unlock(); 374 rc = -ENODEV; 375 goto invalid; 376 } 377 378 free_rpc_get_vhost_ctrlrs(&req); 379 380 w = spdk_jsonrpc_begin_result(request); 381 spdk_json_write_array_begin(w); 382 383 _rpc_get_vhost_controller(w, vdev); 384 spdk_vhost_unlock(); 385 386 spdk_json_write_array_end(w); 387 spdk_jsonrpc_end_result(request, w); 388 return; 389 } 390 391 free_rpc_get_vhost_ctrlrs(&req); 392 393 w = spdk_jsonrpc_begin_result(request); 394 spdk_json_write_array_begin(w); 395 396 vdev = spdk_vhost_dev_next(NULL); 397 while (vdev != NULL) { 398 _rpc_get_vhost_controller(w, vdev); 399 vdev = spdk_vhost_dev_next(vdev); 400 } 401 spdk_vhost_unlock(); 402 403 spdk_json_write_array_end(w); 404 spdk_jsonrpc_end_result(request, w); 405 return; 406 407 invalid: 408 free_rpc_get_vhost_ctrlrs(&req); 409 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 410 spdk_strerror(-rc)); 411 } 412 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME) 413 414 415 struct rpc_vhost_ctrlr_coalescing { 416 char *ctrlr; 417 uint32_t delay_base_us; 418 uint32_t iops_threshold; 419 }; 420 421 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = { 422 {"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string }, 423 {"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32}, 424 {"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32}, 425 }; 426 427 static void 428 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req) 429 { 430 free(req->ctrlr); 431 } 432 433 static void 434 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request, 435 const struct spdk_json_val *params) 436 { 437 struct rpc_vhost_ctrlr_coalescing req = {0}; 438 struct spdk_vhost_dev *vdev; 439 int rc; 440 441 if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing, 442 SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) { 443 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 444 rc = -EINVAL; 445 goto invalid; 446 } 447 448 spdk_vhost_lock(); 449 vdev = spdk_vhost_dev_find(req.ctrlr); 450 if (vdev == NULL) { 451 spdk_vhost_unlock(); 452 rc = -ENODEV; 453 goto invalid; 454 } 455 456 rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold); 457 spdk_vhost_unlock(); 458 if (rc) { 459 goto invalid; 460 } 461 462 free_rpc_set_vhost_controllers_event_coalescing(&req); 463 464 spdk_jsonrpc_send_bool_response(request, true); 465 return; 466 467 invalid: 468 free_rpc_set_vhost_controllers_event_coalescing(&req); 469 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 470 spdk_strerror(-rc)); 471 } 472 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing, 473 SPDK_RPC_RUNTIME) 474 475 struct rpc_virtio_blk_create_transport { 476 char *name; 477 }; 478 479 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = { 480 {"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string}, 481 }; 482 483 static void 484 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req) 485 { 486 free(req->name); 487 } 488 489 static void 490 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request, 491 const struct spdk_json_val *params) 492 { 493 struct rpc_virtio_blk_create_transport req = {0}; 494 int rc; 495 496 if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport, 497 SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) { 498 SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n"); 499 rc = -EINVAL; 500 goto invalid; 501 } 502 503 spdk_vhost_lock(); 504 rc = virtio_blk_transport_create(req.name, params); 505 spdk_vhost_unlock(); 506 if (rc != 0) { 507 goto invalid; 508 } 509 510 free_rpc_virtio_blk_create_transport(&req); 511 spdk_jsonrpc_send_bool_response(request, true); 512 return; 513 514 invalid: 515 free_rpc_virtio_blk_create_transport(&req); 516 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 517 } 518 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport, 519 SPDK_RPC_RUNTIME) 520 521 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc) 522