4 * Copyright (c) Intel Corporation. All rights reserved.
5 * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/stdinc.h"
35 #include "spdk/version.h"
37 #include "spdk_internal/event.h"
41 #include "spdk/conf.h"
42 #include "spdk/thread.h"
43 #include "spdk/trace.h"
44 #include "spdk/string.h"
46 #include "spdk/util.h"
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
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_DPDK_DEFAULT_BASE_VIRTADDR 0x200000000000
57 #define SPDK_APP_DEFAULT_CORE_LIMIT 0x140000000 /* 5 GiB */
60 struct spdk_conf
*config
;
61 const char *json_config_file
;
62 bool json_config_ignore_errors
;
65 spdk_app_shutdown_cb shutdown_cb
;
69 static struct spdk_app g_spdk_app
;
70 static spdk_msg_fn g_start_fn
= NULL
;
71 static void *g_start_arg
= NULL
;
72 static struct spdk_thread
*g_app_thread
= NULL
;
73 static bool g_delay_subsystem_init
= false;
74 static bool g_shutdown_sig_received
= false;
75 static char *g_executable_name
;
76 static struct spdk_app_opts g_default_opts
;
79 spdk_app_get_shm_id(void)
81 return g_spdk_app
.shm_id
;
84 /* append one empty option to indicate the end of the array */
85 static const struct option g_cmdline_options
[] = {
86 #define CONFIG_FILE_OPT_IDX 'c'
87 {"config", required_argument
, NULL
, CONFIG_FILE_OPT_IDX
},
88 #define LIMIT_COREDUMP_OPT_IDX 'd'
89 {"limit-coredump", no_argument
, NULL
, LIMIT_COREDUMP_OPT_IDX
},
90 #define TPOINT_GROUP_MASK_OPT_IDX 'e'
91 {"tpoint-group-mask", required_argument
, NULL
, TPOINT_GROUP_MASK_OPT_IDX
},
92 #define SINGLE_FILE_SEGMENTS_OPT_IDX 'g'
93 {"single-file-segments", no_argument
, NULL
, SINGLE_FILE_SEGMENTS_OPT_IDX
},
94 #define HELP_OPT_IDX 'h'
95 {"help", no_argument
, NULL
, HELP_OPT_IDX
},
96 #define SHM_ID_OPT_IDX 'i'
97 {"shm-id", required_argument
, NULL
, SHM_ID_OPT_IDX
},
98 #define CPUMASK_OPT_IDX 'm'
99 {"cpumask", required_argument
, NULL
, CPUMASK_OPT_IDX
},
100 #define MEM_CHANNELS_OPT_IDX 'n'
101 {"mem-channels", required_argument
, NULL
, MEM_CHANNELS_OPT_IDX
},
102 #define MASTER_CORE_OPT_IDX 'p'
103 {"master-core", required_argument
, NULL
, MASTER_CORE_OPT_IDX
},
104 #define RPC_SOCKET_OPT_IDX 'r'
105 {"rpc-socket", required_argument
, NULL
, RPC_SOCKET_OPT_IDX
},
106 #define MEM_SIZE_OPT_IDX 's'
107 {"mem-size", required_argument
, NULL
, MEM_SIZE_OPT_IDX
},
108 #define NO_PCI_OPT_IDX 'u'
109 {"no-pci", no_argument
, NULL
, NO_PCI_OPT_IDX
},
110 #define VERSION_OPT_IDX 'v'
111 {"version", no_argument
, NULL
, VERSION_OPT_IDX
},
112 #define PCI_BLACKLIST_OPT_IDX 'B'
113 {"pci-blacklist", required_argument
, NULL
, PCI_BLACKLIST_OPT_IDX
},
114 #define LOGFLAG_OPT_IDX 'L'
115 {"logflag", required_argument
, NULL
, LOGFLAG_OPT_IDX
},
116 #define HUGE_UNLINK_OPT_IDX 'R'
117 {"huge-unlink", no_argument
, NULL
, HUGE_UNLINK_OPT_IDX
},
118 #define PCI_WHITELIST_OPT_IDX 'W'
119 {"pci-whitelist", required_argument
, NULL
, PCI_WHITELIST_OPT_IDX
},
120 #define SILENCE_NOTICELOG_OPT_IDX 257
121 {"silence-noticelog", no_argument
, NULL
, SILENCE_NOTICELOG_OPT_IDX
},
122 #define WAIT_FOR_RPC_OPT_IDX 258
123 {"wait-for-rpc", no_argument
, NULL
, WAIT_FOR_RPC_OPT_IDX
},
124 #define HUGE_DIR_OPT_IDX 259
125 {"huge-dir", required_argument
, NULL
, HUGE_DIR_OPT_IDX
},
126 #define NUM_TRACE_ENTRIES_OPT_IDX 260
127 {"num-trace-entries", required_argument
, NULL
, NUM_TRACE_ENTRIES_OPT_IDX
},
128 #define MAX_REACTOR_DELAY_OPT_IDX 261
129 {"max-delay", required_argument
, NULL
, MAX_REACTOR_DELAY_OPT_IDX
},
130 #define JSON_CONFIG_OPT_IDX 262
131 {"json", required_argument
, NULL
, JSON_CONFIG_OPT_IDX
},
132 #define JSON_CONFIG_IGNORE_INIT_ERRORS_IDX 263
133 {"json-ignore-init-errors", no_argument
, NULL
, JSON_CONFIG_IGNORE_INIT_ERRORS_IDX
},
134 #define IOVA_MODE_OPT_IDX 264
135 {"iova-mode", required_argument
, NULL
, IOVA_MODE_OPT_IDX
},
136 #define BASE_VIRTADDR_OPT_IDX 265
137 {"base-virtaddr", required_argument
, NULL
, BASE_VIRTADDR_OPT_IDX
},
141 #define GLOBAL_CONFIG_TMPL \
142 "# Configuration file\n" \
144 "# Please write all parameters using ASCII.\n" \
145 "# The parameter must be quoted if it includes whitespace.\n" \
147 "# Configuration syntax:\n" \
148 "# Spaces at head of line are deleted, other spaces are as separator\n" \
149 "# Lines starting with '#' are comments and not evaluated.\n" \
150 "# Lines ending with '\\' are concatenated with the next line.\n" \
151 "# Bracketed keys are section keys grouping the following value keys.\n" \
152 "# Number of section key is used as a tag number.\n" \
153 "# Ex. [TargetNode1] = TargetNode section key with tag number 1\n" \
155 " Comment \"Global section\"\n" \
157 " # Users can restrict work items to only run on certain cores by\n" \
158 " # specifying a ReactorMask. Default is to allow work items to run\n" \
159 " # on all cores. Core 0 must be set in the mask if one is specified.\n" \
160 " # Default: 0xFFFF (cores 0-15)\n" \
161 " ReactorMask \"0x%s\"\n" \
163 " # Tracepoint group mask for spdk trace buffers\n" \
164 " # Default: 0x0 (all tracepoint groups disabled)\n" \
165 " # Set to 0xFFFF to enable all tracepoint groups.\n" \
166 " TpointGroupMask \"0x%" PRIX64 "\"\n" \
170 app_config_dump_global_section(FILE *fp
)
172 struct spdk_cpuset
*coremask
;
178 coremask
= spdk_app_get_core_mask();
180 fprintf(fp
, GLOBAL_CONFIG_TMPL
, spdk_cpuset_fmt(coremask
),
181 spdk_trace_get_tpoint_group_mask());
185 spdk_app_get_running_config(char **config_str
, char *name
)
189 long length
= 0, ret
= 0;
191 char config_template
[64];
193 snprintf(config_template
, sizeof(config_template
), "/tmp/%s.XXXXXX", name
);
194 /* Create temporary file to hold config */
195 fd
= mkstemp(config_template
);
197 SPDK_ERRLOG("mkstemp failed\n");
200 fp
= fdopen(fd
, "wb+");
202 SPDK_ERRLOG("error opening tmpfile fd = %d\n", fd
);
207 setvbuf(fp
, vbuf
, _IOFBF
, BUFSIZ
);
209 app_config_dump_global_section(fp
);
210 spdk_subsystem_config(fp
);
214 *config_str
= malloc(length
+ 1);
216 SPDK_ERRLOG("out-of-memory for config\n");
220 fseek(fp
, 0, SEEK_SET
);
221 ret
= fread(*config_str
, sizeof(char), length
, fp
);
223 SPDK_ERRLOG("short read\n");
226 (*config_str
)[length
] = '\0';
232 app_start_shutdown(void *ctx
)
234 if (g_spdk_app
.shutdown_cb
) {
235 g_spdk_app
.shutdown_cb();
236 g_spdk_app
.shutdown_cb
= NULL
;
243 spdk_app_start_shutdown(void)
245 spdk_thread_send_critical_msg(g_app_thread
, app_start_shutdown
);
249 __shutdown_signal(int signo
)
251 if (!g_shutdown_sig_received
) {
252 g_shutdown_sig_received
= true;
253 spdk_app_start_shutdown();
258 app_opts_validate(const char *app_opts
)
262 for (i
= 0; app_opts
[i
] != '\0'; i
++) {
263 /* ignore getopt control characters */
264 if (app_opts
[i
] == ':' || app_opts
[i
] == '+' || app_opts
[i
] == '-') {
268 for (j
= 0; SPDK_APP_GETOPT_STRING
[j
] != '\0'; j
++) {
269 if (app_opts
[i
] == SPDK_APP_GETOPT_STRING
[j
]) {
278 spdk_app_opts_init(struct spdk_app_opts
*opts
)
284 memset(opts
, 0, sizeof(*opts
));
286 opts
->enable_coredump
= true;
288 opts
->mem_size
= SPDK_APP_DPDK_DEFAULT_MEM_SIZE
;
289 opts
->master_core
= SPDK_APP_DPDK_DEFAULT_MASTER_CORE
;
290 opts
->mem_channel
= SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL
;
291 opts
->reactor_mask
= NULL
;
292 opts
->base_virtaddr
= SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR
;
293 opts
->print_level
= SPDK_APP_DEFAULT_LOG_PRINT_LEVEL
;
294 opts
->rpc_addr
= SPDK_DEFAULT_RPC_ADDR
;
295 opts
->num_entries
= SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES
;
296 opts
->delay_subsystem_init
= false;
300 app_setup_signal_handlers(struct spdk_app_opts
*opts
)
302 struct sigaction sigact
;
306 sigemptyset(&sigmask
);
307 memset(&sigact
, 0, sizeof(sigact
));
308 sigemptyset(&sigact
.sa_mask
);
310 sigact
.sa_handler
= SIG_IGN
;
311 rc
= sigaction(SIGPIPE
, &sigact
, NULL
);
313 SPDK_ERRLOG("sigaction(SIGPIPE) failed\n");
317 /* Install the same handler for SIGINT and SIGTERM */
318 g_shutdown_sig_received
= false;
319 sigact
.sa_handler
= __shutdown_signal
;
320 rc
= sigaction(SIGINT
, &sigact
, NULL
);
322 SPDK_ERRLOG("sigaction(SIGINT) failed\n");
325 sigaddset(&sigmask
, SIGINT
);
327 rc
= sigaction(SIGTERM
, &sigact
, NULL
);
329 SPDK_ERRLOG("sigaction(SIGTERM) failed\n");
332 sigaddset(&sigmask
, SIGTERM
);
334 if (opts
->usr1_handler
!= NULL
) {
335 sigact
.sa_handler
= opts
->usr1_handler
;
336 rc
= sigaction(SIGUSR1
, &sigact
, NULL
);
338 SPDK_ERRLOG("sigaction(SIGUSR1) failed\n");
341 sigaddset(&sigmask
, SIGUSR1
);
344 pthread_sigmask(SIG_UNBLOCK
, &sigmask
, NULL
);
350 app_start_application(void)
352 assert(spdk_get_thread() == g_app_thread
);
354 g_start_fn(g_start_arg
);
358 app_start_rpc(int rc
, void *arg1
)
365 spdk_rpc_initialize(g_spdk_app
.rpc_addr
);
366 if (!g_delay_subsystem_init
) {
367 spdk_rpc_set_state(SPDK_RPC_RUNTIME
);
368 app_start_application();
372 static struct spdk_conf
*
373 app_setup_conf(const char *config_file
)
375 struct spdk_conf
*config
;
378 config
= spdk_conf_allocate();
379 assert(config
!= NULL
);
381 rc
= spdk_conf_read(config
, config_file
);
383 SPDK_ERRLOG("Could not read config file %s\n", config_file
);
386 if (spdk_conf_first_section(config
) == NULL
) {
387 SPDK_ERRLOG("Invalid config file %s\n", config_file
);
391 spdk_conf_set_as_default(config
);
395 spdk_conf_free(config
);
400 app_opts_add_pci_addr(struct spdk_app_opts
*opts
, struct spdk_pci_addr
**list
, char *bdf
)
402 struct spdk_pci_addr
*tmp
= *list
;
403 size_t i
= opts
->num_pci_addr
;
405 tmp
= realloc(tmp
, sizeof(*tmp
) * (i
+ 1));
407 SPDK_ERRLOG("realloc error\n");
412 if (spdk_pci_addr_parse(*list
+ i
, bdf
) < 0) {
413 SPDK_ERRLOG("Invalid address %s\n", bdf
);
417 opts
->num_pci_addr
++;
422 app_read_config_file_global_params(struct spdk_app_opts
*opts
)
424 struct spdk_conf_section
*sp
;
428 sp
= spdk_conf_find_section(NULL
, "Global");
430 if (opts
->shm_id
== -1) {
432 opts
->shm_id
= spdk_conf_section_get_intval(sp
, "SharedMemoryID");
436 if (opts
->reactor_mask
== NULL
) {
437 if (sp
&& spdk_conf_section_get_val(sp
, "ReactorMask")) {
438 SPDK_ERRLOG("ReactorMask config option is deprecated. Use -m/--cpumask\n"
439 "command line parameter instead.\n");
440 opts
->reactor_mask
= spdk_conf_section_get_val(sp
, "ReactorMask");
442 opts
->reactor_mask
= SPDK_APP_DPDK_DEFAULT_CORE_MASK
;
446 if (!opts
->no_pci
&& sp
) {
447 opts
->no_pci
= spdk_conf_section_get_boolval(sp
, "NoPci", false);
450 if (opts
->tpoint_group_mask
== NULL
) {
452 opts
->tpoint_group_mask
= spdk_conf_section_get_val(sp
, "TpointGroupMask");
461 bdf
= spdk_conf_section_get_nmval(sp
, "PciBlacklist", i
, 0);
466 rc
= app_opts_add_pci_addr(opts
, &opts
->pci_blacklist
, bdf
);
468 free(opts
->pci_blacklist
);
474 bdf
= spdk_conf_section_get_nmval(sp
, "PciWhitelist", i
, 0);
479 if (opts
->pci_blacklist
!= NULL
) {
480 SPDK_ERRLOG("PciBlacklist and PciWhitelist cannot be used at the same time\n");
481 free(opts
->pci_blacklist
);
485 rc
= app_opts_add_pci_addr(opts
, &opts
->pci_whitelist
, bdf
);
487 free(opts
->pci_whitelist
);
495 app_setup_env(struct spdk_app_opts
*opts
)
497 struct spdk_env_opts env_opts
= {};
501 rc
= spdk_env_init(NULL
);
503 SPDK_ERRLOG("Unable to reinitialize SPDK env\n");
510 spdk_env_opts_init(&env_opts
);
512 env_opts
.name
= opts
->name
;
513 env_opts
.core_mask
= opts
->reactor_mask
;
514 env_opts
.shm_id
= opts
->shm_id
;
515 env_opts
.mem_channel
= opts
->mem_channel
;
516 env_opts
.master_core
= opts
->master_core
;
517 env_opts
.mem_size
= opts
->mem_size
;
518 env_opts
.hugepage_single_segments
= opts
->hugepage_single_segments
;
519 env_opts
.unlink_hugepage
= opts
->unlink_hugepage
;
520 env_opts
.hugedir
= opts
->hugedir
;
521 env_opts
.no_pci
= opts
->no_pci
;
522 env_opts
.num_pci_addr
= opts
->num_pci_addr
;
523 env_opts
.pci_blacklist
= opts
->pci_blacklist
;
524 env_opts
.pci_whitelist
= opts
->pci_whitelist
;
525 env_opts
.env_context
= opts
->env_context
;
526 env_opts
.iova_mode
= opts
->iova_mode
;
528 rc
= spdk_env_init(&env_opts
);
529 free(env_opts
.pci_blacklist
);
530 free(env_opts
.pci_whitelist
);
534 SPDK_ERRLOG("Unable to initialize SPDK env\n");
541 app_setup_trace(struct spdk_app_opts
*opts
)
544 uint64_t tpoint_group_mask
;
547 if (opts
->shm_id
>= 0) {
548 snprintf(shm_name
, sizeof(shm_name
), "/%s_trace.%d", opts
->name
, opts
->shm_id
);
550 snprintf(shm_name
, sizeof(shm_name
), "/%s_trace.pid%d", opts
->name
, (int)getpid());
553 if (spdk_trace_init(shm_name
, opts
->num_entries
) != 0) {
557 if (opts
->tpoint_group_mask
!= NULL
) {
559 tpoint_group_mask
= strtoull(opts
->tpoint_group_mask
, &end
, 16);
560 if (*end
!= '\0' || errno
) {
561 SPDK_ERRLOG("invalid tpoint mask %s\n", opts
->tpoint_group_mask
);
563 SPDK_NOTICELOG("Tracepoint Group Mask %s specified.\n", opts
->tpoint_group_mask
);
564 SPDK_NOTICELOG("Use 'spdk_trace -s %s %s %d' to capture a snapshot of events at runtime.\n",
566 opts
->shm_id
>= 0 ? "-i" : "-p",
567 opts
->shm_id
>= 0 ? opts
->shm_id
: getpid());
568 #if defined(__linux__)
569 SPDK_NOTICELOG("Or copy /dev/shm%s for offline analysis/debug.\n", shm_name
);
571 spdk_trace_set_tpoint_group_mask(tpoint_group_mask
);
579 bootstrap_fn(void *arg1
)
581 if (g_spdk_app
.json_config_file
) {
582 g_delay_subsystem_init
= false;
583 spdk_app_json_config_load(g_spdk_app
.json_config_file
, g_spdk_app
.rpc_addr
, app_start_rpc
,
584 NULL
, !g_spdk_app
.json_config_ignore_errors
);
586 if (!g_delay_subsystem_init
) {
587 spdk_subsystem_init(app_start_rpc
, NULL
);
589 spdk_rpc_initialize(g_spdk_app
.rpc_addr
);
595 spdk_app_start(struct spdk_app_opts
*opts
, spdk_msg_fn start_fn
,
598 struct spdk_conf
*config
= NULL
;
601 struct spdk_cpuset tmp_cpumask
= {};
602 static bool g_env_was_setup
= false;
605 SPDK_ERRLOG("opts should not be NULL\n");
610 SPDK_ERRLOG("start_fn should not be NULL\n");
614 tty
= ttyname(STDERR_FILENO
);
615 if (opts
->print_level
> SPDK_LOG_WARN
&&
616 isatty(STDERR_FILENO
) &&
618 !strncmp(tty
, "/dev/tty", strlen("/dev/tty"))) {
619 printf("Warning: printing stderr to console terminal without -q option specified.\n");
620 printf("Suggest using --silence-noticelog to disable logging to stderr and\n");
621 printf("monitor syslog, or redirect stderr to a file.\n");
622 printf("(Delaying for 10 seconds...)\n");
626 spdk_log_set_print_level(opts
->print_level
);
628 #ifndef SPDK_NO_RLIMIT
629 if (opts
->enable_coredump
) {
630 struct rlimit core_limits
;
632 core_limits
.rlim_cur
= core_limits
.rlim_max
= SPDK_APP_DEFAULT_CORE_LIMIT
;
633 setrlimit(RLIMIT_CORE
, &core_limits
);
637 config
= app_setup_conf(opts
->config_file
);
638 if (config
== NULL
) {
642 if (app_read_config_file_global_params(opts
) < 0) {
643 spdk_conf_free(config
);
647 memset(&g_spdk_app
, 0, sizeof(g_spdk_app
));
648 g_spdk_app
.config
= config
;
649 g_spdk_app
.json_config_file
= opts
->json_config_file
;
650 g_spdk_app
.json_config_ignore_errors
= opts
->json_config_ignore_errors
;
651 g_spdk_app
.rpc_addr
= opts
->rpc_addr
;
652 g_spdk_app
.shm_id
= opts
->shm_id
;
653 g_spdk_app
.shutdown_cb
= opts
->shutdown_cb
;
656 spdk_log_set_level(SPDK_APP_DEFAULT_LOG_LEVEL
);
658 /* Pass NULL to app_setup_env if SPDK app has been set up, in order to
659 * indicate that this is a reinitialization.
661 if (app_setup_env(g_env_was_setup
? NULL
: opts
) < 0) {
665 spdk_log_open(opts
->log
);
666 SPDK_NOTICELOG("Total cores available: %d\n", spdk_env_get_core_count());
669 * If mask not specified on command line or in configuration file,
670 * reactor_mask will be 0x1 which will enable core 0 to run one
673 if ((rc
= spdk_reactors_init()) != 0) {
674 SPDK_ERRLOG("Reactor Initilization failed: rc = %d\n", rc
);
678 spdk_cpuset_set_cpu(&tmp_cpumask
, spdk_env_get_current_core(), true);
680 /* Now that the reactors have been initialized, we can create an
681 * initialization thread. */
682 g_app_thread
= spdk_thread_create("app_thread", &tmp_cpumask
);
684 SPDK_ERRLOG("Unable to create an spdk_thread for initialization\n");
689 * Note the call to app_setup_trace() is located here
690 * ahead of app_setup_signal_handlers().
691 * That's because there is not an easy/direct clean
692 * way of unwinding alloc'd resources that can occur
693 * in app_setup_signal_handlers().
695 if (app_setup_trace(opts
) != 0) {
699 if ((rc
= app_setup_signal_handlers(opts
)) != 0) {
703 g_delay_subsystem_init
= opts
->delay_subsystem_init
;
704 g_start_fn
= start_fn
;
707 spdk_thread_send_msg(g_app_thread
, bootstrap_fn
, NULL
);
709 /* This blocks until spdk_app_stop is called */
710 spdk_reactors_start();
712 g_env_was_setup
= true;
714 return g_spdk_app
.rc
;
720 spdk_trace_cleanup();
721 spdk_reactors_fini();
723 spdk_conf_free(g_spdk_app
.config
);
731 spdk_subsystem_fini(spdk_reactors_stop
, NULL
);
735 spdk_app_stop(int rc
)
738 SPDK_WARNLOG("spdk_app_stop'd on non-zero\n");
742 * We want to run spdk_subsystem_fini() from the same thread where spdk_subsystem_init()
745 spdk_thread_send_msg(g_app_thread
, app_stop
, NULL
);
749 usage(void (*app_usage
)(void))
751 printf("%s [options]\n", g_executable_name
);
752 printf("options:\n");
753 printf(" -c, --config <config> config file (default %s)\n",
754 g_default_opts
.config_file
!= NULL
? g_default_opts
.config_file
: "none");
755 printf(" --json <config> JSON config file (default %s)\n",
756 g_default_opts
.json_config_file
!= NULL
? g_default_opts
.json_config_file
: "none");
757 printf(" --json-ignore-init-errors\n");
758 printf(" don't exit on invalid config entry\n");
759 printf(" -d, --limit-coredump do not set max coredump size to RLIM_INFINITY\n");
760 printf(" -g, --single-file-segments\n");
761 printf(" force creating just one hugetlbfs file\n");
762 printf(" -h, --help show this usage\n");
763 printf(" -i, --shm-id <id> shared memory ID (optional)\n");
764 printf(" -m, --cpumask <mask> core mask for DPDK\n");
765 printf(" -n, --mem-channels <num> channel number of memory channels used for DPDK\n");
766 printf(" -p, --master-core <id> master (primary) core for DPDK\n");
767 printf(" -r, --rpc-socket <path> RPC listen address (default %s)\n", SPDK_DEFAULT_RPC_ADDR
);
768 printf(" -s, --mem-size <size> memory size in MB for DPDK (default: ");
770 if (g_default_opts
.mem_size
<= 0) {
771 printf("all hugepage memory)\n");
775 printf("%dMB)\n", g_default_opts
.mem_size
>= 0 ? g_default_opts
.mem_size
: 0);
777 printf(" --silence-noticelog disable notice level logging to stderr\n");
778 printf(" -u, --no-pci disable PCI access\n");
779 printf(" --wait-for-rpc wait for RPCs to initialize subsystems\n");
780 printf(" --max-delay <num> maximum reactor delay (in microseconds)\n");
781 printf(" -B, --pci-blacklist <bdf>\n");
782 printf(" pci addr to blacklist (can be used more than once)\n");
783 printf(" -R, --huge-unlink unlink huge files after initialization\n");
784 printf(" -v, --version print SPDK version\n");
785 printf(" -W, --pci-whitelist <bdf>\n");
786 printf(" pci addr to whitelist (-B and -W cannot be used at the same time)\n");
787 printf(" --huge-dir <path> use a specific hugetlbfs mount to reserve memory from\n");
788 printf(" --iova-mode <pa/va> set IOVA mode ('pa' for IOVA_PA and 'va' for IOVA_VA)\n");
789 printf(" --base-virtaddr <addr> the base virtual address for DPDK (default: 0x200000000000)\n");
790 printf(" --num-trace-entries <num> number of trace entries for each core, must be power of 2. (default %d)\n",
791 SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES
);
792 spdk_log_usage(stdout
, "-L");
793 spdk_trace_mask_usage(stdout
, "-e");
799 spdk_app_parse_args_rvals_t
800 spdk_app_parse_args(int argc
, char **argv
, struct spdk_app_opts
*opts
,
801 const char *app_getopt_str
, struct option
*app_long_opts
,
802 int (*app_parse
)(int ch
, char *arg
),
803 void (*app_usage
)(void))
805 int ch
, rc
, opt_idx
, global_long_opts_len
, app_long_opts_len
;
806 struct option
*cmdline_options
;
807 char *cmdline_short_opts
= NULL
;
808 enum spdk_app_parse_args_rvals retval
= SPDK_APP_PARSE_ARGS_FAIL
;
811 memcpy(&g_default_opts
, opts
, sizeof(g_default_opts
));
813 if (opts
->config_file
&& access(opts
->config_file
, R_OK
) != 0) {
814 SPDK_WARNLOG("Can't read legacy configuration file '%s'\n", opts
->config_file
);
815 opts
->config_file
= NULL
;
818 if (opts
->json_config_file
&& access(opts
->json_config_file
, R_OK
) != 0) {
819 SPDK_WARNLOG("Can't read JSON configuration file '%s'\n", opts
->json_config_file
);
820 opts
->json_config_file
= NULL
;
823 if (app_long_opts
== NULL
) {
824 app_long_opts_len
= 0;
826 for (app_long_opts_len
= 0;
827 app_long_opts
[app_long_opts_len
].name
!= NULL
;
828 app_long_opts_len
++);
831 global_long_opts_len
= SPDK_COUNTOF(g_cmdline_options
);
833 cmdline_options
= calloc(global_long_opts_len
+ app_long_opts_len
+ 1, sizeof(*cmdline_options
));
834 if (!cmdline_options
) {
835 SPDK_ERRLOG("Out of memory\n");
836 return SPDK_APP_PARSE_ARGS_FAIL
;
839 memcpy(&cmdline_options
[0], g_cmdline_options
, sizeof(g_cmdline_options
));
841 memcpy(&cmdline_options
[global_long_opts_len
], app_long_opts
,
842 app_long_opts_len
* sizeof(*app_long_opts
));
845 if (app_getopt_str
!= NULL
) {
846 ch
= app_opts_validate(app_getopt_str
);
848 SPDK_ERRLOG("Duplicated option '%c' between the generic and application specific spdk opts.\n",
854 cmdline_short_opts
= spdk_sprintf_alloc("%s%s", app_getopt_str
, SPDK_APP_GETOPT_STRING
);
855 if (!cmdline_short_opts
) {
856 SPDK_ERRLOG("Out of memory\n");
860 g_executable_name
= argv
[0];
862 while ((ch
= getopt_long(argc
, argv
, cmdline_short_opts
, cmdline_options
, &opt_idx
)) != -1) {
864 case CONFIG_FILE_OPT_IDX
:
865 opts
->config_file
= optarg
;
867 case JSON_CONFIG_OPT_IDX
:
868 opts
->json_config_file
= optarg
;
870 case JSON_CONFIG_IGNORE_INIT_ERRORS_IDX
:
871 opts
->json_config_ignore_errors
= true;
873 case LIMIT_COREDUMP_OPT_IDX
:
874 opts
->enable_coredump
= false;
876 case TPOINT_GROUP_MASK_OPT_IDX
:
877 opts
->tpoint_group_mask
= optarg
;
879 case SINGLE_FILE_SEGMENTS_OPT_IDX
:
880 opts
->hugepage_single_segments
= true;
884 retval
= SPDK_APP_PARSE_ARGS_HELP
;
887 opts
->shm_id
= spdk_strtol(optarg
, 0);
888 if (opts
->shm_id
< 0) {
889 SPDK_ERRLOG("Invalid shared memory ID %s\n", optarg
);
893 case CPUMASK_OPT_IDX
:
894 opts
->reactor_mask
= optarg
;
896 case MEM_CHANNELS_OPT_IDX
:
897 opts
->mem_channel
= spdk_strtol(optarg
, 0);
898 if (opts
->mem_channel
< 0) {
899 SPDK_ERRLOG("Invalid memory channel %s\n", optarg
);
903 case MASTER_CORE_OPT_IDX
:
904 opts
->master_core
= spdk_strtol(optarg
, 0);
905 if (opts
->master_core
< 0) {
906 SPDK_ERRLOG("Invalid master core %s\n", optarg
);
910 case SILENCE_NOTICELOG_OPT_IDX
:
911 opts
->print_level
= SPDK_LOG_WARN
;
913 case RPC_SOCKET_OPT_IDX
:
914 opts
->rpc_addr
= optarg
;
916 case MEM_SIZE_OPT_IDX
: {
917 uint64_t mem_size_mb
;
918 bool mem_size_has_prefix
;
920 rc
= spdk_parse_capacity(optarg
, &mem_size_mb
, &mem_size_has_prefix
);
922 SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg
);
927 if (mem_size_has_prefix
) {
928 /* the mem size is in MB by default, so if a prefix was
929 * specified, we need to manually convert to MB.
931 mem_size_mb
/= 1024 * 1024;
934 if (mem_size_mb
> INT_MAX
) {
935 SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg
);
940 opts
->mem_size
= (int) mem_size_mb
;
946 case WAIT_FOR_RPC_OPT_IDX
:
947 opts
->delay_subsystem_init
= true;
949 case PCI_BLACKLIST_OPT_IDX
:
950 if (opts
->pci_whitelist
) {
951 free(opts
->pci_whitelist
);
952 opts
->pci_whitelist
= NULL
;
953 SPDK_ERRLOG("-B and -W cannot be used at the same time\n");
958 rc
= app_opts_add_pci_addr(opts
, &opts
->pci_blacklist
, optarg
);
960 free(opts
->pci_blacklist
);
961 opts
->pci_blacklist
= NULL
;
965 case LOGFLAG_OPT_IDX
:
967 SPDK_ERRLOG("%s must be configured with --enable-debug for -L flag\n",
972 rc
= spdk_log_set_flag(optarg
);
974 SPDK_ERRLOG("unknown flag\n");
978 opts
->print_level
= SPDK_LOG_DEBUG
;
981 case HUGE_UNLINK_OPT_IDX
:
982 opts
->unlink_hugepage
= true;
984 case PCI_WHITELIST_OPT_IDX
:
985 if (opts
->pci_blacklist
) {
986 free(opts
->pci_blacklist
);
987 opts
->pci_blacklist
= NULL
;
988 SPDK_ERRLOG("-B and -W cannot be used at the same time\n");
993 rc
= app_opts_add_pci_addr(opts
, &opts
->pci_whitelist
, optarg
);
995 free(opts
->pci_whitelist
);
996 opts
->pci_whitelist
= NULL
;
1000 case BASE_VIRTADDR_OPT_IDX
:
1001 tmp
= spdk_strtoll(optarg
, 0);
1003 SPDK_ERRLOG("Invalid base-virtaddr %s\n", optarg
);
1007 opts
->base_virtaddr
= (uint64_t)tmp
;
1009 case HUGE_DIR_OPT_IDX
:
1010 opts
->hugedir
= optarg
;
1012 case IOVA_MODE_OPT_IDX
:
1013 opts
->iova_mode
= optarg
;
1015 case NUM_TRACE_ENTRIES_OPT_IDX
:
1016 tmp
= spdk_strtoll(optarg
, 0);
1018 SPDK_ERRLOG("Invalid num-trace-entries %s\n", optarg
);
1022 opts
->num_entries
= (uint64_t)tmp
;
1023 if (opts
->num_entries
& (opts
->num_entries
- 1)) {
1024 SPDK_ERRLOG("num-trace-entries must be power of 2\n");
1029 case MAX_REACTOR_DELAY_OPT_IDX
:
1030 SPDK_ERRLOG("Deprecation warning: The maximum allowed latency parameter is no longer supported.\n");
1032 case VERSION_OPT_IDX
:
1033 printf(SPDK_VERSION_STRING
"\n");
1034 retval
= SPDK_APP_PARSE_ARGS_HELP
;
1038 * In the event getopt() above detects an option
1039 * in argv that is NOT in the getopt_str,
1040 * getopt() will return a '?' indicating failure.
1045 rc
= app_parse(ch
, optarg
);
1047 SPDK_ERRLOG("Parsing application specific arguments failed: %d\n", rc
);
1053 if (opts
->config_file
&& opts
->json_config_file
) {
1054 SPDK_ERRLOG("ERROR: Legacy config and JSON config can't be used together.\n");
1058 if (opts
->json_config_file
&& opts
->delay_subsystem_init
) {
1059 SPDK_ERRLOG("ERROR: JSON configuration file can't be used together with --wait-for-rpc.\n");
1063 /* TBD: Replace warning by failure when RPCs for startup are prepared. */
1064 if (opts
->config_file
&& opts
->delay_subsystem_init
) {
1066 "WARNING: --wait-for-rpc and config file are used at the same time. "
1067 "- Please be careful one options might overwrite others.\n");
1070 retval
= SPDK_APP_PARSE_ARGS_SUCCESS
;
1072 if (retval
!= SPDK_APP_PARSE_ARGS_SUCCESS
) {
1073 free(opts
->pci_blacklist
);
1074 opts
->pci_blacklist
= NULL
;
1075 free(opts
->pci_whitelist
);
1076 opts
->pci_whitelist
= NULL
;
1078 free(cmdline_short_opts
);
1079 free(cmdline_options
);
1084 spdk_app_usage(void)
1086 if (g_executable_name
== NULL
) {
1087 SPDK_ERRLOG("%s not valid before calling spdk_app_parse_args()\n", __func__
);
1095 rpc_framework_start_init_cpl(int rc
, void *arg1
)
1097 struct spdk_jsonrpc_request
*request
= arg1
;
1098 struct spdk_json_write_ctx
*w
;
1100 assert(spdk_get_thread() == g_app_thread
);
1103 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
,
1104 "framework_initialization failed");
1108 spdk_rpc_set_state(SPDK_RPC_RUNTIME
);
1109 app_start_application();
1111 w
= spdk_jsonrpc_begin_result(request
);
1112 spdk_json_write_bool(w
, true);
1113 spdk_jsonrpc_end_result(request
, w
);
1117 rpc_framework_start_init(struct spdk_jsonrpc_request
*request
,
1118 const struct spdk_json_val
*params
)
1120 if (params
!= NULL
) {
1121 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
1122 "framework_start_init requires no parameters");
1126 spdk_subsystem_init(rpc_framework_start_init_cpl
, request
);
1128 SPDK_RPC_REGISTER("framework_start_init", rpc_framework_start_init
, SPDK_RPC_STARTUP
)
1129 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_start_init
, start_subsystem_init
)
1131 struct subsystem_init_poller_ctx
{
1132 struct spdk_poller
*init_poller
;
1133 struct spdk_jsonrpc_request
*request
;
1137 rpc_subsystem_init_poller_ctx(void *ctx
)
1139 struct spdk_json_write_ctx
*w
;
1140 struct subsystem_init_poller_ctx
*poller_ctx
= ctx
;
1142 if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME
) {
1143 w
= spdk_jsonrpc_begin_result(poller_ctx
->request
);
1144 spdk_json_write_bool(w
, true);
1145 spdk_jsonrpc_end_result(poller_ctx
->request
, w
);
1146 spdk_poller_unregister(&poller_ctx
->init_poller
);
1150 return SPDK_POLLER_BUSY
;
1154 rpc_framework_wait_init(struct spdk_jsonrpc_request
*request
,
1155 const struct spdk_json_val
*params
)
1157 struct spdk_json_write_ctx
*w
;
1158 struct subsystem_init_poller_ctx
*ctx
;
1160 if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME
) {
1161 w
= spdk_jsonrpc_begin_result(request
);
1162 spdk_json_write_bool(w
, true);
1163 spdk_jsonrpc_end_result(request
, w
);
1165 ctx
= malloc(sizeof(struct subsystem_init_poller_ctx
));
1167 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
,
1168 "Unable to allocate memory for the request context\n");
1171 ctx
->request
= request
;
1172 ctx
->init_poller
= SPDK_POLLER_REGISTER(rpc_subsystem_init_poller_ctx
, ctx
, 0);
1175 SPDK_RPC_REGISTER("framework_wait_init", rpc_framework_wait_init
,
1176 SPDK_RPC_STARTUP
| SPDK_RPC_RUNTIME
)
1177 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_wait_init
, wait_subsystem_init
)