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 542 if (params) { 543 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 544 "'rpc_get_scheduler' requires no arguments"); 545 return; 546 } 547 548 w = spdk_jsonrpc_begin_result(request); 549 spdk_json_write_object_begin(w); 550 if (scheduler) { 551 spdk_json_write_named_string(w, "scheduler_name", scheduler->name); 552 } 553 spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period); 554 if (governor != NULL) { 555 spdk_json_write_named_string(w, "governor_name", governor->name); 556 } 557 558 if (scheduler != NULL && scheduler->get_opts != NULL) { 559 scheduler->get_opts(w); 560 } 561 562 spdk_json_write_object_end(w); 563 spdk_jsonrpc_end_result(request, w); 564 } 565 SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler, 566 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 567 568 static void 569 rpc_framework_get_governor(struct spdk_jsonrpc_request *request, 570 const struct spdk_json_val *params) 571 { 572 struct spdk_json_write_ctx *w; 573 struct spdk_governor *governor = spdk_governor_get(); 574 575 if (params) { 576 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 577 "'rpc_get_governor' requires no arguments"); 578 return; 579 } 580 581 w = spdk_jsonrpc_begin_result(request); 582 spdk_json_write_object_begin(w); 583 584 if (governor != NULL) { 585 uint32_t core, index, num; 586 uint32_t freqs[SPDK_MAX_LCORE_FREQS]; 587 588 spdk_json_write_named_string(w, "governor_name", governor->name); 589 590 spdk_json_write_named_object_begin(w, "module_specific"); 591 592 governor->dump_info_json(w); 593 594 spdk_json_write_object_end(w); 595 596 spdk_json_write_named_array_begin(w, "cores"); 597 598 SPDK_ENV_FOREACH_CORE(core) { 599 spdk_json_write_object_begin(w); 600 spdk_json_write_named_uint32(w, "lcore_id", core); 601 602 memset(freqs, 0, SPDK_MAX_LCORE_FREQS * sizeof(uint32_t)); 603 604 num = governor->get_core_avail_freqs(core, freqs, SPDK_MAX_LCORE_FREQS); 605 606 spdk_json_write_named_array_begin(w, "available_frequencies"); 607 for (index = 0; index < num; index++) { 608 spdk_json_write_uint32(w, freqs[index]); 609 } 610 spdk_json_write_array_end(w); 611 612 spdk_json_write_named_uint32(w, "current_frequency", governor->get_core_curr_freq(core)); 613 spdk_json_write_object_end(w); 614 } 615 616 spdk_json_write_array_end(w); 617 } 618 619 spdk_json_write_object_end(w); 620 spdk_jsonrpc_end_result(request, w); 621 } 622 SPDK_RPC_REGISTER("framework_get_governor", rpc_framework_get_governor, SPDK_RPC_RUNTIME) 623 624 struct rpc_thread_set_cpumask_ctx { 625 struct spdk_jsonrpc_request *request; 626 struct spdk_cpuset cpumask; 627 int status; 628 struct spdk_thread *orig_thread; 629 }; 630 631 static void 632 rpc_thread_set_cpumask_done(void *_ctx) 633 { 634 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 635 636 if (ctx->status == 0) { 637 spdk_jsonrpc_send_bool_response(ctx->request, true); 638 } else { 639 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 640 spdk_strerror(-ctx->status)); 641 } 642 643 free(ctx); 644 } 645 646 static void 647 _rpc_thread_set_cpumask(void *_ctx) 648 { 649 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 650 651 ctx->status = spdk_thread_set_cpumask(&ctx->cpumask); 652 653 spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx); 654 } 655 656 struct rpc_thread_set_cpumask { 657 uint64_t id; 658 char *cpumask; 659 }; 660 661 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = { 662 {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64}, 663 {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string}, 664 }; 665 666 static void 667 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request, 668 const struct spdk_json_val *params) 669 { 670 struct rpc_thread_set_cpumask req = {}; 671 struct rpc_thread_set_cpumask_ctx *ctx; 672 const struct spdk_cpuset *coremask; 673 struct spdk_cpuset tmp_mask; 674 struct spdk_thread *thread; 675 int rc; 676 677 ctx = calloc(1, sizeof(*ctx)); 678 if (ctx == NULL) { 679 SPDK_ERRLOG("Memory allocation failed\n"); 680 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 681 "Memory allocation failed"); 682 return; 683 } 684 685 if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders, 686 SPDK_COUNTOF(rpc_thread_set_cpumask_decoders), 687 &req)) { 688 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 689 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 690 "spdk_json_decode_object failed"); 691 goto err; 692 } 693 694 thread = spdk_thread_get_by_id(req.id); 695 if (thread == NULL) { 696 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id); 697 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 698 "Thread %" PRIu64 " does not exist", req.id); 699 goto err; 700 } 701 702 rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask); 703 if (rc != 0) { 704 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask); 705 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 706 "Invalid cpumask %s", req.cpumask); 707 goto err; 708 } 709 710 if (spdk_cpuset_count(&ctx->cpumask) == 0) { 711 coremask = spdk_app_get_core_mask(); 712 spdk_cpuset_copy(&tmp_mask, coremask); 713 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 714 "No CPU is selected from reactor mask %s", 715 spdk_cpuset_fmt(&tmp_mask)); 716 goto err; 717 } 718 719 /* There may be any reactors running in interrupt mode. But currently, 720 * when interrupt ability of the spdk_thread is not enabled, 721 * spdk_thread can't get executed on reactor which runs in interrupt. 722 * Exclude the situation that reactors specified by the cpumask are 723 * all in interrupt mode. 724 */ 725 if (!spdk_interrupt_mode_is_enabled()) { 726 struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core()); 727 struct spdk_cpuset tmp_cpuset; 728 729 /* Masking off reactors which are in interrupt mode */ 730 spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset); 731 spdk_cpuset_negate(&tmp_cpuset); 732 spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask); 733 if (spdk_cpuset_count(&tmp_cpuset) == 0) { 734 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 735 "cpumask %s are all in interrupt mode, and can't be scheduled yet", 736 req.cpumask); 737 goto err; 738 } 739 } 740 741 ctx->request = request; 742 ctx->orig_thread = spdk_get_thread(); 743 744 spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx); 745 746 free(req.cpumask); 747 return; 748 749 err: 750 free(req.cpumask); 751 free(ctx); 752 } 753 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME) 754 SPDK_LOG_REGISTER_COMPONENT(app_rpc) 755