1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2016 Intel Corporation. All rights reserved. 3 * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "spdk/event.h" 9 #include "spdk/rpc.h" 10 #include "spdk/string.h" 11 #include "spdk/util.h" 12 #include "spdk/env.h" 13 #include "spdk/scheduler.h" 14 #include "spdk/thread.h" 15 #include "spdk/json.h" 16 17 #include "spdk/log.h" 18 #include "spdk_internal/event.h" 19 #include "spdk_internal/thread.h" 20 21 struct rpc_spdk_kill_instance { 22 char *sig_name; 23 }; 24 25 static void 26 free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req) 27 { 28 free(req->sig_name); 29 } 30 31 static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = { 32 {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string}, 33 }; 34 35 static void 36 rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request, 37 const struct spdk_json_val *params) 38 { 39 static const struct { 40 const char *signal_string; 41 int32_t signal; 42 } signals[] = { 43 {"SIGINT", SIGINT}, 44 {"SIGTERM", SIGTERM}, 45 {"SIGQUIT", SIGQUIT}, 46 {"SIGHUP", SIGHUP}, 47 {"SIGKILL", SIGKILL}, 48 {"SIGUSR1", SIGUSR1}, 49 }; 50 size_t i, sig_count; 51 int signal; 52 struct rpc_spdk_kill_instance req = {}; 53 54 if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders, 55 SPDK_COUNTOF(rpc_spdk_kill_instance_decoders), 56 &req)) { 57 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 58 goto invalid; 59 } 60 61 sig_count = SPDK_COUNTOF(signals); 62 signal = spdk_strtol(req.sig_name, 10); 63 for (i = 0 ; i < sig_count; i++) { 64 if (strcmp(req.sig_name, signals[i].signal_string) == 0 || 65 signal == signals[i].signal) { 66 break; 67 } 68 } 69 70 if (i == sig_count) { 71 goto invalid; 72 } 73 74 SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal); 75 free_rpc_spdk_kill_instance(&req); 76 kill(getpid(), signals[i].signal); 77 78 spdk_jsonrpc_send_bool_response(request, true); 79 return; 80 81 invalid: 82 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 83 free_rpc_spdk_kill_instance(&req); 84 } 85 SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME) 86 87 88 struct rpc_framework_monitor_context_switch { 89 bool enabled; 90 }; 91 92 static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = { 93 {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool}, 94 }; 95 96 static void 97 rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request, 98 const struct spdk_json_val *params) 99 { 100 struct rpc_framework_monitor_context_switch req = {}; 101 struct spdk_json_write_ctx *w; 102 103 if (params != NULL) { 104 if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders, 105 SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders), 106 &req)) { 107 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 108 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 109 return; 110 } 111 112 spdk_framework_enable_context_switch_monitor(req.enabled); 113 } 114 115 w = spdk_jsonrpc_begin_result(request); 116 spdk_json_write_object_begin(w); 117 118 spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled()); 119 120 spdk_json_write_object_end(w); 121 spdk_jsonrpc_end_result(request, w); 122 } 123 124 SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch, 125 SPDK_RPC_RUNTIME) 126 127 struct rpc_get_stats_ctx { 128 struct spdk_jsonrpc_request *request; 129 struct spdk_json_write_ctx *w; 130 uint64_t now; 131 }; 132 133 static void 134 rpc_thread_get_stats_done(void *arg) 135 { 136 struct rpc_get_stats_ctx *ctx = arg; 137 138 spdk_json_write_array_end(ctx->w); 139 spdk_json_write_object_end(ctx->w); 140 spdk_jsonrpc_end_result(ctx->request, ctx->w); 141 142 free(ctx); 143 } 144 145 static void 146 rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn) 147 { 148 struct rpc_get_stats_ctx *ctx; 149 150 ctx = calloc(1, sizeof(*ctx)); 151 if (!ctx) { 152 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 153 "Memory allocation error"); 154 return; 155 } 156 ctx->request = request; 157 158 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 159 spdk_json_write_object_begin(ctx->w); 160 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 161 spdk_json_write_named_array_begin(ctx->w, "threads"); 162 163 spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done); 164 } 165 166 static void 167 _rpc_thread_get_stats(void *arg) 168 { 169 struct rpc_get_stats_ctx *ctx = arg; 170 struct spdk_thread *thread = spdk_get_thread(); 171 struct spdk_cpuset tmp_mask = {}; 172 struct spdk_poller *poller; 173 struct spdk_thread_stats stats; 174 uint64_t active_pollers_count = 0; 175 uint64_t timed_pollers_count = 0; 176 uint64_t paused_pollers_count = 0; 177 178 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 179 poller = spdk_thread_get_next_active_poller(poller)) { 180 active_pollers_count++; 181 } 182 183 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 184 poller = spdk_thread_get_next_timed_poller(poller)) { 185 timed_pollers_count++; 186 } 187 188 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 189 poller = spdk_thread_get_next_paused_poller(poller)) { 190 paused_pollers_count++; 191 } 192 193 if (0 == spdk_thread_get_stats(&stats)) { 194 spdk_json_write_object_begin(ctx->w); 195 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 196 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 197 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 198 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 199 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 200 spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc); 201 spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc); 202 spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count); 203 spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count); 204 spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count); 205 spdk_json_write_object_end(ctx->w); 206 } 207 } 208 209 static void 210 rpc_thread_get_stats(struct spdk_jsonrpc_request *request, 211 const struct spdk_json_val *params) 212 { 213 if (params) { 214 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 215 "'thread_get_stats' requires no arguments"); 216 return; 217 } 218 219 rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats); 220 } 221 222 SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME) 223 224 static void 225 rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w) 226 { 227 struct spdk_poller_stats stats; 228 uint64_t period_ticks; 229 230 period_ticks = spdk_poller_get_period_ticks(poller); 231 spdk_poller_get_stats(poller, &stats); 232 233 spdk_json_write_object_begin(w); 234 spdk_json_write_named_string(w, "name", spdk_poller_get_name(poller)); 235 spdk_json_write_named_uint64(w, "id", spdk_poller_get_id(poller)); 236 spdk_json_write_named_string(w, "state", spdk_poller_get_state_str(poller)); 237 spdk_json_write_named_uint64(w, "run_count", stats.run_count); 238 spdk_json_write_named_uint64(w, "busy_count", stats.busy_count); 239 if (period_ticks) { 240 spdk_json_write_named_uint64(w, "period_ticks", period_ticks); 241 } 242 spdk_json_write_object_end(w); 243 } 244 245 static void 246 _rpc_thread_get_pollers(void *arg) 247 { 248 struct rpc_get_stats_ctx *ctx = arg; 249 struct spdk_thread *thread = spdk_get_thread(); 250 struct spdk_poller *poller; 251 252 spdk_json_write_object_begin(ctx->w); 253 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 254 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 255 256 spdk_json_write_named_array_begin(ctx->w, "active_pollers"); 257 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 258 poller = spdk_thread_get_next_active_poller(poller)) { 259 rpc_get_poller(poller, ctx->w); 260 } 261 spdk_json_write_array_end(ctx->w); 262 263 spdk_json_write_named_array_begin(ctx->w, "timed_pollers"); 264 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 265 poller = spdk_thread_get_next_timed_poller(poller)) { 266 rpc_get_poller(poller, ctx->w); 267 } 268 spdk_json_write_array_end(ctx->w); 269 270 spdk_json_write_named_array_begin(ctx->w, "paused_pollers"); 271 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 272 poller = spdk_thread_get_next_paused_poller(poller)) { 273 rpc_get_poller(poller, ctx->w); 274 } 275 spdk_json_write_array_end(ctx->w); 276 277 spdk_json_write_object_end(ctx->w); 278 } 279 280 static void 281 rpc_thread_get_pollers(struct spdk_jsonrpc_request *request, 282 const struct spdk_json_val *params) 283 { 284 if (params) { 285 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 286 "'thread_get_pollers' requires no arguments"); 287 return; 288 } 289 290 rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers); 291 } 292 293 SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME) 294 295 static void 296 rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w) 297 { 298 spdk_json_write_object_begin(w); 299 spdk_json_write_named_string(w, "name", spdk_io_channel_get_io_device_name(ch)); 300 spdk_json_write_named_uint32(w, "ref", spdk_io_channel_get_ref_count(ch)); 301 spdk_json_write_object_end(w); 302 } 303 304 static void 305 _rpc_thread_get_io_channels(void *arg) 306 { 307 struct rpc_get_stats_ctx *ctx = arg; 308 struct spdk_thread *thread = spdk_get_thread(); 309 struct spdk_io_channel *ch; 310 311 spdk_json_write_object_begin(ctx->w); 312 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 313 314 spdk_json_write_named_array_begin(ctx->w, "io_channels"); 315 for (ch = spdk_thread_get_first_io_channel(thread); ch != NULL; 316 ch = spdk_thread_get_next_io_channel(ch)) { 317 rpc_get_io_channel(ch, ctx->w); 318 } 319 spdk_json_write_array_end(ctx->w); 320 321 spdk_json_write_object_end(ctx->w); 322 } 323 324 static void 325 rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request, 326 const struct spdk_json_val *params) 327 { 328 if (params) { 329 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 330 "'thread_get_io_channels' requires no arguments"); 331 return; 332 } 333 334 rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels); 335 } 336 337 SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME); 338 339 static void 340 rpc_framework_get_reactors_done(void *arg1, void *arg2) 341 { 342 struct rpc_get_stats_ctx *ctx = arg1; 343 344 spdk_json_write_array_end(ctx->w); 345 spdk_json_write_object_end(ctx->w); 346 spdk_jsonrpc_end_result(ctx->request, ctx->w); 347 348 free(ctx); 349 } 350 351 #define GET_DELTA(end, start) (end >= start ? end - start : 0) 352 353 static void 354 _rpc_framework_get_reactors(void *arg1, void *arg2) 355 { 356 struct rpc_get_stats_ctx *ctx = arg1; 357 uint32_t current_core; 358 uint32_t curr_core_freq; 359 struct spdk_reactor *reactor; 360 struct spdk_lw_thread *lw_thread; 361 struct spdk_thread *thread; 362 struct spdk_cpuset tmp_mask = {}; 363 struct spdk_governor *governor; 364 365 current_core = spdk_env_get_current_core(); 366 reactor = spdk_reactor_get(current_core); 367 368 assert(reactor != NULL); 369 370 spdk_json_write_object_begin(ctx->w); 371 spdk_json_write_named_uint32(ctx->w, "lcore", current_core); 372 spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc); 373 spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc); 374 spdk_json_write_named_bool(ctx->w, "in_interrupt", reactor->in_interrupt); 375 376 governor = spdk_governor_get(); 377 if (governor != NULL) { 378 /* Governor returns core freqs in kHz, we want MHz. */ 379 curr_core_freq = governor->get_core_curr_freq(current_core) / 1000; 380 spdk_json_write_named_uint32(ctx->w, "core_freq", curr_core_freq); 381 } 382 383 spdk_json_write_named_array_begin(ctx->w, "lw_threads"); 384 TAILQ_FOREACH(lw_thread, &reactor->threads, link) { 385 thread = spdk_thread_get_from_ctx(lw_thread); 386 387 spdk_json_write_object_begin(ctx->w); 388 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 389 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 390 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 391 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 392 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 393 spdk_json_write_named_uint64(ctx->w, "elapsed", 394 GET_DELTA(ctx->now, lw_thread->tsc_start)); 395 spdk_json_write_object_end(ctx->w); 396 } 397 spdk_json_write_array_end(ctx->w); 398 399 spdk_json_write_object_end(ctx->w); 400 } 401 402 static void 403 rpc_framework_get_reactors(struct spdk_jsonrpc_request *request, 404 const struct spdk_json_val *params) 405 { 406 struct rpc_get_stats_ctx *ctx; 407 408 if (params) { 409 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 410 "`framework_get_reactors` requires no arguments"); 411 return; 412 } 413 414 ctx = calloc(1, sizeof(*ctx)); 415 if (!ctx) { 416 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 417 "Memory allocation error"); 418 return; 419 } 420 421 ctx->now = spdk_get_ticks(); 422 ctx->request = request; 423 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 424 425 spdk_json_write_object_begin(ctx->w); 426 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 427 spdk_json_write_named_array_begin(ctx->w, "reactors"); 428 429 spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL, 430 rpc_framework_get_reactors_done); 431 } 432 433 SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME) 434 435 struct rpc_set_scheduler_ctx { 436 char *name; 437 uint64_t period; 438 }; 439 440 static void 441 free_rpc_framework_set_scheduler(struct rpc_set_scheduler_ctx *r) 442 { 443 free(r->name); 444 } 445 446 static const struct spdk_json_object_decoder rpc_set_scheduler_decoders[] = { 447 {"name", offsetof(struct rpc_set_scheduler_ctx, name), spdk_json_decode_string}, 448 {"period", offsetof(struct rpc_set_scheduler_ctx, period), spdk_json_decode_uint64, true}, 449 }; 450 451 static void 452 rpc_framework_set_scheduler(struct spdk_jsonrpc_request *request, 453 const struct spdk_json_val *params) 454 { 455 struct rpc_set_scheduler_ctx req = {NULL}; 456 struct spdk_scheduler *scheduler = NULL; 457 int ret; 458 459 ret = spdk_json_decode_object_relaxed(params, rpc_set_scheduler_decoders, 460 SPDK_COUNTOF(rpc_set_scheduler_decoders), 461 &req); 462 if (ret) { 463 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 464 "Invalid parameters"); 465 goto end; 466 } 467 468 scheduler = spdk_scheduler_get(); 469 /* SPDK does not support changing scheduler back to static. */ 470 if (scheduler != NULL && (strcmp(req.name, "static") == 0) && 471 strcmp(scheduler->name, "static") != 0) { 472 spdk_jsonrpc_send_error_response(request, 473 SPDK_JSONRPC_ERROR_INVALID_PARAMS, 474 "Static scheduler cannot be re-enabled " 475 "after a different scheduler was selected"); 476 goto end; 477 } 478 479 if (req.period != 0) { 480 spdk_scheduler_set_period(req.period); 481 } 482 483 ret = spdk_scheduler_set(req.name); 484 if (ret) { 485 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 486 spdk_strerror(ret)); 487 goto end; 488 } 489 490 if (scheduler != NULL && scheduler->set_opts != NULL) { 491 ret = scheduler->set_opts(params); 492 } 493 if (ret) { 494 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(ret)); 495 goto end; 496 } 497 498 spdk_jsonrpc_send_bool_response(request, true); 499 500 end: 501 free_rpc_framework_set_scheduler(&req); 502 } 503 SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler, 504 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 505 506 static void 507 rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request, 508 const struct spdk_json_val *params) 509 { 510 struct spdk_json_write_ctx *w; 511 struct spdk_scheduler *scheduler = spdk_scheduler_get(); 512 uint64_t scheduler_period = spdk_scheduler_get_period(); 513 struct spdk_governor *governor = spdk_governor_get(); 514 515 if (params) { 516 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 517 "'rpc_get_scheduler' requires no arguments"); 518 return; 519 } 520 521 w = spdk_jsonrpc_begin_result(request); 522 spdk_json_write_object_begin(w); 523 if (scheduler) { 524 spdk_json_write_named_string(w, "scheduler_name", scheduler->name); 525 } 526 spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period); 527 if (governor != NULL) { 528 spdk_json_write_named_string(w, "governor_name", governor->name); 529 } 530 531 if (scheduler != NULL && scheduler->get_opts != NULL) { 532 scheduler->get_opts(w); 533 } 534 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