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 #include "event_internal.h" 21 22 struct rpc_spdk_kill_instance { 23 char *sig_name; 24 }; 25 26 static void 27 free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req) 28 { 29 free(req->sig_name); 30 } 31 32 static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = { 33 {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string}, 34 }; 35 36 static void 37 rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request, 38 const struct spdk_json_val *params) 39 { 40 static const struct { 41 const char *signal_string; 42 int32_t signal; 43 } signals[] = { 44 {"SIGINT", SIGINT}, 45 {"SIGTERM", SIGTERM}, 46 {"SIGQUIT", SIGQUIT}, 47 {"SIGHUP", SIGHUP}, 48 {"SIGKILL", SIGKILL}, 49 {"SIGUSR1", SIGUSR1}, 50 }; 51 size_t i, sig_count; 52 int signal; 53 struct rpc_spdk_kill_instance req = {}; 54 55 if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders, 56 SPDK_COUNTOF(rpc_spdk_kill_instance_decoders), 57 &req)) { 58 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 59 goto invalid; 60 } 61 62 sig_count = SPDK_COUNTOF(signals); 63 signal = spdk_strtol(req.sig_name, 10); 64 for (i = 0 ; i < sig_count; i++) { 65 if (strcmp(req.sig_name, signals[i].signal_string) == 0 || 66 signal == signals[i].signal) { 67 break; 68 } 69 } 70 71 if (i == sig_count) { 72 goto invalid; 73 } 74 75 SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal); 76 free_rpc_spdk_kill_instance(&req); 77 kill(getpid(), signals[i].signal); 78 79 spdk_jsonrpc_send_bool_response(request, true); 80 return; 81 82 invalid: 83 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 84 free_rpc_spdk_kill_instance(&req); 85 } 86 SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME) 87 88 89 struct rpc_framework_monitor_context_switch { 90 bool enabled; 91 }; 92 93 static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = { 94 {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool}, 95 }; 96 97 static void 98 rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request, 99 const struct spdk_json_val *params) 100 { 101 struct rpc_framework_monitor_context_switch req = {}; 102 struct spdk_json_write_ctx *w; 103 104 if (params != NULL) { 105 if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders, 106 SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders), 107 &req)) { 108 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 109 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 110 return; 111 } 112 113 spdk_framework_enable_context_switch_monitor(req.enabled); 114 } 115 116 w = spdk_jsonrpc_begin_result(request); 117 spdk_json_write_object_begin(w); 118 119 spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled()); 120 121 spdk_json_write_object_end(w); 122 spdk_jsonrpc_end_result(request, w); 123 } 124 125 SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch, 126 SPDK_RPC_RUNTIME) 127 128 struct rpc_get_stats_ctx { 129 struct spdk_jsonrpc_request *request; 130 struct spdk_json_write_ctx *w; 131 uint64_t now; 132 }; 133 134 static void 135 rpc_thread_get_stats_done(void *arg) 136 { 137 struct rpc_get_stats_ctx *ctx = arg; 138 139 spdk_json_write_array_end(ctx->w); 140 spdk_json_write_object_end(ctx->w); 141 spdk_jsonrpc_end_result(ctx->request, ctx->w); 142 143 free(ctx); 144 } 145 146 static void 147 rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn) 148 { 149 struct rpc_get_stats_ctx *ctx; 150 151 ctx = calloc(1, sizeof(*ctx)); 152 if (!ctx) { 153 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 154 "Memory allocation error"); 155 return; 156 } 157 ctx->request = request; 158 159 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 160 spdk_json_write_object_begin(ctx->w); 161 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 162 spdk_json_write_named_array_begin(ctx->w, "threads"); 163 164 spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done); 165 } 166 167 static void 168 _rpc_thread_get_stats(void *arg) 169 { 170 struct rpc_get_stats_ctx *ctx = arg; 171 struct spdk_thread *thread = spdk_get_thread(); 172 struct spdk_cpuset tmp_mask = {}; 173 struct spdk_poller *poller; 174 struct spdk_thread_stats stats; 175 uint64_t active_pollers_count = 0; 176 uint64_t timed_pollers_count = 0; 177 uint64_t paused_pollers_count = 0; 178 179 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 180 poller = spdk_thread_get_next_active_poller(poller)) { 181 active_pollers_count++; 182 } 183 184 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 185 poller = spdk_thread_get_next_timed_poller(poller)) { 186 timed_pollers_count++; 187 } 188 189 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 190 poller = spdk_thread_get_next_paused_poller(poller)) { 191 paused_pollers_count++; 192 } 193 194 if (0 == spdk_thread_get_stats(&stats)) { 195 spdk_json_write_object_begin(ctx->w); 196 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 197 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 198 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 199 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 200 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 201 spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc); 202 spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc); 203 spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count); 204 spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count); 205 spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count); 206 spdk_json_write_object_end(ctx->w); 207 } 208 } 209 210 static void 211 rpc_thread_get_stats(struct spdk_jsonrpc_request *request, 212 const struct spdk_json_val *params) 213 { 214 if (params) { 215 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 216 "'thread_get_stats' requires no arguments"); 217 return; 218 } 219 220 rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats); 221 } 222 223 SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME) 224 225 static void 226 rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w) 227 { 228 struct spdk_poller_stats stats; 229 uint64_t period_ticks; 230 231 period_ticks = spdk_poller_get_period_ticks(poller); 232 spdk_poller_get_stats(poller, &stats); 233 234 spdk_json_write_object_begin(w); 235 spdk_json_write_named_string(w, "name", spdk_poller_get_name(poller)); 236 spdk_json_write_named_uint64(w, "id", spdk_poller_get_id(poller)); 237 spdk_json_write_named_string(w, "state", spdk_poller_get_state_str(poller)); 238 spdk_json_write_named_uint64(w, "run_count", stats.run_count); 239 spdk_json_write_named_uint64(w, "busy_count", stats.busy_count); 240 if (period_ticks) { 241 spdk_json_write_named_uint64(w, "period_ticks", period_ticks); 242 } 243 spdk_json_write_object_end(w); 244 } 245 246 static void 247 _rpc_thread_get_pollers(void *arg) 248 { 249 struct rpc_get_stats_ctx *ctx = arg; 250 struct spdk_thread *thread = spdk_get_thread(); 251 struct spdk_poller *poller; 252 253 spdk_json_write_object_begin(ctx->w); 254 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 255 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 256 257 spdk_json_write_named_array_begin(ctx->w, "active_pollers"); 258 for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL; 259 poller = spdk_thread_get_next_active_poller(poller)) { 260 rpc_get_poller(poller, ctx->w); 261 } 262 spdk_json_write_array_end(ctx->w); 263 264 spdk_json_write_named_array_begin(ctx->w, "timed_pollers"); 265 for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL; 266 poller = spdk_thread_get_next_timed_poller(poller)) { 267 rpc_get_poller(poller, ctx->w); 268 } 269 spdk_json_write_array_end(ctx->w); 270 271 spdk_json_write_named_array_begin(ctx->w, "paused_pollers"); 272 for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL; 273 poller = spdk_thread_get_next_paused_poller(poller)) { 274 rpc_get_poller(poller, ctx->w); 275 } 276 spdk_json_write_array_end(ctx->w); 277 278 spdk_json_write_object_end(ctx->w); 279 } 280 281 static void 282 rpc_thread_get_pollers(struct spdk_jsonrpc_request *request, 283 const struct spdk_json_val *params) 284 { 285 if (params) { 286 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 287 "'thread_get_pollers' requires no arguments"); 288 return; 289 } 290 291 rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers); 292 } 293 294 SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME) 295 296 static void 297 rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w) 298 { 299 spdk_json_write_object_begin(w); 300 spdk_json_write_named_string(w, "name", spdk_io_channel_get_io_device_name(ch)); 301 spdk_json_write_named_uint32(w, "ref", spdk_io_channel_get_ref_count(ch)); 302 spdk_json_write_object_end(w); 303 } 304 305 static void 306 _rpc_thread_get_io_channels(void *arg) 307 { 308 struct rpc_get_stats_ctx *ctx = arg; 309 struct spdk_thread *thread = spdk_get_thread(); 310 struct spdk_io_channel *ch; 311 312 spdk_json_write_object_begin(ctx->w); 313 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 314 315 spdk_json_write_named_array_begin(ctx->w, "io_channels"); 316 for (ch = spdk_thread_get_first_io_channel(thread); ch != NULL; 317 ch = spdk_thread_get_next_io_channel(ch)) { 318 rpc_get_io_channel(ch, ctx->w); 319 } 320 spdk_json_write_array_end(ctx->w); 321 322 spdk_json_write_object_end(ctx->w); 323 } 324 325 static void 326 rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request, 327 const struct spdk_json_val *params) 328 { 329 if (params) { 330 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 331 "'thread_get_io_channels' requires no arguments"); 332 return; 333 } 334 335 rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels); 336 } 337 338 SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME); 339 340 static void 341 rpc_framework_get_reactors_done(void *arg1, void *arg2) 342 { 343 struct rpc_get_stats_ctx *ctx = arg1; 344 345 spdk_json_write_array_end(ctx->w); 346 spdk_json_write_object_end(ctx->w); 347 spdk_jsonrpc_end_result(ctx->request, ctx->w); 348 349 free(ctx); 350 } 351 352 #define GET_DELTA(end, start) (end >= start ? end - start : 0) 353 354 static void 355 _rpc_framework_get_reactors(void *arg1, void *arg2) 356 { 357 struct rpc_get_stats_ctx *ctx = arg1; 358 uint32_t current_core; 359 uint32_t curr_core_freq; 360 uint64_t sys, usr, irq; 361 struct spdk_reactor *reactor; 362 struct spdk_lw_thread *lw_thread; 363 struct spdk_thread *thread; 364 struct spdk_cpuset tmp_mask = {}; 365 struct spdk_governor *governor; 366 367 current_core = spdk_env_get_current_core(); 368 reactor = spdk_reactor_get(current_core); 369 370 assert(reactor != NULL); 371 372 spdk_json_write_object_begin(ctx->w); 373 spdk_json_write_named_uint32(ctx->w, "lcore", current_core); 374 spdk_json_write_named_uint64(ctx->w, "tid", spdk_get_tid()); 375 spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc); 376 spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc); 377 spdk_json_write_named_bool(ctx->w, "in_interrupt", reactor->in_interrupt); 378 379 if (app_get_proc_stat(current_core, &usr, &sys, &irq) != 0) { 380 irq = sys = usr = 0; 381 } 382 spdk_json_write_named_uint64(ctx->w, "irq", irq); 383 spdk_json_write_named_uint64(ctx->w, "sys", sys); 384 spdk_json_write_named_uint64(ctx->w, "usr", usr); 385 386 governor = spdk_governor_get(); 387 if (governor != NULL) { 388 /* Governor returns core freqs in kHz, we want MHz. */ 389 curr_core_freq = governor->get_core_curr_freq(current_core) / 1000; 390 spdk_json_write_named_uint32(ctx->w, "core_freq", curr_core_freq); 391 } 392 393 spdk_json_write_named_array_begin(ctx->w, "lw_threads"); 394 TAILQ_FOREACH(lw_thread, &reactor->threads, link) { 395 thread = spdk_thread_get_from_ctx(lw_thread); 396 397 spdk_json_write_object_begin(ctx->w); 398 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 399 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 400 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask()); 401 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread)); 402 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask)); 403 spdk_json_write_named_uint64(ctx->w, "elapsed", 404 GET_DELTA(ctx->now, lw_thread->tsc_start)); 405 spdk_json_write_object_end(ctx->w); 406 } 407 spdk_json_write_array_end(ctx->w); 408 409 spdk_json_write_object_end(ctx->w); 410 } 411 412 static void 413 rpc_framework_get_reactors(struct spdk_jsonrpc_request *request, 414 const struct spdk_json_val *params) 415 { 416 struct rpc_get_stats_ctx *ctx; 417 418 if (params) { 419 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 420 "`framework_get_reactors` requires no arguments"); 421 return; 422 } 423 424 ctx = calloc(1, sizeof(*ctx)); 425 if (!ctx) { 426 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 427 "Memory allocation error"); 428 return; 429 } 430 431 ctx->now = spdk_get_ticks(); 432 ctx->request = request; 433 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 434 435 spdk_json_write_object_begin(ctx->w); 436 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 437 spdk_json_write_named_uint64(ctx->w, "pid", getpid()); 438 spdk_json_write_named_array_begin(ctx->w, "reactors"); 439 440 spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL, 441 rpc_framework_get_reactors_done); 442 } 443 444 SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME) 445 446 struct rpc_set_scheduler_ctx { 447 char *name; 448 uint64_t period; 449 }; 450 451 static void 452 free_rpc_framework_set_scheduler(struct rpc_set_scheduler_ctx *r) 453 { 454 free(r->name); 455 } 456 457 static const struct spdk_json_object_decoder rpc_set_scheduler_decoders[] = { 458 {"name", offsetof(struct rpc_set_scheduler_ctx, name), spdk_json_decode_string}, 459 {"period", offsetof(struct rpc_set_scheduler_ctx, period), spdk_json_decode_uint64, true}, 460 }; 461 462 static void 463 rpc_framework_set_scheduler(struct spdk_jsonrpc_request *request, 464 const struct spdk_json_val *params) 465 { 466 struct rpc_set_scheduler_ctx req = {NULL}; 467 struct spdk_scheduler *scheduler = NULL; 468 bool has_custom_opts = false; 469 int ret; 470 471 ret = spdk_json_decode_object(params, rpc_set_scheduler_decoders, 472 SPDK_COUNTOF(rpc_set_scheduler_decoders), 473 &req); 474 if (ret) { 475 has_custom_opts = true; 476 ret = spdk_json_decode_object_relaxed(params, rpc_set_scheduler_decoders, 477 SPDK_COUNTOF(rpc_set_scheduler_decoders), 478 &req); 479 } 480 if (ret) { 481 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 482 "Invalid parameters"); 483 goto end; 484 } 485 486 scheduler = spdk_scheduler_get(); 487 /* SPDK does not support changing scheduler back to static. */ 488 if (scheduler != NULL && (strcmp(req.name, "static") == 0) && 489 strcmp(scheduler->name, "static") != 0) { 490 spdk_jsonrpc_send_error_response(request, 491 SPDK_JSONRPC_ERROR_INVALID_PARAMS, 492 "Static scheduler cannot be re-enabled " 493 "after a different scheduler was selected"); 494 goto end; 495 } 496 497 if (req.period != 0) { 498 spdk_scheduler_set_period(req.period); 499 } else if (spdk_scheduler_get_period() == 0) { 500 /* User didn't specify a period, and no period has been set 501 * previously, so set it now to 1 second. 502 */ 503 spdk_scheduler_set_period(SPDK_SEC_TO_USEC); 504 } 505 506 ret = spdk_scheduler_set(req.name); 507 if (ret) { 508 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 509 spdk_strerror(ret)); 510 goto end; 511 } 512 513 scheduler = spdk_scheduler_get(); 514 if (scheduler != NULL && scheduler->set_opts != NULL) { 515 ret = scheduler->set_opts(params); 516 } else if (has_custom_opts) { 517 /* No custom options are allowed if set_opts are not implemented. */ 518 ret = -EINVAL; 519 } 520 if (ret) { 521 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(ret)); 522 goto end; 523 } 524 525 spdk_jsonrpc_send_bool_response(request, true); 526 527 end: 528 free_rpc_framework_set_scheduler(&req); 529 } 530 SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler, 531 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 532 533 static void 534 rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request, 535 const struct spdk_json_val *params) 536 { 537 struct spdk_json_write_ctx *w; 538 struct spdk_scheduler *scheduler = spdk_scheduler_get(); 539 uint64_t scheduler_period = spdk_scheduler_get_period(); 540 struct spdk_governor *governor = spdk_governor_get(); 541 uint32_t scheduling_core = spdk_scheduler_get_scheduling_lcore(); 542 543 if (params) { 544 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 545 "'rpc_get_scheduler' requires no arguments"); 546 return; 547 } 548 549 w = spdk_jsonrpc_begin_result(request); 550 spdk_json_write_object_begin(w); 551 if (scheduler) { 552 spdk_json_write_named_string(w, "scheduler_name", scheduler->name); 553 } 554 spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period); 555 spdk_json_write_named_string(w, "isolated_core_mask", scheduler_get_isolated_core_mask()); 556 spdk_json_write_named_uint32(w, "scheduling_core", scheduling_core); 557 if (governor != NULL) { 558 spdk_json_write_named_string(w, "governor_name", governor->name); 559 } 560 561 if (scheduler != NULL && scheduler->get_opts != NULL) { 562 scheduler->get_opts(w); 563 } 564 565 spdk_json_write_object_end(w); 566 spdk_jsonrpc_end_result(request, w); 567 } 568 SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler, 569 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 570 571 static void 572 rpc_framework_get_governor(struct spdk_jsonrpc_request *request, 573 const struct spdk_json_val *params) 574 { 575 struct spdk_json_write_ctx *w; 576 struct spdk_governor *governor = spdk_governor_get(); 577 578 if (params) { 579 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 580 "'rpc_get_governor' requires no arguments"); 581 return; 582 } 583 584 w = spdk_jsonrpc_begin_result(request); 585 spdk_json_write_object_begin(w); 586 587 if (governor != NULL) { 588 uint32_t core, index, num; 589 uint32_t freqs[SPDK_MAX_LCORE_FREQS]; 590 591 spdk_json_write_named_string(w, "governor_name", governor->name); 592 593 spdk_json_write_named_object_begin(w, "module_specific"); 594 595 governor->dump_info_json(w); 596 597 spdk_json_write_object_end(w); 598 599 spdk_json_write_named_array_begin(w, "cores"); 600 601 SPDK_ENV_FOREACH_CORE(core) { 602 spdk_json_write_object_begin(w); 603 spdk_json_write_named_uint32(w, "lcore_id", core); 604 605 memset(freqs, 0, SPDK_MAX_LCORE_FREQS * sizeof(uint32_t)); 606 607 num = governor->get_core_avail_freqs(core, freqs, SPDK_MAX_LCORE_FREQS); 608 609 spdk_json_write_named_array_begin(w, "available_frequencies"); 610 for (index = 0; index < num; index++) { 611 spdk_json_write_uint32(w, freqs[index]); 612 } 613 spdk_json_write_array_end(w); 614 615 spdk_json_write_named_uint32(w, "current_frequency", governor->get_core_curr_freq(core)); 616 spdk_json_write_object_end(w); 617 } 618 619 spdk_json_write_array_end(w); 620 } 621 622 spdk_json_write_object_end(w); 623 spdk_jsonrpc_end_result(request, w); 624 } 625 SPDK_RPC_REGISTER("framework_get_governor", rpc_framework_get_governor, SPDK_RPC_RUNTIME) 626 627 struct rpc_set_scheduler_opts_ctx { 628 char *isolated_core_mask; 629 uint32_t scheduling_core; 630 }; 631 632 static const struct spdk_json_object_decoder rpc_set_scheduler_opts_decoders[] = { 633 {"isolated_core_mask", offsetof(struct rpc_set_scheduler_opts_ctx, isolated_core_mask), spdk_json_decode_string, true}, 634 {"scheduling_core", offsetof(struct rpc_set_scheduler_opts_ctx, scheduling_core), spdk_json_decode_uint32, true}, 635 }; 636 637 static void 638 free_rpc_scheduler_set_options(struct rpc_set_scheduler_opts_ctx *r) 639 { 640 free(r->isolated_core_mask); 641 } 642 643 static void 644 rpc_scheduler_set_options(struct spdk_jsonrpc_request *request, 645 const struct spdk_json_val *params) 646 { 647 struct rpc_set_scheduler_opts_ctx req = {NULL}; 648 struct spdk_cpuset core_mask; 649 650 req.scheduling_core = spdk_scheduler_get_scheduling_lcore(); 651 652 if (spdk_json_decode_object(params, rpc_set_scheduler_opts_decoders, 653 SPDK_COUNTOF(rpc_set_scheduler_opts_decoders), &req)) { 654 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 655 "Invalid parameters"); 656 goto end; 657 } 658 659 if (req.isolated_core_mask != NULL) { 660 spdk_cpuset_parse(&core_mask, req.isolated_core_mask); 661 if (spdk_cpuset_get_cpu(&core_mask, req.scheduling_core)) { 662 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 663 "Scheduling core cannot be included in isolated core mask.\n"); 664 goto end; 665 } 666 if (scheduler_set_isolated_core_mask(core_mask) == false) { 667 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 668 "Invalid isolated core mask\n"); 669 goto end; 670 } 671 } 672 673 if (spdk_scheduler_set_scheduling_lcore(req.scheduling_core) == false) { 674 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 675 "Invalid scheduling core.\n"); 676 goto end; 677 } 678 679 spdk_jsonrpc_send_bool_response(request, true); 680 end: 681 free_rpc_scheduler_set_options(&req); 682 } 683 SPDK_RPC_REGISTER("scheduler_set_options", rpc_scheduler_set_options, SPDK_RPC_STARTUP) 684 685 struct rpc_thread_set_cpumask_ctx { 686 struct spdk_jsonrpc_request *request; 687 struct spdk_cpuset cpumask; 688 int status; 689 struct spdk_thread *orig_thread; 690 }; 691 692 static void 693 rpc_thread_set_cpumask_done(void *_ctx) 694 { 695 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 696 697 if (ctx->status == 0) { 698 spdk_jsonrpc_send_bool_response(ctx->request, true); 699 } else { 700 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 701 spdk_strerror(-ctx->status)); 702 } 703 704 free(ctx); 705 } 706 707 static void 708 _rpc_thread_set_cpumask(void *_ctx) 709 { 710 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 711 712 ctx->status = spdk_thread_set_cpumask(&ctx->cpumask); 713 714 spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx); 715 } 716 717 struct rpc_thread_set_cpumask { 718 uint64_t id; 719 char *cpumask; 720 }; 721 722 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = { 723 {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64}, 724 {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string}, 725 }; 726 727 static void 728 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request, 729 const struct spdk_json_val *params) 730 { 731 struct rpc_thread_set_cpumask req = {}; 732 struct rpc_thread_set_cpumask_ctx *ctx; 733 const struct spdk_cpuset *coremask; 734 struct spdk_cpuset tmp_mask; 735 struct spdk_thread *thread; 736 int rc; 737 738 ctx = calloc(1, sizeof(*ctx)); 739 if (ctx == NULL) { 740 SPDK_ERRLOG("Memory allocation failed\n"); 741 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 742 "Memory allocation failed"); 743 return; 744 } 745 746 if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders, 747 SPDK_COUNTOF(rpc_thread_set_cpumask_decoders), 748 &req)) { 749 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 750 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 751 "spdk_json_decode_object failed"); 752 goto err; 753 } 754 755 thread = spdk_thread_get_by_id(req.id); 756 if (thread == NULL) { 757 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id); 758 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 759 "Thread %" PRIu64 " does not exist", req.id); 760 goto err; 761 } 762 763 rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask); 764 if (rc != 0) { 765 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask); 766 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 767 "Invalid cpumask %s", req.cpumask); 768 goto err; 769 } 770 771 if (spdk_cpuset_count(&ctx->cpumask) == 0) { 772 coremask = spdk_app_get_core_mask(); 773 spdk_cpuset_copy(&tmp_mask, coremask); 774 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 775 "No CPU is selected from reactor mask %s", 776 spdk_cpuset_fmt(&tmp_mask)); 777 goto err; 778 } 779 780 /* There may be any reactors running in interrupt mode. But currently, 781 * when interrupt ability of the spdk_thread is not enabled, 782 * spdk_thread can't get executed on reactor which runs in interrupt. 783 * Exclude the situation that reactors specified by the cpumask are 784 * all in interrupt mode. 785 */ 786 if (!spdk_interrupt_mode_is_enabled()) { 787 struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core()); 788 struct spdk_cpuset tmp_cpuset; 789 790 /* Masking off reactors which are in interrupt mode */ 791 spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset); 792 spdk_cpuset_negate(&tmp_cpuset); 793 spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask); 794 if (spdk_cpuset_count(&tmp_cpuset) == 0) { 795 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 796 "cpumask %s are all in interrupt mode, and can't be scheduled yet", 797 req.cpumask); 798 goto err; 799 } 800 } 801 802 ctx->request = request; 803 ctx->orig_thread = spdk_get_thread(); 804 805 spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx); 806 807 free(req.cpumask); 808 return; 809 810 err: 811 free(req.cpumask); 812 free(ctx); 813 } 814 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME) 815 SPDK_LOG_REGISTER_COMPONENT(app_rpc) 816