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 #include "spdk/version.h" 36 37 #include "spdk_internal/event.h" 38 39 #include "spdk/assert.h" 40 #include "spdk/env.h" 41 #include "spdk/init.h" 42 #include "spdk/log.h" 43 #include "spdk/thread.h" 44 #include "spdk/trace.h" 45 #include "spdk/string.h" 46 #include "spdk/rpc.h" 47 #include "spdk/util.h" 48 49 #define SPDK_APP_DEFAULT_LOG_LEVEL SPDK_LOG_NOTICE 50 #define SPDK_APP_DEFAULT_LOG_PRINT_LEVEL SPDK_LOG_INFO 51 #define SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES SPDK_DEFAULT_NUM_TRACE_ENTRIES 52 53 #define SPDK_APP_DPDK_DEFAULT_MEM_SIZE -1 54 #define SPDK_APP_DPDK_DEFAULT_MAIN_CORE -1 55 #define SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL -1 56 #define SPDK_APP_DPDK_DEFAULT_CORE_MASK "0x1" 57 #define SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR 0x200000000000 58 #define SPDK_APP_DEFAULT_CORE_LIMIT 0x140000000 /* 5 GiB */ 59 60 struct spdk_app { 61 const char *json_config_file; 62 bool json_config_ignore_errors; 63 bool stopped; 64 const char *rpc_addr; 65 int shm_id; 66 spdk_app_shutdown_cb shutdown_cb; 67 int rc; 68 }; 69 70 static struct spdk_app g_spdk_app; 71 static spdk_msg_fn g_start_fn = NULL; 72 static void *g_start_arg = NULL; 73 static struct spdk_thread *g_app_thread = NULL; 74 static bool g_delay_subsystem_init = false; 75 static bool g_shutdown_sig_received = false; 76 static char *g_executable_name; 77 static struct spdk_app_opts g_default_opts; 78 79 int 80 spdk_app_get_shm_id(void) 81 { 82 return g_spdk_app.shm_id; 83 } 84 85 /* append one empty option to indicate the end of the array */ 86 static const struct option g_cmdline_options[] = { 87 #define CONFIG_FILE_OPT_IDX 'c' 88 {"config", required_argument, NULL, CONFIG_FILE_OPT_IDX}, 89 #define LIMIT_COREDUMP_OPT_IDX 'd' 90 {"limit-coredump", no_argument, NULL, LIMIT_COREDUMP_OPT_IDX}, 91 #define TPOINT_GROUP_MASK_OPT_IDX 'e' 92 {"tpoint-group-mask", required_argument, NULL, TPOINT_GROUP_MASK_OPT_IDX}, 93 #define SINGLE_FILE_SEGMENTS_OPT_IDX 'g' 94 {"single-file-segments", no_argument, NULL, SINGLE_FILE_SEGMENTS_OPT_IDX}, 95 #define HELP_OPT_IDX 'h' 96 {"help", no_argument, NULL, HELP_OPT_IDX}, 97 #define SHM_ID_OPT_IDX 'i' 98 {"shm-id", required_argument, NULL, SHM_ID_OPT_IDX}, 99 #define CPUMASK_OPT_IDX 'm' 100 {"cpumask", required_argument, NULL, CPUMASK_OPT_IDX}, 101 #define MEM_CHANNELS_OPT_IDX 'n' 102 {"mem-channels", required_argument, NULL, MEM_CHANNELS_OPT_IDX}, 103 #define MAIN_CORE_OPT_IDX 'p' 104 {"main-core", required_argument, NULL, MAIN_CORE_OPT_IDX}, 105 {"master-core", required_argument, NULL, MAIN_CORE_OPT_IDX}, /* deprecated */ 106 #define RPC_SOCKET_OPT_IDX 'r' 107 {"rpc-socket", required_argument, NULL, RPC_SOCKET_OPT_IDX}, 108 #define MEM_SIZE_OPT_IDX 's' 109 {"mem-size", required_argument, NULL, MEM_SIZE_OPT_IDX}, 110 #define NO_PCI_OPT_IDX 'u' 111 {"no-pci", no_argument, NULL, NO_PCI_OPT_IDX}, 112 #define VERSION_OPT_IDX 'v' 113 {"version", no_argument, NULL, VERSION_OPT_IDX}, 114 #define PCI_BLOCKED_OPT_IDX 'B' 115 {"pci-blocked", required_argument, NULL, PCI_BLOCKED_OPT_IDX}, 116 {"pci-blacklist", required_argument, NULL, PCI_BLOCKED_OPT_IDX}, /* deprecated */ 117 #define LOGFLAG_OPT_IDX 'L' 118 {"logflag", required_argument, NULL, LOGFLAG_OPT_IDX}, 119 #define HUGE_UNLINK_OPT_IDX 'R' 120 {"huge-unlink", no_argument, NULL, HUGE_UNLINK_OPT_IDX}, 121 #define PCI_ALLOWED_OPT_IDX 'A' 122 {"pci-allowed", required_argument, NULL, PCI_ALLOWED_OPT_IDX}, 123 #define PCI_WHITELIST_OPT_IDX 'W' 124 {"pci-whitelist", required_argument, NULL, PCI_WHITELIST_OPT_IDX}, /* deprecated */ 125 #define SILENCE_NOTICELOG_OPT_IDX 257 126 {"silence-noticelog", no_argument, NULL, SILENCE_NOTICELOG_OPT_IDX}, 127 #define WAIT_FOR_RPC_OPT_IDX 258 128 {"wait-for-rpc", no_argument, NULL, WAIT_FOR_RPC_OPT_IDX}, 129 #define HUGE_DIR_OPT_IDX 259 130 {"huge-dir", required_argument, NULL, HUGE_DIR_OPT_IDX}, 131 #define NUM_TRACE_ENTRIES_OPT_IDX 260 132 {"num-trace-entries", required_argument, NULL, NUM_TRACE_ENTRIES_OPT_IDX}, 133 #define MAX_REACTOR_DELAY_OPT_IDX 261 134 {"max-delay", required_argument, NULL, MAX_REACTOR_DELAY_OPT_IDX}, 135 #define JSON_CONFIG_OPT_IDX 262 136 {"json", required_argument, NULL, JSON_CONFIG_OPT_IDX}, 137 #define JSON_CONFIG_IGNORE_INIT_ERRORS_IDX 263 138 {"json-ignore-init-errors", no_argument, NULL, JSON_CONFIG_IGNORE_INIT_ERRORS_IDX}, 139 #define IOVA_MODE_OPT_IDX 264 140 {"iova-mode", required_argument, NULL, IOVA_MODE_OPT_IDX}, 141 #define BASE_VIRTADDR_OPT_IDX 265 142 {"base-virtaddr", required_argument, NULL, BASE_VIRTADDR_OPT_IDX}, 143 }; 144 145 static void 146 app_start_shutdown(void *ctx) 147 { 148 if (g_spdk_app.shutdown_cb) { 149 g_spdk_app.shutdown_cb(); 150 g_spdk_app.shutdown_cb = NULL; 151 } else { 152 spdk_app_stop(0); 153 } 154 } 155 156 void 157 spdk_app_start_shutdown(void) 158 { 159 spdk_thread_send_critical_msg(g_app_thread, app_start_shutdown); 160 } 161 162 static void 163 __shutdown_signal(int signo) 164 { 165 if (!g_shutdown_sig_received) { 166 g_shutdown_sig_received = true; 167 spdk_app_start_shutdown(); 168 } 169 } 170 171 static int 172 app_opts_validate(const char *app_opts) 173 { 174 int i = 0, j; 175 176 for (i = 0; app_opts[i] != '\0'; i++) { 177 /* ignore getopt control characters */ 178 if (app_opts[i] == ':' || app_opts[i] == '+' || app_opts[i] == '-') { 179 continue; 180 } 181 182 for (j = 0; SPDK_APP_GETOPT_STRING[j] != '\0'; j++) { 183 if (app_opts[i] == SPDK_APP_GETOPT_STRING[j]) { 184 return app_opts[i]; 185 } 186 } 187 } 188 return 0; 189 } 190 191 void 192 spdk_app_opts_init(struct spdk_app_opts *opts, size_t opts_size) 193 { 194 if (!opts) { 195 SPDK_ERRLOG("opts should not be NULL\n"); 196 return; 197 } 198 199 if (!opts_size) { 200 SPDK_ERRLOG("opts_size should not be zero value\n"); 201 return; 202 } 203 204 memset(opts, 0, opts_size); 205 opts->opts_size = opts_size; 206 207 #define SET_FIELD(field, value) \ 208 if (offsetof(struct spdk_app_opts, field) + sizeof(opts->field) <= opts_size) { \ 209 opts->field = value; \ 210 } \ 211 212 SET_FIELD(enable_coredump, true); 213 SET_FIELD(shm_id, -1); 214 SET_FIELD(mem_size, SPDK_APP_DPDK_DEFAULT_MEM_SIZE); 215 SET_FIELD(main_core, SPDK_APP_DPDK_DEFAULT_MAIN_CORE); 216 SET_FIELD(mem_channel, SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL); 217 SET_FIELD(reactor_mask, SPDK_APP_DPDK_DEFAULT_CORE_MASK); 218 SET_FIELD(base_virtaddr, SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR); 219 SET_FIELD(print_level, SPDK_APP_DEFAULT_LOG_PRINT_LEVEL); 220 SET_FIELD(rpc_addr, SPDK_DEFAULT_RPC_ADDR); 221 SET_FIELD(num_entries, SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES); 222 SET_FIELD(delay_subsystem_init, false); 223 #undef SET_FIELD 224 } 225 226 static int 227 app_setup_signal_handlers(struct spdk_app_opts *opts) 228 { 229 struct sigaction sigact; 230 sigset_t sigmask; 231 int rc; 232 233 sigemptyset(&sigmask); 234 memset(&sigact, 0, sizeof(sigact)); 235 sigemptyset(&sigact.sa_mask); 236 237 sigact.sa_handler = SIG_IGN; 238 rc = sigaction(SIGPIPE, &sigact, NULL); 239 if (rc < 0) { 240 SPDK_ERRLOG("sigaction(SIGPIPE) failed\n"); 241 return rc; 242 } 243 244 /* Install the same handler for SIGINT and SIGTERM */ 245 g_shutdown_sig_received = false; 246 sigact.sa_handler = __shutdown_signal; 247 rc = sigaction(SIGINT, &sigact, NULL); 248 if (rc < 0) { 249 SPDK_ERRLOG("sigaction(SIGINT) failed\n"); 250 return rc; 251 } 252 sigaddset(&sigmask, SIGINT); 253 254 rc = sigaction(SIGTERM, &sigact, NULL); 255 if (rc < 0) { 256 SPDK_ERRLOG("sigaction(SIGTERM) failed\n"); 257 return rc; 258 } 259 sigaddset(&sigmask, SIGTERM); 260 261 pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL); 262 263 return 0; 264 } 265 266 static void 267 app_start_application(void) 268 { 269 assert(spdk_get_thread() == g_app_thread); 270 271 g_start_fn(g_start_arg); 272 } 273 274 static void 275 app_start_rpc(int rc, void *arg1) 276 { 277 if (rc) { 278 spdk_app_stop(rc); 279 return; 280 } 281 282 rc = spdk_rpc_initialize(g_spdk_app.rpc_addr); 283 if (rc) { 284 spdk_app_stop(rc); 285 return; 286 } 287 288 if (!g_delay_subsystem_init) { 289 spdk_rpc_set_state(SPDK_RPC_RUNTIME); 290 app_start_application(); 291 } 292 } 293 294 static int 295 app_opts_add_pci_addr(struct spdk_app_opts *opts, struct spdk_pci_addr **list, char *bdf) 296 { 297 struct spdk_pci_addr *tmp = *list; 298 size_t i = opts->num_pci_addr; 299 300 tmp = realloc(tmp, sizeof(*tmp) * (i + 1)); 301 if (tmp == NULL) { 302 SPDK_ERRLOG("realloc error\n"); 303 return -ENOMEM; 304 } 305 306 *list = tmp; 307 if (spdk_pci_addr_parse(*list + i, bdf) < 0) { 308 SPDK_ERRLOG("Invalid address %s\n", bdf); 309 return -EINVAL; 310 } 311 312 opts->num_pci_addr++; 313 return 0; 314 } 315 316 static int 317 app_setup_env(struct spdk_app_opts *opts) 318 { 319 struct spdk_env_opts env_opts = {}; 320 int rc; 321 322 if (opts == NULL) { 323 rc = spdk_env_init(NULL); 324 if (rc != 0) { 325 SPDK_ERRLOG("Unable to reinitialize SPDK env\n"); 326 } 327 328 return rc; 329 } 330 331 spdk_env_opts_init(&env_opts); 332 333 env_opts.name = opts->name; 334 env_opts.core_mask = opts->reactor_mask; 335 env_opts.shm_id = opts->shm_id; 336 env_opts.mem_channel = opts->mem_channel; 337 env_opts.main_core = opts->main_core; 338 env_opts.mem_size = opts->mem_size; 339 env_opts.hugepage_single_segments = opts->hugepage_single_segments; 340 env_opts.unlink_hugepage = opts->unlink_hugepage; 341 env_opts.hugedir = opts->hugedir; 342 env_opts.no_pci = opts->no_pci; 343 env_opts.num_pci_addr = opts->num_pci_addr; 344 env_opts.pci_blocked = opts->pci_blocked; 345 env_opts.pci_allowed = opts->pci_allowed; 346 env_opts.base_virtaddr = opts->base_virtaddr; 347 env_opts.env_context = opts->env_context; 348 env_opts.iova_mode = opts->iova_mode; 349 350 rc = spdk_env_init(&env_opts); 351 free(env_opts.pci_blocked); 352 free(env_opts.pci_allowed); 353 354 if (rc < 0) { 355 SPDK_ERRLOG("Unable to initialize SPDK env\n"); 356 } 357 358 return rc; 359 } 360 361 static int 362 app_setup_trace(struct spdk_app_opts *opts) 363 { 364 char shm_name[64]; 365 uint64_t tpoint_group_mask; 366 char *end; 367 368 if (opts->shm_id >= 0) { 369 snprintf(shm_name, sizeof(shm_name), "/%s_trace.%d", opts->name, opts->shm_id); 370 } else { 371 snprintf(shm_name, sizeof(shm_name), "/%s_trace.pid%d", opts->name, (int)getpid()); 372 } 373 374 if (spdk_trace_init(shm_name, opts->num_entries) != 0) { 375 return -1; 376 } 377 378 if (opts->tpoint_group_mask != NULL) { 379 errno = 0; 380 tpoint_group_mask = strtoull(opts->tpoint_group_mask, &end, 16); 381 if (*end != '\0' || errno) { 382 SPDK_ERRLOG("invalid tpoint mask %s\n", opts->tpoint_group_mask); 383 } else { 384 SPDK_NOTICELOG("Tracepoint Group Mask %s specified.\n", opts->tpoint_group_mask); 385 SPDK_NOTICELOG("Use 'spdk_trace -s %s %s %d' to capture a snapshot of events at runtime.\n", 386 opts->name, 387 opts->shm_id >= 0 ? "-i" : "-p", 388 opts->shm_id >= 0 ? opts->shm_id : getpid()); 389 #if defined(__linux__) 390 SPDK_NOTICELOG("Or copy /dev/shm%s for offline analysis/debug.\n", shm_name); 391 #endif 392 spdk_trace_set_tpoint_group_mask(tpoint_group_mask); 393 } 394 } 395 396 return 0; 397 } 398 399 static void 400 bootstrap_fn(void *arg1) 401 { 402 int rc; 403 404 if (g_spdk_app.json_config_file) { 405 g_delay_subsystem_init = false; 406 spdk_subsystem_init_from_json_config(g_spdk_app.json_config_file, g_spdk_app.rpc_addr, 407 app_start_rpc, 408 NULL, !g_spdk_app.json_config_ignore_errors); 409 } else { 410 if (!g_delay_subsystem_init) { 411 spdk_subsystem_init(app_start_rpc, NULL); 412 } else { 413 rc = spdk_rpc_initialize(g_spdk_app.rpc_addr); 414 if (rc) { 415 spdk_app_stop(rc); 416 return; 417 } 418 } 419 } 420 } 421 422 static void 423 app_copy_opts(struct spdk_app_opts *opts, struct spdk_app_opts *opts_user, size_t opts_size) 424 { 425 spdk_app_opts_init(opts, sizeof(*opts)); 426 opts->opts_size = opts_size; 427 428 #define SET_FIELD(field) \ 429 if (offsetof(struct spdk_app_opts, field) + sizeof(opts->field) <= (opts->opts_size)) { \ 430 opts->field = opts_user->field; \ 431 } \ 432 433 SET_FIELD(name); 434 SET_FIELD(json_config_file); 435 SET_FIELD(json_config_ignore_errors); 436 SET_FIELD(rpc_addr); 437 SET_FIELD(reactor_mask); 438 SET_FIELD(tpoint_group_mask); 439 SET_FIELD(shm_id); 440 SET_FIELD(shutdown_cb); 441 SET_FIELD(enable_coredump); 442 SET_FIELD(mem_channel); 443 SET_FIELD(main_core); 444 SET_FIELD(mem_size); 445 SET_FIELD(no_pci); 446 SET_FIELD(hugepage_single_segments); 447 SET_FIELD(unlink_hugepage); 448 SET_FIELD(hugedir); 449 SET_FIELD(print_level); 450 SET_FIELD(num_pci_addr); 451 SET_FIELD(pci_blocked); 452 SET_FIELD(pci_allowed); 453 SET_FIELD(iova_mode); 454 SET_FIELD(delay_subsystem_init); 455 SET_FIELD(num_entries); 456 SET_FIELD(env_context); 457 SET_FIELD(log); 458 SET_FIELD(base_virtaddr); 459 460 /* You should not remove this statement, but need to update the assert statement 461 * if you add a new field, and also add a corresponding SET_FIELD statement */ 462 SPDK_STATIC_ASSERT(sizeof(struct spdk_app_opts) == 184, "Incorrect size"); 463 464 #undef SET_FIELD 465 } 466 467 int 468 spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn, 469 void *arg1) 470 { 471 int rc; 472 char *tty; 473 struct spdk_cpuset tmp_cpumask = {}; 474 static bool g_env_was_setup = false; 475 struct spdk_app_opts opts_local = {}; 476 struct spdk_app_opts *opts = &opts_local; 477 478 if (!opts_user) { 479 SPDK_ERRLOG("opts_user should not be NULL\n"); 480 return 1; 481 } 482 483 if (!opts_user->opts_size) { 484 SPDK_ERRLOG("The opts_size in opts_user structure should not be zero value\n"); 485 return 1; 486 } 487 488 app_copy_opts(opts, opts_user, opts_user->opts_size); 489 490 if (!start_fn) { 491 SPDK_ERRLOG("start_fn should not be NULL\n"); 492 return 1; 493 } 494 495 tty = ttyname(STDERR_FILENO); 496 if (opts->print_level > SPDK_LOG_WARN && 497 isatty(STDERR_FILENO) && 498 tty && 499 !strncmp(tty, "/dev/tty", strlen("/dev/tty"))) { 500 printf("Warning: printing stderr to console terminal without -q option specified.\n"); 501 printf("Suggest using --silence-noticelog to disable logging to stderr and\n"); 502 printf("monitor syslog, or redirect stderr to a file.\n"); 503 printf("(Delaying for 10 seconds...)\n"); 504 sleep(10); 505 } 506 507 spdk_log_set_print_level(opts->print_level); 508 509 #ifndef SPDK_NO_RLIMIT 510 if (opts->enable_coredump) { 511 struct rlimit core_limits; 512 513 core_limits.rlim_cur = core_limits.rlim_max = SPDK_APP_DEFAULT_CORE_LIMIT; 514 setrlimit(RLIMIT_CORE, &core_limits); 515 } 516 #endif 517 518 memset(&g_spdk_app, 0, sizeof(g_spdk_app)); 519 g_spdk_app.json_config_file = opts->json_config_file; 520 g_spdk_app.json_config_ignore_errors = opts->json_config_ignore_errors; 521 g_spdk_app.rpc_addr = opts->rpc_addr; 522 g_spdk_app.shm_id = opts->shm_id; 523 g_spdk_app.shutdown_cb = opts->shutdown_cb; 524 g_spdk_app.rc = 0; 525 g_spdk_app.stopped = false; 526 527 spdk_log_set_level(SPDK_APP_DEFAULT_LOG_LEVEL); 528 529 /* Pass NULL to app_setup_env if SPDK app has been set up, in order to 530 * indicate that this is a reinitialization. 531 */ 532 if (app_setup_env(g_env_was_setup ? NULL : opts) < 0) { 533 return 1; 534 } 535 536 spdk_log_open(opts->log); 537 SPDK_NOTICELOG("Total cores available: %d\n", spdk_env_get_core_count()); 538 539 if ((rc = spdk_reactors_init()) != 0) { 540 SPDK_ERRLOG("Reactor Initilization failed: rc = %d\n", rc); 541 return 1; 542 } 543 544 spdk_cpuset_set_cpu(&tmp_cpumask, spdk_env_get_current_core(), true); 545 546 /* Now that the reactors have been initialized, we can create an 547 * initialization thread. */ 548 g_app_thread = spdk_thread_create("app_thread", &tmp_cpumask); 549 if (!g_app_thread) { 550 SPDK_ERRLOG("Unable to create an spdk_thread for initialization\n"); 551 return 1; 552 } 553 554 /* 555 * Disable and ignore trace setup if setting num_entries 556 * to be 0. 557 * 558 * Note the call to app_setup_trace() is located here 559 * ahead of app_setup_signal_handlers(). 560 * That's because there is not an easy/direct clean 561 * way of unwinding alloc'd resources that can occur 562 * in app_setup_signal_handlers(). 563 */ 564 if (opts->num_entries != 0 && app_setup_trace(opts) != 0) { 565 return 1; 566 } 567 568 if (app_setup_signal_handlers(opts) != 0) { 569 return 1; 570 } 571 572 g_delay_subsystem_init = opts->delay_subsystem_init; 573 g_start_fn = start_fn; 574 g_start_arg = arg1; 575 576 spdk_thread_send_msg(g_app_thread, bootstrap_fn, NULL); 577 578 /* This blocks until spdk_app_stop is called */ 579 spdk_reactors_start(); 580 581 g_env_was_setup = true; 582 583 return g_spdk_app.rc; 584 } 585 586 void 587 spdk_app_fini(void) 588 { 589 spdk_trace_cleanup(); 590 spdk_reactors_fini(); 591 spdk_env_fini(); 592 spdk_log_close(); 593 } 594 595 static void 596 _start_subsystem_fini(void *arg1) 597 { 598 if (_spdk_get_scheduling_reactor()->flags.is_scheduling) { 599 spdk_thread_send_msg(g_app_thread, _start_subsystem_fini, NULL); 600 return; 601 } 602 603 spdk_subsystem_fini(spdk_reactors_stop, NULL); 604 } 605 606 static void 607 app_stop(void *arg1) 608 { 609 if (g_spdk_app.rc == 0) { 610 g_spdk_app.rc = (int)(intptr_t)arg1; 611 } 612 613 if (g_spdk_app.stopped) { 614 SPDK_NOTICELOG("spdk_app_stop called twice\n"); 615 return; 616 } 617 618 spdk_rpc_finish(); 619 g_spdk_app.stopped = true; 620 _spdk_scheduler_disable(); 621 _start_subsystem_fini(NULL); 622 } 623 624 void 625 spdk_app_stop(int rc) 626 { 627 if (rc) { 628 SPDK_WARNLOG("spdk_app_stop'd on non-zero\n"); 629 } 630 631 /* 632 * We want to run spdk_subsystem_fini() from the same thread where spdk_subsystem_init() 633 * was called. 634 */ 635 spdk_thread_send_msg(g_app_thread, app_stop, (void *)(intptr_t)rc); 636 } 637 638 struct spdk_thread * 639 _spdk_get_app_thread(void) 640 { 641 return g_app_thread; 642 } 643 644 static void 645 usage(void (*app_usage)(void)) 646 { 647 printf("%s [options]\n", g_executable_name); 648 printf("options:\n"); 649 printf(" -c, --config <config> JSON config file (default %s)\n", 650 g_default_opts.json_config_file != NULL ? g_default_opts.json_config_file : "none"); 651 printf(" --json <config> JSON config file (default %s)\n", 652 g_default_opts.json_config_file != NULL ? g_default_opts.json_config_file : "none"); 653 printf(" --json-ignore-init-errors\n"); 654 printf(" don't exit on invalid config entry\n"); 655 printf(" -d, --limit-coredump do not set max coredump size to RLIM_INFINITY\n"); 656 printf(" -g, --single-file-segments\n"); 657 printf(" force creating just one hugetlbfs file\n"); 658 printf(" -h, --help show this usage\n"); 659 printf(" -i, --shm-id <id> shared memory ID (optional)\n"); 660 printf(" -m, --cpumask <mask> core mask for DPDK\n"); 661 printf(" -n, --mem-channels <num> channel number of memory channels used for DPDK\n"); 662 printf(" -p, --main-core <id> main (primary) core for DPDK\n"); 663 printf(" -r, --rpc-socket <path> RPC listen address (default %s)\n", SPDK_DEFAULT_RPC_ADDR); 664 printf(" -s, --mem-size <size> memory size in MB for DPDK (default: "); 665 #ifndef __linux__ 666 if (g_default_opts.mem_size <= 0) { 667 printf("all hugepage memory)\n"); 668 } else 669 #endif 670 { 671 printf("%dMB)\n", g_default_opts.mem_size >= 0 ? g_default_opts.mem_size : 0); 672 } 673 printf(" --silence-noticelog disable notice level logging to stderr\n"); 674 printf(" -u, --no-pci disable PCI access\n"); 675 printf(" --wait-for-rpc wait for RPCs to initialize subsystems\n"); 676 printf(" --max-delay <num> maximum reactor delay (in microseconds)\n"); 677 printf(" -B, --pci-blocked <bdf>\n"); 678 printf(" pci addr to block (can be used more than once)\n"); 679 printf(" -R, --huge-unlink unlink huge files after initialization\n"); 680 printf(" -v, --version print SPDK version\n"); 681 printf(" -A, --pci-allowed <bdf>\n"); 682 printf(" pci addr to allow (-B and -A cannot be used at the same time)\n"); 683 printf(" --huge-dir <path> use a specific hugetlbfs mount to reserve memory from\n"); 684 printf(" --iova-mode <pa/va> set IOVA mode ('pa' for IOVA_PA and 'va' for IOVA_VA)\n"); 685 printf(" --base-virtaddr <addr> the base virtual address for DPDK (default: 0x200000000000)\n"); 686 printf(" --num-trace-entries <num> number of trace entries for each core, must be power of 2, setting 0 to disable trace (default %d)\n", 687 SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES); 688 spdk_log_usage(stdout, "-L"); 689 spdk_trace_mask_usage(stdout, "-e"); 690 if (app_usage) { 691 app_usage(); 692 } 693 } 694 695 spdk_app_parse_args_rvals_t 696 spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts, 697 const char *app_getopt_str, struct option *app_long_opts, 698 int (*app_parse)(int ch, char *arg), 699 void (*app_usage)(void)) 700 { 701 int ch, rc, opt_idx, global_long_opts_len, app_long_opts_len; 702 struct option *cmdline_options; 703 char *cmdline_short_opts = NULL; 704 enum spdk_app_parse_args_rvals retval = SPDK_APP_PARSE_ARGS_FAIL; 705 long int tmp; 706 707 memcpy(&g_default_opts, opts, sizeof(g_default_opts)); 708 709 if (opts->json_config_file && access(opts->json_config_file, R_OK) != 0) { 710 SPDK_WARNLOG("Can't read JSON configuration file '%s'\n", opts->json_config_file); 711 opts->json_config_file = NULL; 712 } 713 714 if (app_long_opts == NULL) { 715 app_long_opts_len = 0; 716 } else { 717 for (app_long_opts_len = 0; 718 app_long_opts[app_long_opts_len].name != NULL; 719 app_long_opts_len++); 720 } 721 722 global_long_opts_len = SPDK_COUNTOF(g_cmdline_options); 723 724 cmdline_options = calloc(global_long_opts_len + app_long_opts_len + 1, sizeof(*cmdline_options)); 725 if (!cmdline_options) { 726 SPDK_ERRLOG("Out of memory\n"); 727 return SPDK_APP_PARSE_ARGS_FAIL; 728 } 729 730 memcpy(&cmdline_options[0], g_cmdline_options, sizeof(g_cmdline_options)); 731 if (app_long_opts) { 732 memcpy(&cmdline_options[global_long_opts_len], app_long_opts, 733 app_long_opts_len * sizeof(*app_long_opts)); 734 } 735 736 if (app_getopt_str != NULL) { 737 ch = app_opts_validate(app_getopt_str); 738 if (ch) { 739 SPDK_ERRLOG("Duplicated option '%c' between the generic and application specific spdk opts.\n", 740 ch); 741 goto out; 742 } 743 } 744 745 cmdline_short_opts = spdk_sprintf_alloc("%s%s", app_getopt_str, SPDK_APP_GETOPT_STRING); 746 if (!cmdline_short_opts) { 747 SPDK_ERRLOG("Out of memory\n"); 748 goto out; 749 } 750 751 g_executable_name = argv[0]; 752 753 while ((ch = getopt_long(argc, argv, cmdline_short_opts, cmdline_options, &opt_idx)) != -1) { 754 switch (ch) { 755 case CONFIG_FILE_OPT_IDX: 756 case JSON_CONFIG_OPT_IDX: 757 opts->json_config_file = optarg; 758 break; 759 case JSON_CONFIG_IGNORE_INIT_ERRORS_IDX: 760 opts->json_config_ignore_errors = true; 761 break; 762 case LIMIT_COREDUMP_OPT_IDX: 763 opts->enable_coredump = false; 764 break; 765 case TPOINT_GROUP_MASK_OPT_IDX: 766 opts->tpoint_group_mask = optarg; 767 break; 768 case SINGLE_FILE_SEGMENTS_OPT_IDX: 769 opts->hugepage_single_segments = true; 770 break; 771 case HELP_OPT_IDX: 772 usage(app_usage); 773 retval = SPDK_APP_PARSE_ARGS_HELP; 774 goto out; 775 case SHM_ID_OPT_IDX: 776 opts->shm_id = spdk_strtol(optarg, 0); 777 if (opts->shm_id < 0) { 778 SPDK_ERRLOG("Invalid shared memory ID %s\n", optarg); 779 goto out; 780 } 781 break; 782 case CPUMASK_OPT_IDX: 783 opts->reactor_mask = optarg; 784 break; 785 case MEM_CHANNELS_OPT_IDX: 786 opts->mem_channel = spdk_strtol(optarg, 0); 787 if (opts->mem_channel < 0) { 788 SPDK_ERRLOG("Invalid memory channel %s\n", optarg); 789 goto out; 790 } 791 break; 792 case MAIN_CORE_OPT_IDX: 793 opts->main_core = spdk_strtol(optarg, 0); 794 if (opts->main_core < 0) { 795 SPDK_ERRLOG("Invalid main core %s\n", optarg); 796 goto out; 797 } 798 break; 799 case SILENCE_NOTICELOG_OPT_IDX: 800 opts->print_level = SPDK_LOG_WARN; 801 break; 802 case RPC_SOCKET_OPT_IDX: 803 opts->rpc_addr = optarg; 804 break; 805 case MEM_SIZE_OPT_IDX: { 806 uint64_t mem_size_mb; 807 bool mem_size_has_prefix; 808 809 rc = spdk_parse_capacity(optarg, &mem_size_mb, &mem_size_has_prefix); 810 if (rc != 0) { 811 SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg); 812 usage(app_usage); 813 goto out; 814 } 815 816 if (mem_size_has_prefix) { 817 /* the mem size is in MB by default, so if a prefix was 818 * specified, we need to manually convert to MB. 819 */ 820 mem_size_mb /= 1024 * 1024; 821 } 822 823 if (mem_size_mb > INT_MAX) { 824 SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg); 825 usage(app_usage); 826 goto out; 827 } 828 829 opts->mem_size = (int) mem_size_mb; 830 break; 831 } 832 case NO_PCI_OPT_IDX: 833 opts->no_pci = true; 834 break; 835 case WAIT_FOR_RPC_OPT_IDX: 836 opts->delay_subsystem_init = true; 837 break; 838 case PCI_BLOCKED_OPT_IDX: 839 if (opts->pci_allowed) { 840 free(opts->pci_allowed); 841 opts->pci_allowed = NULL; 842 SPDK_ERRLOG("-B and -A cannot be used at the same time\n"); 843 usage(app_usage); 844 goto out; 845 } 846 847 rc = app_opts_add_pci_addr(opts, &opts->pci_blocked, optarg); 848 if (rc != 0) { 849 free(opts->pci_blocked); 850 opts->pci_blocked = NULL; 851 goto out; 852 } 853 break; 854 case LOGFLAG_OPT_IDX: 855 rc = spdk_log_set_flag(optarg); 856 if (rc < 0) { 857 SPDK_ERRLOG("unknown flag\n"); 858 usage(app_usage); 859 goto out; 860 } 861 #ifdef DEBUG 862 opts->print_level = SPDK_LOG_DEBUG; 863 #endif 864 break; 865 case HUGE_UNLINK_OPT_IDX: 866 opts->unlink_hugepage = true; 867 break; 868 case PCI_WHITELIST_OPT_IDX: 869 SPDK_WARNLOG("-W/--pci-whitelist is deprecated. Use -A/--pci-allowed.\n"); 870 /* fallthrough */ 871 case PCI_ALLOWED_OPT_IDX: 872 if (opts->pci_blocked) { 873 free(opts->pci_blocked); 874 opts->pci_blocked = NULL; 875 SPDK_ERRLOG("-B and -W cannot be used at the same time\n"); 876 usage(app_usage); 877 goto out; 878 } 879 880 rc = app_opts_add_pci_addr(opts, &opts->pci_allowed, optarg); 881 if (rc != 0) { 882 free(opts->pci_allowed); 883 opts->pci_allowed = NULL; 884 goto out; 885 } 886 break; 887 case BASE_VIRTADDR_OPT_IDX: 888 tmp = spdk_strtoll(optarg, 0); 889 if (tmp <= 0) { 890 SPDK_ERRLOG("Invalid base-virtaddr %s\n", optarg); 891 usage(app_usage); 892 goto out; 893 } 894 opts->base_virtaddr = (uint64_t)tmp; 895 break; 896 case HUGE_DIR_OPT_IDX: 897 opts->hugedir = optarg; 898 break; 899 case IOVA_MODE_OPT_IDX: 900 opts->iova_mode = optarg; 901 break; 902 case NUM_TRACE_ENTRIES_OPT_IDX: 903 tmp = spdk_strtoll(optarg, 0); 904 if (tmp < 0) { 905 SPDK_ERRLOG("Invalid num-trace-entries %s\n", optarg); 906 usage(app_usage); 907 goto out; 908 } 909 opts->num_entries = (uint64_t)tmp; 910 if (opts->num_entries > 0 && opts->num_entries & (opts->num_entries - 1)) { 911 SPDK_ERRLOG("num-trace-entries must be power of 2\n"); 912 usage(app_usage); 913 goto out; 914 } 915 break; 916 case MAX_REACTOR_DELAY_OPT_IDX: 917 SPDK_ERRLOG("Deprecation warning: The maximum allowed latency parameter is no longer supported.\n"); 918 break; 919 case VERSION_OPT_IDX: 920 printf(SPDK_VERSION_STRING"\n"); 921 retval = SPDK_APP_PARSE_ARGS_HELP; 922 goto out; 923 case '?': 924 /* 925 * In the event getopt() above detects an option 926 * in argv that is NOT in the getopt_str, 927 * getopt() will return a '?' indicating failure. 928 */ 929 usage(app_usage); 930 goto out; 931 default: 932 rc = app_parse(ch, optarg); 933 if (rc) { 934 SPDK_ERRLOG("Parsing application specific arguments failed: %d\n", rc); 935 goto out; 936 } 937 } 938 } 939 940 if (opts->json_config_file && opts->delay_subsystem_init) { 941 SPDK_ERRLOG("JSON configuration file can't be used together with --wait-for-rpc.\n"); 942 goto out; 943 } 944 945 retval = SPDK_APP_PARSE_ARGS_SUCCESS; 946 out: 947 if (retval != SPDK_APP_PARSE_ARGS_SUCCESS) { 948 free(opts->pci_blocked); 949 opts->pci_blocked = NULL; 950 free(opts->pci_allowed); 951 opts->pci_allowed = NULL; 952 } 953 free(cmdline_short_opts); 954 free(cmdline_options); 955 return retval; 956 } 957 958 void 959 spdk_app_usage(void) 960 { 961 if (g_executable_name == NULL) { 962 SPDK_ERRLOG("%s not valid before calling spdk_app_parse_args()\n", __func__); 963 return; 964 } 965 966 usage(NULL); 967 } 968 969 static void 970 rpc_framework_start_init_cpl(int rc, void *arg1) 971 { 972 struct spdk_jsonrpc_request *request = arg1; 973 974 assert(spdk_get_thread() == g_app_thread); 975 976 if (rc) { 977 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 978 "framework_initialization failed"); 979 return; 980 } 981 982 spdk_rpc_set_state(SPDK_RPC_RUNTIME); 983 app_start_application(); 984 985 spdk_jsonrpc_send_bool_response(request, true); 986 } 987 988 static void 989 rpc_framework_start_init(struct spdk_jsonrpc_request *request, 990 const struct spdk_json_val *params) 991 { 992 if (params != NULL) { 993 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 994 "framework_start_init requires no parameters"); 995 return; 996 } 997 998 spdk_subsystem_init(rpc_framework_start_init_cpl, request); 999 } 1000 SPDK_RPC_REGISTER("framework_start_init", rpc_framework_start_init, SPDK_RPC_STARTUP) 1001 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_start_init, start_subsystem_init) 1002 1003 struct subsystem_init_poller_ctx { 1004 struct spdk_poller *init_poller; 1005 struct spdk_jsonrpc_request *request; 1006 }; 1007 1008 static int 1009 rpc_subsystem_init_poller_ctx(void *ctx) 1010 { 1011 struct subsystem_init_poller_ctx *poller_ctx = ctx; 1012 1013 if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME) { 1014 spdk_jsonrpc_send_bool_response(poller_ctx->request, true); 1015 spdk_poller_unregister(&poller_ctx->init_poller); 1016 free(poller_ctx); 1017 } 1018 1019 return SPDK_POLLER_BUSY; 1020 } 1021 1022 static void 1023 rpc_framework_wait_init(struct spdk_jsonrpc_request *request, 1024 const struct spdk_json_val *params) 1025 { 1026 struct subsystem_init_poller_ctx *ctx; 1027 1028 if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME) { 1029 spdk_jsonrpc_send_bool_response(request, true); 1030 } else { 1031 ctx = malloc(sizeof(struct subsystem_init_poller_ctx)); 1032 if (ctx == NULL) { 1033 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1034 "Unable to allocate memory for the request context\n"); 1035 return; 1036 } 1037 ctx->request = request; 1038 ctx->init_poller = SPDK_POLLER_REGISTER(rpc_subsystem_init_poller_ctx, ctx, 0); 1039 } 1040 } 1041 SPDK_RPC_REGISTER("framework_wait_init", rpc_framework_wait_init, 1042 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 1043 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_wait_init, wait_subsystem_init) 1044