1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2019 Mellanox Technologies LTD. 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/event.h" 37 #include "spdk/rpc.h" 38 #include "spdk/string.h" 39 #include "spdk/util.h" 40 #include "spdk/env.h" 41 #include "spdk/thread.h" 42 43 #include "spdk/log.h" 44 #include "spdk_internal/event.h" 45 #include "spdk_internal/thread.h" 46 47 struct rpc_spdk_kill_instance { 48 char *sig_name; 49 }; 50 51 static void 52 free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req) 53 { 54 free(req->sig_name); 55 } 56 57 static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = { 58 {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string}, 59 }; 60 61 static void 62 rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request, 63 const struct spdk_json_val *params) 64 { 65 static const struct { 66 const char *signal_string; 67 int32_t signal; 68 } signals[] = { 69 {"SIGINT", SIGINT}, 70 {"SIGTERM", SIGTERM}, 71 {"SIGQUIT", SIGQUIT}, 72 {"SIGHUP", SIGHUP}, 73 {"SIGKILL", SIGKILL}, 74 {"SIGUSR1", SIGUSR1}, 75 }; 76 size_t i, sig_count; 77 int signal; 78 struct rpc_spdk_kill_instance req = {}; 79 80 if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders, 81 SPDK_COUNTOF(rpc_spdk_kill_instance_decoders), 82 &req)) { 83 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 84 goto invalid; 85 } 86 87 sig_count = SPDK_COUNTOF(signals); 88 signal = spdk_strtol(req.sig_name, 10); 89 for (i = 0 ; i < sig_count; i++) { 90 if (strcmp(req.sig_name, signals[i].signal_string) == 0 || 91 signal == signals[i].signal) { 92 break; 93 } 94 } 95 96 if (i == sig_count) { 97 goto invalid; 98 } 99 100 SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal); 101 free_rpc_spdk_kill_instance(&req); 102 kill(getpid(), signals[i].signal); 103 104 spdk_jsonrpc_send_bool_response(request, true); 105 return; 106 107 invalid: 108 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 109 free_rpc_spdk_kill_instance(&req); 110 } 111 SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME) 112 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(spdk_kill_instance, kill_instance) 113 114 115 struct rpc_framework_monitor_context_switch { 116 bool enabled; 117 }; 118 119 static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = { 120 {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool}, 121 }; 122 123 static void 124 rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request, 125 const struct spdk_json_val *params) 126 { 127 struct rpc_framework_monitor_context_switch req = {}; 128 struct spdk_json_write_ctx *w; 129 130 if (params != NULL) { 131 if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders, 132 SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders), 133 &req)) { 134 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 135 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 136 return; 137 } 138 139 spdk_framework_enable_context_switch_monitor(req.enabled); 140 } 141 142 w = spdk_jsonrpc_begin_result(request); 143 spdk_json_write_object_begin(w); 144 145 spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled()); 146 147 spdk_json_write_object_end(w); 148 spdk_jsonrpc_end_result(request, w); 149 } 150 151 SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch, 152 SPDK_RPC_RUNTIME) 153 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_monitor_context_switch, context_switch_monitor) 154 155 struct rpc_get_stats_ctx { 156 struct spdk_jsonrpc_request *request; 157 struct spdk_json_write_ctx *w; 158 uint64_t now; 159 }; 160 161 static void 162 rpc_thread_get_stats_done(void *arg) 163 { 164 struct rpc_get_stats_ctx *ctx = arg; 165 166 spdk_json_write_array_end(ctx->w); 167 spdk_json_write_object_end(ctx->w); 168 spdk_jsonrpc_end_result(ctx->request, ctx->w); 169 170 free(ctx); 171 } 172 173 static void 174 rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn) 175 { 176 struct rpc_get_stats_ctx *ctx; 177 178 ctx = calloc(1, sizeof(*ctx)); 179 if (!ctx) { 180 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 181 "Memory allocation error"); 182 return; 183 } 184 ctx->request = request; 185 186 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 187 spdk_json_write_object_begin(ctx->w); 188 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 189 spdk_json_write_named_array_begin(ctx->w, "threads"); 190 191 spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done); 192 } 193 194 static void 195 _rpc_thread_get_stats(void *arg) 196 { 197 struct rpc_get_stats_ctx *ctx = arg; 198 struct spdk_thread *thread = spdk_get_thread(); 199 struct spdk_cpuset tmp_mask = {}; 200 struct spdk_poller *poller; 201 struct spdk_thread_stats stats; 202 uint64_t active_pollers_count = 0; 203 uint64_t timed_pollers_count = 0; 204 uint64_t paused_pollers_count = 0; 205 206 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 207 poller = spdk_thread_get_next_active_poller(poller)) { 208 active_pollers_count++; 209 } 210 211 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 212 poller = spdk_thread_get_next_timed_poller(poller)) { 213 timed_pollers_count++; 214 } 215 216 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 217 poller = spdk_thread_get_next_paused_poller(poller)) { 218 paused_pollers_count++; 219 } 220 221 if (0 == spdk_thread_get_stats(&stats)) { 222 spdk_json_write_object_begin(ctx->w); 223 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 224 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 225 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 226 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 227 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 228 spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc); 229 spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc); 230 spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count); 231 spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count); 232 spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count); 233 spdk_json_write_object_end(ctx->w); 234 } 235 } 236 237 static void 238 rpc_thread_get_stats(struct spdk_jsonrpc_request *request, 239 const struct spdk_json_val *params) 240 { 241 if (params) { 242 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 243 "'thread_get_stats' requires no arguments"); 244 return; 245 } 246 247 rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats); 248 } 249 250 SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME) 251 252 static void 253 rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w) 254 { 255 struct spdk_poller_stats stats; 256 uint64_t period_ticks; 257 258 period_ticks = spdk_poller_get_period_ticks(poller); 259 spdk_poller_get_stats(poller, &stats); 260 261 spdk_json_write_object_begin(w); 262 spdk_json_write_named_string(w, "name", spdk_poller_get_name(poller)); 263 spdk_json_write_named_string(w, "state", spdk_poller_get_state_str(poller)); 264 spdk_json_write_named_uint64(w, "run_count", stats.run_count); 265 spdk_json_write_named_uint64(w, "busy_count", stats.busy_count); 266 if (period_ticks) { 267 spdk_json_write_named_uint64(w, "period_ticks", period_ticks); 268 } 269 spdk_json_write_object_end(w); 270 } 271 272 static void 273 _rpc_thread_get_pollers(void *arg) 274 { 275 struct rpc_get_stats_ctx *ctx = arg; 276 struct spdk_thread *thread = spdk_get_thread(); 277 struct spdk_poller *poller; 278 279 spdk_json_write_object_begin(ctx->w); 280 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 281 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 282 283 spdk_json_write_named_array_begin(ctx->w, "active_pollers"); 284 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 285 poller = spdk_thread_get_next_active_poller(poller)) { 286 rpc_get_poller(poller, ctx->w); 287 } 288 spdk_json_write_array_end(ctx->w); 289 290 spdk_json_write_named_array_begin(ctx->w, "timed_pollers"); 291 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 292 poller = spdk_thread_get_next_timed_poller(poller)) { 293 rpc_get_poller(poller, ctx->w); 294 } 295 spdk_json_write_array_end(ctx->w); 296 297 spdk_json_write_named_array_begin(ctx->w, "paused_pollers"); 298 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 299 poller = spdk_thread_get_next_paused_poller(poller)) { 300 rpc_get_poller(poller, ctx->w); 301 } 302 spdk_json_write_array_end(ctx->w); 303 304 spdk_json_write_object_end(ctx->w); 305 } 306 307 static void 308 rpc_thread_get_pollers(struct spdk_jsonrpc_request *request, 309 const struct spdk_json_val *params) 310 { 311 if (params) { 312 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 313 "'thread_get_pollers' requires no arguments"); 314 return; 315 } 316 317 rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers); 318 } 319 320 SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME) 321 322 static void 323 rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w) 324 { 325 spdk_json_write_object_begin(w); 326 spdk_json_write_named_string(w, "name", spdk_io_channel_get_io_device_name(ch)); 327 spdk_json_write_named_uint32(w, "ref", spdk_io_channel_get_ref_count(ch)); 328 spdk_json_write_object_end(w); 329 } 330 331 static void 332 _rpc_thread_get_io_channels(void *arg) 333 { 334 struct rpc_get_stats_ctx *ctx = arg; 335 struct spdk_thread *thread = spdk_get_thread(); 336 struct spdk_io_channel *ch; 337 338 spdk_json_write_object_begin(ctx->w); 339 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 340 341 spdk_json_write_named_array_begin(ctx->w, "io_channels"); 342 for (ch = spdk_thread_get_first_io_channel(thread); ch != NULL; 343 ch = spdk_thread_get_next_io_channel(ch)) { 344 rpc_get_io_channel(ch, ctx->w); 345 } 346 spdk_json_write_array_end(ctx->w); 347 348 spdk_json_write_object_end(ctx->w); 349 } 350 351 static void 352 rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request, 353 const struct spdk_json_val *params) 354 { 355 if (params) { 356 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 357 "'thread_get_io_channels' requires no arguments"); 358 return; 359 } 360 361 rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels); 362 } 363 364 SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME); 365 366 static void 367 rpc_framework_get_reactors_done(void *arg1, void *arg2) 368 { 369 struct rpc_get_stats_ctx *ctx = arg1; 370 371 spdk_json_write_array_end(ctx->w); 372 spdk_json_write_object_end(ctx->w); 373 spdk_jsonrpc_end_result(ctx->request, ctx->w); 374 375 free(ctx); 376 } 377 378 #define GET_DELTA(end, start) (end >= start ? end - start : 0) 379 380 static void 381 _rpc_framework_get_reactors(void *arg1, void *arg2) 382 { 383 struct rpc_get_stats_ctx *ctx = arg1; 384 uint32_t current_core; 385 uint32_t curr_core_freq; 386 struct spdk_reactor *reactor; 387 struct spdk_lw_thread *lw_thread; 388 struct spdk_thread *thread; 389 struct spdk_cpuset tmp_mask = {}; 390 struct spdk_governor *governor; 391 struct spdk_governor_capabilities capabilities; 392 393 current_core = spdk_env_get_current_core(); 394 reactor = spdk_reactor_get(current_core); 395 396 assert(reactor != NULL); 397 398 spdk_json_write_object_begin(ctx->w); 399 spdk_json_write_named_uint32(ctx->w, "lcore", current_core); 400 spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc); 401 spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc); 402 governor = _spdk_governor_get(); 403 /* We need to check whether governor can return current core frequency. */ 404 if (governor->get_core_capabilities && governor->get_core_freqs) { 405 governor->get_core_capabilities(current_core, &capabilities); 406 if (capabilities.freq_getset) { 407 /* Governor returns core freqs in kHz, we want MHz. */ 408 curr_core_freq = governor->get_core_curr_freq(current_core) / 1000; 409 spdk_json_write_named_uint32(ctx->w, "core_freq", curr_core_freq); 410 } 411 } 412 413 spdk_json_write_named_array_begin(ctx->w, "lw_threads"); 414 TAILQ_FOREACH(lw_thread, &reactor->threads, link) { 415 thread = spdk_thread_get_from_ctx(lw_thread); 416 417 spdk_json_write_object_begin(ctx->w); 418 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 419 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 420 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 421 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 422 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 423 spdk_json_write_named_uint64(ctx->w, "elapsed", 424 GET_DELTA(ctx->now, lw_thread->tsc_start)); 425 spdk_json_write_object_end(ctx->w); 426 } 427 spdk_json_write_array_end(ctx->w); 428 429 spdk_json_write_object_end(ctx->w); 430 } 431 432 static void 433 rpc_framework_get_reactors(struct spdk_jsonrpc_request *request, 434 const struct spdk_json_val *params) 435 { 436 struct rpc_get_stats_ctx *ctx; 437 438 if (params) { 439 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 440 "`framework_get_reactors` requires no arguments"); 441 return; 442 } 443 444 ctx = calloc(1, sizeof(*ctx)); 445 if (!ctx) { 446 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 447 "Memory allocation error"); 448 return; 449 } 450 451 ctx->now = spdk_get_ticks(); 452 ctx->request = request; 453 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 454 455 spdk_json_write_object_begin(ctx->w); 456 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 457 spdk_json_write_named_array_begin(ctx->w, "reactors"); 458 459 spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL, 460 rpc_framework_get_reactors_done); 461 } 462 463 SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME) 464 465 struct rpc_set_scheduler_ctx { 466 char *name; 467 uint64_t period; 468 }; 469 470 static void 471 free_rpc_framework_set_scheduler(struct rpc_set_scheduler_ctx *r) 472 { 473 free(r->name); 474 } 475 476 static const struct spdk_json_object_decoder rpc_set_scheduler_decoders[] = { 477 {"name", offsetof(struct rpc_set_scheduler_ctx, name), spdk_json_decode_string}, 478 {"period", offsetof(struct rpc_set_scheduler_ctx, period), spdk_json_decode_uint64, true} 479 }; 480 481 static void 482 rpc_framework_set_scheduler(struct spdk_jsonrpc_request *request, 483 const struct spdk_json_val *params) 484 { 485 struct rpc_set_scheduler_ctx req = {NULL}; 486 int ret; 487 488 ret = spdk_json_decode_object(params, rpc_set_scheduler_decoders, 489 SPDK_COUNTOF(rpc_set_scheduler_decoders), 490 &req); 491 if (ret) { 492 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 493 "Invalid parameters"); 494 goto end; 495 } 496 497 if (req.period != 0) { 498 _spdk_scheduler_period_set(req.period); 499 } 500 501 ret = _spdk_scheduler_set(req.name); 502 if (ret) { 503 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 504 spdk_strerror(ret)); 505 goto end; 506 } 507 508 spdk_jsonrpc_send_bool_response(request, true); 509 510 end: 511 free_rpc_framework_set_scheduler(&req); 512 } 513 SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler, SPDK_RPC_STARTUP) 514 515 static void 516 rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request, 517 const struct spdk_json_val *params) 518 { 519 struct spdk_json_write_ctx *w; 520 struct spdk_scheduler *scheduler = _spdk_scheduler_get(); 521 uint64_t scheduler_period = _spdk_scheduler_period_get(); 522 struct spdk_governor *governor = _spdk_governor_get(); 523 524 if (params) { 525 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 526 "'rpc_get_scheduler' requires no arguments"); 527 return; 528 } 529 530 w = spdk_jsonrpc_begin_result(request); 531 spdk_json_write_object_begin(w); 532 spdk_json_write_named_string(w, "scheduler_name", scheduler->name); 533 spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period); 534 spdk_json_write_named_string(w, "governor_name", governor->name); 535 spdk_json_write_object_end(w); 536 spdk_jsonrpc_end_result(request, w); 537 } 538 SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler, SPDK_RPC_RUNTIME) 539 540 struct rpc_thread_set_cpumask_ctx { 541 struct spdk_jsonrpc_request *request; 542 struct spdk_cpuset cpumask; 543 int status; 544 struct spdk_thread *orig_thread; 545 }; 546 547 static void 548 rpc_thread_set_cpumask_done(void *_ctx) 549 { 550 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 551 552 if (ctx->status == 0) { 553 spdk_jsonrpc_send_bool_response(ctx->request, true); 554 } else { 555 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 556 spdk_strerror(-ctx->status)); 557 } 558 559 free(ctx); 560 } 561 562 static void 563 _rpc_thread_set_cpumask(void *_ctx) 564 { 565 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 566 567 ctx->status = spdk_thread_set_cpumask(&ctx->cpumask); 568 569 spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx); 570 } 571 572 struct rpc_thread_set_cpumask { 573 uint64_t id; 574 char *cpumask; 575 }; 576 577 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = { 578 {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64}, 579 {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string}, 580 }; 581 582 static void 583 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request, 584 const struct spdk_json_val *params) 585 { 586 struct rpc_thread_set_cpumask req = {}; 587 struct rpc_thread_set_cpumask_ctx *ctx; 588 const struct spdk_cpuset *coremask; 589 struct spdk_cpuset tmp_mask; 590 struct spdk_thread *thread; 591 int rc; 592 593 ctx = calloc(1, sizeof(*ctx)); 594 if (ctx == NULL) { 595 SPDK_ERRLOG("Memory allocation failed\n"); 596 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 597 "Memory allocation failed"); 598 return; 599 } 600 601 if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders, 602 SPDK_COUNTOF(rpc_thread_set_cpumask_decoders), 603 &req)) { 604 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 605 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 606 "spdk_json_decode_object failed"); 607 goto err; 608 } 609 610 thread = spdk_thread_get_by_id(req.id); 611 if (thread == NULL) { 612 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id); 613 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 614 "Thread %" PRIu64 " does not exist", req.id); 615 goto err; 616 } 617 618 rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask); 619 if (rc != 0) { 620 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask); 621 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 622 "Invalid cpumask %s", req.cpumask); 623 goto err; 624 } 625 626 if (spdk_cpuset_count(&ctx->cpumask) == 0) { 627 coremask = spdk_app_get_core_mask(); 628 spdk_cpuset_copy(&tmp_mask, coremask); 629 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 630 "No CPU is selected from reactor mask %s\n", 631 spdk_cpuset_fmt(&tmp_mask)); 632 goto err; 633 } 634 635 /* There may be any reactors running in interrupt mode. But currently, 636 * when interrupt ability of the spdk_thread is not enabled, 637 * spdk_thread can't get executed on reactor which runs in interrupt. 638 * Exclude the situation that reactors specified by the cpumask are 639 * all in interrupt mode. 640 */ 641 if (!spdk_interrupt_mode_is_enabled()) { 642 struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core()); 643 struct spdk_cpuset tmp_cpuset; 644 645 /* Masking off reactors which are in interrupt mode */ 646 spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset); 647 spdk_cpuset_negate(&tmp_cpuset); 648 spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask); 649 if (spdk_cpuset_count(&tmp_cpuset) == 0) { 650 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 651 "cpumask %s are all in interrupt mode, and can't be scheduled yet\n", 652 req.cpumask); 653 goto err; 654 } 655 } 656 657 ctx->request = request; 658 ctx->orig_thread = spdk_get_thread(); 659 660 spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx); 661 662 free(req.cpumask); 663 return; 664 665 err: 666 free(req.cpumask); 667 free(ctx); 668 } 669 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME) 670 SPDK_LOG_REGISTER_COMPONENT(app_rpc) 671