1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/event.h" 37 #include "spdk/rpc.h" 38 #include "spdk/string.h" 39 #include "spdk/util.h" 40 #include "spdk/env.h" 41 #include "spdk/thread.h" 42 43 #include "spdk/log.h" 44 #include "spdk_internal/event.h" 45 #include "spdk_internal/thread.h" 46 47 struct rpc_spdk_kill_instance { 48 char *sig_name; 49 }; 50 51 static void 52 free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req) 53 { 54 free(req->sig_name); 55 } 56 57 static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = { 58 {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string}, 59 }; 60 61 static void 62 rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request, 63 const struct spdk_json_val *params) 64 { 65 static const struct { 66 const char *signal_string; 67 int32_t signal; 68 } signals[] = { 69 {"SIGINT", SIGINT}, 70 {"SIGTERM", SIGTERM}, 71 {"SIGQUIT", SIGQUIT}, 72 {"SIGHUP", SIGHUP}, 73 {"SIGKILL", SIGKILL}, 74 {"SIGUSR1", SIGUSR1}, 75 }; 76 size_t i, sig_count; 77 int signal; 78 struct rpc_spdk_kill_instance req = {}; 79 struct spdk_json_write_ctx *w; 80 81 if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders, 82 SPDK_COUNTOF(rpc_spdk_kill_instance_decoders), 83 &req)) { 84 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 85 goto invalid; 86 } 87 88 sig_count = SPDK_COUNTOF(signals); 89 signal = spdk_strtol(req.sig_name, 10); 90 for (i = 0 ; i < sig_count; i++) { 91 if (strcmp(req.sig_name, signals[i].signal_string) == 0 || 92 signal == signals[i].signal) { 93 break; 94 } 95 } 96 97 if (i == sig_count) { 98 goto invalid; 99 } 100 101 SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal); 102 free_rpc_spdk_kill_instance(&req); 103 kill(getpid(), signals[i].signal); 104 105 w = spdk_jsonrpc_begin_result(request); 106 spdk_json_write_bool(w, true); 107 spdk_jsonrpc_end_result(request, w); 108 return; 109 110 invalid: 111 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 112 free_rpc_spdk_kill_instance(&req); 113 } 114 SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME) 115 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(spdk_kill_instance, kill_instance) 116 117 118 struct rpc_framework_monitor_context_switch { 119 bool enabled; 120 }; 121 122 static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = { 123 {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool}, 124 }; 125 126 static void 127 rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request, 128 const struct spdk_json_val *params) 129 { 130 struct rpc_framework_monitor_context_switch req = {}; 131 struct spdk_json_write_ctx *w; 132 133 if (params != NULL) { 134 if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders, 135 SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders), 136 &req)) { 137 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n"); 138 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 139 return; 140 } 141 142 spdk_framework_enable_context_switch_monitor(req.enabled); 143 } 144 145 w = spdk_jsonrpc_begin_result(request); 146 spdk_json_write_object_begin(w); 147 148 spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled()); 149 150 spdk_json_write_object_end(w); 151 spdk_jsonrpc_end_result(request, w); 152 } 153 154 SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch, 155 SPDK_RPC_RUNTIME) 156 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_monitor_context_switch, context_switch_monitor) 157 158 struct rpc_get_stats_ctx { 159 struct spdk_jsonrpc_request *request; 160 struct spdk_json_write_ctx *w; 161 uint64_t now; 162 }; 163 164 static void 165 rpc_thread_get_stats_done(void *arg) 166 { 167 struct rpc_get_stats_ctx *ctx = arg; 168 169 spdk_json_write_array_end(ctx->w); 170 spdk_json_write_object_end(ctx->w); 171 spdk_jsonrpc_end_result(ctx->request, ctx->w); 172 173 free(ctx); 174 } 175 176 static void 177 rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn) 178 { 179 struct rpc_get_stats_ctx *ctx; 180 181 ctx = calloc(1, sizeof(*ctx)); 182 if (!ctx) { 183 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 184 "Memory allocation error"); 185 return; 186 } 187 ctx->request = request; 188 189 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 190 spdk_json_write_object_begin(ctx->w); 191 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 192 spdk_json_write_named_array_begin(ctx->w, "threads"); 193 194 spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done); 195 } 196 197 static void 198 _rpc_thread_get_stats(void *arg) 199 { 200 struct rpc_get_stats_ctx *ctx = arg; 201 struct spdk_thread *thread = spdk_get_thread(); 202 struct spdk_poller *poller; 203 struct spdk_thread_stats stats; 204 uint64_t active_pollers_count = 0; 205 uint64_t timed_pollers_count = 0; 206 uint64_t paused_pollers_count = 0; 207 208 TAILQ_FOREACH(poller, &thread->active_pollers, tailq) { 209 active_pollers_count++; 210 } 211 TAILQ_FOREACH(poller, &thread->timed_pollers, tailq) { 212 timed_pollers_count++; 213 } 214 TAILQ_FOREACH(poller, &thread->paused_pollers, tailq) { 215 paused_pollers_count++; 216 } 217 218 if (0 == spdk_thread_get_stats(&stats)) { 219 spdk_json_write_object_begin(ctx->w); 220 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 221 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 222 spdk_json_write_named_string(ctx->w, "cpumask", 223 spdk_cpuset_fmt(spdk_thread_get_cpumask(thread))); 224 spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc); 225 spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc); 226 spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count); 227 spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count); 228 spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count); 229 spdk_json_write_object_end(ctx->w); 230 } 231 } 232 233 static void 234 rpc_thread_get_stats(struct spdk_jsonrpc_request *request, 235 const struct spdk_json_val *params) 236 { 237 if (params) { 238 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 239 "'thread_get_stats' requires no arguments"); 240 return; 241 } 242 243 rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats); 244 } 245 246 SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME) 247 248 static void 249 rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w) 250 { 251 spdk_json_write_object_begin(w); 252 spdk_json_write_named_string(w, "name", poller->name); 253 spdk_json_write_named_string(w, "state", spdk_poller_state_str(poller->state)); 254 spdk_json_write_named_uint64(w, "run_count", poller->run_count); 255 spdk_json_write_named_uint64(w, "busy_count", poller->busy_count); 256 if (poller->period_ticks) { 257 spdk_json_write_named_uint64(w, "period_ticks", poller->period_ticks); 258 } 259 spdk_json_write_object_end(w); 260 } 261 262 static void 263 _rpc_thread_get_pollers(void *arg) 264 { 265 struct rpc_get_stats_ctx *ctx = arg; 266 struct spdk_thread *thread = spdk_get_thread(); 267 struct spdk_poller *poller; 268 269 spdk_json_write_object_begin(ctx->w); 270 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 271 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 272 273 spdk_json_write_named_array_begin(ctx->w, "active_pollers"); 274 TAILQ_FOREACH(poller, &thread->active_pollers, tailq) { 275 rpc_get_poller(poller, ctx->w); 276 } 277 spdk_json_write_array_end(ctx->w); 278 279 spdk_json_write_named_array_begin(ctx->w, "timed_pollers"); 280 TAILQ_FOREACH(poller, &thread->timed_pollers, tailq) { 281 rpc_get_poller(poller, ctx->w); 282 } 283 spdk_json_write_array_end(ctx->w); 284 285 spdk_json_write_named_array_begin(ctx->w, "paused_pollers"); 286 TAILQ_FOREACH(poller, &thread->paused_pollers, tailq) { 287 rpc_get_poller(poller, ctx->w); 288 } 289 spdk_json_write_array_end(ctx->w); 290 291 spdk_json_write_object_end(ctx->w); 292 } 293 294 static void 295 rpc_thread_get_pollers(struct spdk_jsonrpc_request *request, 296 const struct spdk_json_val *params) 297 { 298 if (params) { 299 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 300 "'thread_get_pollers' requires no arguments"); 301 return; 302 } 303 304 rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers); 305 } 306 307 SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME) 308 309 static void 310 rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w) 311 { 312 spdk_json_write_object_begin(w); 313 spdk_json_write_named_string(w, "name", spdk_io_device_get_name(ch->dev)); 314 spdk_json_write_named_uint32(w, "ref", ch->ref); 315 spdk_json_write_object_end(w); 316 } 317 318 static void 319 _rpc_thread_get_io_channels(void *arg) 320 { 321 struct rpc_get_stats_ctx *ctx = arg; 322 struct spdk_thread *thread = spdk_get_thread(); 323 struct spdk_io_channel *ch; 324 325 spdk_json_write_object_begin(ctx->w); 326 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 327 328 spdk_json_write_named_array_begin(ctx->w, "io_channels"); 329 TAILQ_FOREACH(ch, &thread->io_channels, tailq) { 330 rpc_get_io_channel(ch, ctx->w); 331 } 332 spdk_json_write_array_end(ctx->w); 333 334 spdk_json_write_object_end(ctx->w); 335 } 336 337 static void 338 rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request, 339 const struct spdk_json_val *params) 340 { 341 if (params) { 342 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 343 "'thread_get_io_channels' requires no arguments"); 344 return; 345 } 346 347 rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels); 348 } 349 350 SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME); 351 352 static void 353 rpc_framework_get_reactors_done(void *arg1, void *arg2) 354 { 355 struct rpc_get_stats_ctx *ctx = arg1; 356 357 spdk_json_write_array_end(ctx->w); 358 spdk_json_write_object_end(ctx->w); 359 spdk_jsonrpc_end_result(ctx->request, ctx->w); 360 361 free(ctx); 362 } 363 364 #define GET_DELTA(end, start) (end >= start ? end - start : 0) 365 366 static void 367 _rpc_framework_get_reactors(void *arg1, void *arg2) 368 { 369 struct rpc_get_stats_ctx *ctx = arg1; 370 uint32_t current_core; 371 struct spdk_reactor *reactor; 372 struct spdk_lw_thread *lw_thread; 373 struct spdk_thread *thread; 374 375 current_core = spdk_env_get_current_core(); 376 reactor = spdk_reactor_get(current_core); 377 378 assert(reactor != NULL); 379 380 spdk_json_write_object_begin(ctx->w); 381 spdk_json_write_named_uint32(ctx->w, "lcore", current_core); 382 spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc); 383 spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc); 384 385 spdk_json_write_named_array_begin(ctx->w, "lw_threads"); 386 TAILQ_FOREACH(lw_thread, &reactor->threads, link) { 387 thread = spdk_thread_get_from_ctx(lw_thread); 388 389 spdk_json_write_object_begin(ctx->w); 390 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); 391 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread)); 392 spdk_json_write_named_string(ctx->w, "cpumask", 393 spdk_cpuset_fmt(spdk_thread_get_cpumask(thread))); 394 spdk_json_write_named_uint64(ctx->w, "elapsed", 395 GET_DELTA(ctx->now, lw_thread->tsc_start)); 396 spdk_json_write_object_end(ctx->w); 397 } 398 spdk_json_write_array_end(ctx->w); 399 400 spdk_json_write_object_end(ctx->w); 401 } 402 403 static void 404 rpc_framework_get_reactors(struct spdk_jsonrpc_request *request, 405 const struct spdk_json_val *params) 406 { 407 struct rpc_get_stats_ctx *ctx; 408 409 if (params) { 410 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 411 "`framework_get_reactors` requires no arguments"); 412 return; 413 } 414 415 ctx = calloc(1, sizeof(*ctx)); 416 if (!ctx) { 417 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 418 "Memory allocation error"); 419 return; 420 } 421 422 ctx->now = spdk_get_ticks(); 423 ctx->request = request; 424 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 425 426 spdk_json_write_object_begin(ctx->w); 427 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 428 spdk_json_write_named_array_begin(ctx->w, "reactors"); 429 430 spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL, 431 rpc_framework_get_reactors_done); 432 } 433 434 SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME) 435 436 struct rpc_thread_set_cpumask_ctx { 437 struct spdk_jsonrpc_request *request; 438 struct spdk_cpuset cpumask; 439 int status; 440 struct spdk_thread *orig_thread; 441 }; 442 443 static void 444 rpc_thread_set_cpumask_done(void *_ctx) 445 { 446 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 447 struct spdk_json_write_ctx *w; 448 449 if (ctx->status == 0) { 450 w = spdk_jsonrpc_begin_result(ctx->request); 451 spdk_json_write_bool(w, true); 452 spdk_jsonrpc_end_result(ctx->request, w); 453 } else { 454 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 455 spdk_strerror(-ctx->status)); 456 } 457 458 free(ctx); 459 } 460 461 static void 462 _rpc_thread_set_cpumask(void *_ctx) 463 { 464 struct rpc_thread_set_cpumask_ctx *ctx = _ctx; 465 466 ctx->status = spdk_thread_set_cpumask(&ctx->cpumask); 467 468 spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx); 469 } 470 471 struct rpc_thread_set_cpumask { 472 uint64_t id; 473 char *cpumask; 474 }; 475 476 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = { 477 {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64}, 478 {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string}, 479 }; 480 481 static void 482 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request, 483 const struct spdk_json_val *params) 484 { 485 struct rpc_thread_set_cpumask req = {}; 486 struct rpc_thread_set_cpumask_ctx *ctx; 487 const struct spdk_cpuset *coremask; 488 struct spdk_cpuset tmp_mask; 489 struct spdk_thread *thread; 490 int rc; 491 492 ctx = calloc(1, sizeof(*ctx)); 493 if (ctx == NULL) { 494 SPDK_ERRLOG("Memory allocation failed\n"); 495 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 496 "Memory allocation failed"); 497 return; 498 } 499 500 if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders, 501 SPDK_COUNTOF(rpc_thread_set_cpumask_decoders), 502 &req)) { 503 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 504 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 505 "spdk_json_decode_object failed"); 506 goto err; 507 } 508 509 thread = spdk_thread_get_by_id(req.id); 510 if (thread == NULL) { 511 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id); 512 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 513 "Thread %" PRIu64 " does not exist", req.id); 514 goto err; 515 } 516 517 rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask); 518 if (rc != 0) { 519 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask); 520 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 521 "Invalid cpumask %s", req.cpumask); 522 goto err; 523 } 524 525 if (spdk_cpuset_count(&ctx->cpumask) == 0) { 526 coremask = spdk_app_get_core_mask(); 527 spdk_cpuset_copy(&tmp_mask, coremask); 528 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 529 "No CPU is selected from reactor mask %s\n", 530 spdk_cpuset_fmt(&tmp_mask)); 531 goto err; 532 } 533 534 ctx->request = request; 535 ctx->orig_thread = spdk_get_thread(); 536 537 spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx); 538 539 free(req.cpumask); 540 return; 541 542 err: 543 free(req.cpumask); 544 free(ctx); 545 } 546 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME) 547 SPDK_LOG_REGISTER_COMPONENT(app_rpc) 548