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; 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 if (req.period != 0) { 487 spdk_scheduler_set_period(req.period); 488 } else if (spdk_scheduler_get_period() == 0) { 489 /* User didn't specify a period, and no period has been set 490 * previously, so set it now to 1 second. 491 */ 492 spdk_scheduler_set_period(SPDK_SEC_TO_USEC); 493 } 494 495 ret = spdk_scheduler_set(req.name); 496 if (ret) { 497 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 498 spdk_strerror(ret)); 499 goto end; 500 } 501 502 scheduler = spdk_scheduler_get(); 503 if (scheduler != NULL && scheduler->set_opts != NULL) { 504 ret = scheduler->set_opts(params); 505 } else if (has_custom_opts) { 506 /* No custom options are allowed if set_opts are not implemented. */ 507 ret = -EINVAL; 508 } 509 if (ret) { 510 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(ret)); 511 goto end; 512 } 513 514 spdk_jsonrpc_send_bool_response(request, true); 515 516 end: 517 free_rpc_framework_set_scheduler(&req); 518 } 519 SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler, 520 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 521 522 static void 523 rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request, 524 const struct spdk_json_val *params) 525 { 526 struct spdk_json_write_ctx *w; 527 struct spdk_scheduler *scheduler = spdk_scheduler_get(); 528 uint64_t scheduler_period = spdk_scheduler_get_period(); 529 struct spdk_governor *governor = spdk_governor_get(); 530 uint32_t scheduling_core = spdk_scheduler_get_scheduling_lcore(); 531 532 if (params) { 533 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 534 "'rpc_get_scheduler' requires no arguments"); 535 return; 536 } 537 538 w = spdk_jsonrpc_begin_result(request); 539 spdk_json_write_object_begin(w); 540 if (scheduler) { 541 spdk_json_write_named_string(w, "scheduler_name", scheduler->name); 542 } 543 spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period); 544 spdk_json_write_named_string(w, "isolated_core_mask", scheduler_get_isolated_core_mask()); 545 spdk_json_write_named_uint32(w, "scheduling_core", scheduling_core); 546 if (governor != NULL) { 547 spdk_json_write_named_string(w, "governor_name", governor->name); 548 } 549 550 if (scheduler != NULL && scheduler->get_opts != NULL) { 551 scheduler->get_opts(w); 552 } 553 554 spdk_json_write_object_end(w); 555 spdk_jsonrpc_end_result(request, w); 556 } 557 SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler, 558 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 559 560 static void 561 rpc_framework_get_governor(struct spdk_jsonrpc_request *request, 562 const struct spdk_json_val *params) 563 { 564 struct spdk_json_write_ctx *w; 565 struct spdk_governor *governor = spdk_governor_get(); 566 567 if (params) { 568 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 569 "'rpc_get_governor' requires no arguments"); 570 return; 571 } 572 573 w = spdk_jsonrpc_begin_result(request); 574 spdk_json_write_object_begin(w); 575 576 if (governor != NULL) { 577 uint32_t core, index, num; 578 uint32_t freqs[SPDK_MAX_LCORE_FREQS]; 579 580 spdk_json_write_named_string(w, "governor_name", governor->name); 581 582 spdk_json_write_named_object_begin(w, "module_specific"); 583 584 governor->dump_info_json(w); 585 586 spdk_json_write_object_end(w); 587 588 spdk_json_write_named_array_begin(w, "cores"); 589 590 SPDK_ENV_FOREACH_CORE(core) { 591 spdk_json_write_object_begin(w); 592 spdk_json_write_named_uint32(w, "lcore_id", core); 593 594 memset(freqs, 0, SPDK_MAX_LCORE_FREQS * sizeof(uint32_t)); 595 596 num = governor->get_core_avail_freqs(core, freqs, SPDK_MAX_LCORE_FREQS); 597 598 spdk_json_write_named_array_begin(w, "available_frequencies"); 599 for (index = 0; index < num; index++) { 600 spdk_json_write_uint32(w, freqs[index]); 601 } 602 spdk_json_write_array_end(w); 603 604 spdk_json_write_named_uint32(w, "current_frequency", governor->get_core_curr_freq(core)); 605 spdk_json_write_object_end(w); 606 } 607 608 spdk_json_write_array_end(w); 609 } 610 611 spdk_json_write_object_end(w); 612 spdk_jsonrpc_end_result(request, w); 613 } 614 SPDK_RPC_REGISTER("framework_get_governor", rpc_framework_get_governor, SPDK_RPC_RUNTIME) 615 616 struct rpc_set_scheduler_opts_ctx { 617 char *isolated_core_mask; 618 uint32_t scheduling_core; 619 }; 620 621 static const struct spdk_json_object_decoder rpc_set_scheduler_opts_decoders[] = { 622 {"isolated_core_mask", offsetof(struct rpc_set_scheduler_opts_ctx, isolated_core_mask), spdk_json_decode_string, true}, 623 {"scheduling_core", offsetof(struct rpc_set_scheduler_opts_ctx, scheduling_core), spdk_json_decode_uint32, true}, 624 }; 625 626 static void 627 free_rpc_scheduler_set_options(struct rpc_set_scheduler_opts_ctx *r) 628 { 629 free(r->isolated_core_mask); 630 } 631 632 static void 633 rpc_scheduler_set_options(struct spdk_jsonrpc_request *request, 634 const struct spdk_json_val *params) 635 { 636 struct rpc_set_scheduler_opts_ctx req = {NULL}; 637 struct spdk_cpuset core_mask; 638 639 req.scheduling_core = spdk_scheduler_get_scheduling_lcore(); 640 641 if (spdk_json_decode_object(params, rpc_set_scheduler_opts_decoders, 642 SPDK_COUNTOF(rpc_set_scheduler_opts_decoders), &req)) { 643 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 644 "Invalid parameters"); 645 goto end; 646 } 647 648 if (req.isolated_core_mask != NULL) { 649 spdk_cpuset_parse(&core_mask, req.isolated_core_mask); 650 if (spdk_cpuset_get_cpu(&core_mask, req.scheduling_core)) { 651 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 652 "Scheduling core cannot be included in isolated core mask.\n"); 653 goto end; 654 } 655 if (scheduler_set_isolated_core_mask(core_mask) == false) { 656 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 657 "Invalid isolated core mask\n"); 658 goto end; 659 } 660 } 661 662 if (spdk_scheduler_set_scheduling_lcore(req.scheduling_core) == false) { 663 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 664 "Invalid scheduling core.\n"); 665 goto end; 666 } 667 668 spdk_jsonrpc_send_bool_response(request, true); 669 end: 670 free_rpc_scheduler_set_options(&req); 671 } 672 SPDK_RPC_REGISTER("scheduler_set_options", rpc_scheduler_set_options, SPDK_RPC_STARTUP) 673 674 struct rpc_thread_set_cpumask_ctx { 675 struct spdk_jsonrpc_request *request; 676 struct spdk_cpuset cpumask; 677 int status; 678 struct spdk_thread *orig_thread; 679 }; 680 681 static void 682 rpc_thread_set_cpumask_done(void *_ctx) 683 { 684 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 685 686 if (ctx->status == 0) { 687 spdk_jsonrpc_send_bool_response(ctx->request, true); 688 } else { 689 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 690 spdk_strerror(-ctx->status)); 691 } 692 693 free(ctx); 694 } 695 696 static void 697 _rpc_thread_set_cpumask(void *_ctx) 698 { 699 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 700 701 ctx->status = spdk_thread_set_cpumask(&ctx->cpumask); 702 703 spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx); 704 } 705 706 struct rpc_thread_set_cpumask { 707 uint64_t id; 708 char *cpumask; 709 }; 710 711 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = { 712 {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64}, 713 {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string}, 714 }; 715 716 static void 717 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request, 718 const struct spdk_json_val *params) 719 { 720 struct rpc_thread_set_cpumask req = {}; 721 struct rpc_thread_set_cpumask_ctx *ctx; 722 const struct spdk_cpuset *coremask; 723 struct spdk_cpuset tmp_mask; 724 struct spdk_thread *thread; 725 int rc; 726 727 ctx = calloc(1, sizeof(*ctx)); 728 if (ctx == NULL) { 729 SPDK_ERRLOG("Memory allocation failed\n"); 730 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 731 "Memory allocation failed"); 732 return; 733 } 734 735 if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders, 736 SPDK_COUNTOF(rpc_thread_set_cpumask_decoders), 737 &req)) { 738 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 739 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 740 "spdk_json_decode_object failed"); 741 goto err; 742 } 743 744 thread = spdk_thread_get_by_id(req.id); 745 if (thread == NULL) { 746 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id); 747 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 748 "Thread %" PRIu64 " does not exist", req.id); 749 goto err; 750 } 751 752 rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask); 753 if (rc != 0) { 754 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask); 755 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 756 "Invalid cpumask %s", req.cpumask); 757 goto err; 758 } 759 760 if (spdk_cpuset_count(&ctx->cpumask) == 0) { 761 coremask = spdk_app_get_core_mask(); 762 spdk_cpuset_copy(&tmp_mask, coremask); 763 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 764 "No CPU is selected from reactor mask %s", 765 spdk_cpuset_fmt(&tmp_mask)); 766 goto err; 767 } 768 769 /* There may be any reactors running in interrupt mode. But currently, 770 * when interrupt ability of the spdk_thread is not enabled, 771 * spdk_thread can't get executed on reactor which runs in interrupt. 772 * Exclude the situation that reactors specified by the cpumask are 773 * all in interrupt mode. 774 */ 775 if (!spdk_interrupt_mode_is_enabled()) { 776 struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core()); 777 struct spdk_cpuset tmp_cpuset; 778 779 /* Masking off reactors which are in interrupt mode */ 780 spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset); 781 spdk_cpuset_negate(&tmp_cpuset); 782 spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask); 783 if (spdk_cpuset_count(&tmp_cpuset) == 0) { 784 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 785 "cpumask %s are all in interrupt mode, and can't be scheduled yet", 786 req.cpumask); 787 goto err; 788 } 789 } 790 791 ctx->request = request; 792 ctx->orig_thread = spdk_get_thread(); 793 794 spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx); 795 796 free(req.cpumask); 797 return; 798 799 err: 800 free(req.cpumask); 801 free(ctx); 802 } 803 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME) 804 SPDK_LOG_REGISTER_COMPONENT(app_rpc) 805