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