xref: /spdk/lib/event/app.c (revision 0fd542bcf43352bf25e48e6f131fe30f26f7c1b8)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2016 Intel Corporation. All rights reserved.
3  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4  *   Copyright (c) 2021, 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 #include "spdk/version.h"
9 
10 #include "spdk_internal/event.h"
11 
12 #include "spdk/assert.h"
13 #include "spdk/env.h"
14 #include "spdk/init.h"
15 #include "spdk/log.h"
16 #include "spdk/thread.h"
17 #include "spdk/trace.h"
18 #include "spdk/string.h"
19 #include "spdk/scheduler.h"
20 #include "spdk/rpc.h"
21 #include "spdk/util.h"
22 #include "spdk/file.h"
23 
24 #define SPDK_APP_DEFAULT_LOG_LEVEL		SPDK_LOG_NOTICE
25 #define SPDK_APP_DEFAULT_LOG_PRINT_LEVEL	SPDK_LOG_INFO
26 #define SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES	SPDK_DEFAULT_NUM_TRACE_ENTRIES
27 
28 #define SPDK_APP_DPDK_DEFAULT_MEM_SIZE		-1
29 #define SPDK_APP_DPDK_DEFAULT_MAIN_CORE		-1
30 #define SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL	-1
31 #define SPDK_APP_DPDK_DEFAULT_CORE_MASK		"0x1"
32 #define SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR	0x200000000000
33 #define SPDK_APP_DEFAULT_CORE_LIMIT		0x140000000 /* 5 GiB */
34 
35 /* For core counts <= 63, the message memory pool size is set to
36  * SPDK_DEFAULT_MSG_MEMPOOL_SIZE.
37  * For core counts > 63, the message memory pool size is dependend on
38  * number of cores. Per core, it is calculated as SPDK_MSG_MEMPOOL_CACHE_SIZE
39  * multiplied by factor of 4 to have space for multiple spdk threads running
40  * on single core (e.g  iscsi + nvmf + vhost ). */
41 #define SPDK_APP_PER_CORE_MSG_MEMPOOL_SIZE	(4 * SPDK_MSG_MEMPOOL_CACHE_SIZE)
42 
43 #define MAX_CPU_CORES				128
44 
45 struct spdk_app {
46 	void				*json_data;
47 	size_t				json_data_size;
48 	bool				json_config_ignore_errors;
49 	bool				stopped;
50 	const char			*rpc_addr;
51 	const char			**rpc_allowlist;
52 	FILE				*rpc_log_file;
53 	enum spdk_log_level		rpc_log_level;
54 	int				shm_id;
55 	spdk_app_shutdown_cb		shutdown_cb;
56 	int				rc;
57 };
58 
59 static struct spdk_app g_spdk_app;
60 static spdk_msg_fn g_start_fn = NULL;
61 static void *g_start_arg = NULL;
62 static bool g_delay_subsystem_init = false;
63 static bool g_shutdown_sig_received = false;
64 static char *g_executable_name;
65 static struct spdk_app_opts g_default_opts;
66 static bool g_disable_cpumask_locks = false;
67 
68 static int g_core_locks[MAX_CPU_CORES];
69 
70 int
71 spdk_app_get_shm_id(void)
72 {
73 	return g_spdk_app.shm_id;
74 }
75 
76 /* append one empty option to indicate the end of the array */
77 static const struct option g_cmdline_options[] = {
78 #define CONFIG_FILE_OPT_IDX	'c'
79 	{"config",			required_argument,	NULL, CONFIG_FILE_OPT_IDX},
80 #define LIMIT_COREDUMP_OPT_IDX 'd'
81 	{"limit-coredump",		no_argument,		NULL, LIMIT_COREDUMP_OPT_IDX},
82 #define TPOINT_GROUP_OPT_IDX 'e'
83 	{"tpoint-group",		required_argument,	NULL, TPOINT_GROUP_OPT_IDX},
84 #define SINGLE_FILE_SEGMENTS_OPT_IDX 'g'
85 	{"single-file-segments",	no_argument,		NULL, SINGLE_FILE_SEGMENTS_OPT_IDX},
86 #define HELP_OPT_IDX		'h'
87 	{"help",			no_argument,		NULL, HELP_OPT_IDX},
88 #define SHM_ID_OPT_IDX		'i'
89 	{"shm-id",			required_argument,	NULL, SHM_ID_OPT_IDX},
90 #define CPUMASK_OPT_IDX		'm'
91 	{"cpumask",			required_argument,	NULL, CPUMASK_OPT_IDX},
92 #define MEM_CHANNELS_OPT_IDX	'n'
93 	{"mem-channels",		required_argument,	NULL, MEM_CHANNELS_OPT_IDX},
94 #define MAIN_CORE_OPT_IDX	'p'
95 	{"main-core",			required_argument,	NULL, MAIN_CORE_OPT_IDX},
96 #define RPC_SOCKET_OPT_IDX	'r'
97 	{"rpc-socket",			required_argument,	NULL, RPC_SOCKET_OPT_IDX},
98 #define MEM_SIZE_OPT_IDX	's'
99 	{"mem-size",			required_argument,	NULL, MEM_SIZE_OPT_IDX},
100 #define NO_PCI_OPT_IDX		'u'
101 	{"no-pci",			no_argument,		NULL, NO_PCI_OPT_IDX},
102 #define VERSION_OPT_IDX		'v'
103 	{"version",			no_argument,		NULL, VERSION_OPT_IDX},
104 #define PCI_BLOCKED_OPT_IDX	'B'
105 	{"pci-blocked",			required_argument,	NULL, PCI_BLOCKED_OPT_IDX},
106 #define LOGFLAG_OPT_IDX		'L'
107 	{"logflag",			required_argument,	NULL, LOGFLAG_OPT_IDX},
108 #define HUGE_UNLINK_OPT_IDX	'R'
109 	{"huge-unlink",			no_argument,		NULL, HUGE_UNLINK_OPT_IDX},
110 #define PCI_ALLOWED_OPT_IDX	'A'
111 	{"pci-allowed",			required_argument,	NULL, PCI_ALLOWED_OPT_IDX},
112 #define INTERRUPT_MODE_OPT_IDX 256
113 	{"interrupt-mode",		no_argument,		NULL, INTERRUPT_MODE_OPT_IDX},
114 #define SILENCE_NOTICELOG_OPT_IDX 257
115 	{"silence-noticelog",		no_argument,		NULL, SILENCE_NOTICELOG_OPT_IDX},
116 #define WAIT_FOR_RPC_OPT_IDX	258
117 	{"wait-for-rpc",		no_argument,		NULL, WAIT_FOR_RPC_OPT_IDX},
118 #define HUGE_DIR_OPT_IDX	259
119 	{"huge-dir",			required_argument,	NULL, HUGE_DIR_OPT_IDX},
120 #define NUM_TRACE_ENTRIES_OPT_IDX	260
121 	{"num-trace-entries",		required_argument,	NULL, NUM_TRACE_ENTRIES_OPT_IDX},
122 #define JSON_CONFIG_OPT_IDX		262
123 	{"json",			required_argument,	NULL, JSON_CONFIG_OPT_IDX},
124 #define JSON_CONFIG_IGNORE_INIT_ERRORS_IDX	263
125 	{"json-ignore-init-errors",	no_argument,		NULL, JSON_CONFIG_IGNORE_INIT_ERRORS_IDX},
126 #define IOVA_MODE_OPT_IDX	264
127 	{"iova-mode",			required_argument,	NULL, IOVA_MODE_OPT_IDX},
128 #define BASE_VIRTADDR_OPT_IDX	265
129 	{"base-virtaddr",		required_argument,	NULL, BASE_VIRTADDR_OPT_IDX},
130 #define ENV_CONTEXT_OPT_IDX	266
131 	{"env-context",			required_argument,	NULL, ENV_CONTEXT_OPT_IDX},
132 #define DISABLE_CPUMASK_LOCKS_OPT_IDX	267
133 	{"disable-cpumask-locks",	no_argument,		NULL, DISABLE_CPUMASK_LOCKS_OPT_IDX},
134 #define RPCS_ALLOWED_OPT_IDX	268
135 	{"rpcs-allowed",		required_argument,	NULL, RPCS_ALLOWED_OPT_IDX},
136 #define ENV_VF_TOKEN_OPT_IDX 269
137 	{"vfio-vf-token",		required_argument,	NULL, ENV_VF_TOKEN_OPT_IDX},
138 #define MSG_MEMPOOL_SIZE_OPT_IDX 270
139 	{"msg-mempool-size",		required_argument,	NULL, MSG_MEMPOOL_SIZE_OPT_IDX},
140 #define LCORES_OPT_IDX	271
141 	{"lcores",			required_argument,	NULL, LCORES_OPT_IDX},
142 #define NO_HUGE_OPT_IDX	272
143 	{"no-huge",			no_argument,		NULL, NO_HUGE_OPT_IDX},
144 #define NO_RPC_SERVER_OPT_IDX	273
145 	{"no-rpc-server",		no_argument,		NULL, NO_RPC_SERVER_OPT_IDX},
146 };
147 
148 static void
149 app_start_shutdown(void *ctx)
150 {
151 	if (g_spdk_app.shutdown_cb) {
152 		g_spdk_app.shutdown_cb();
153 		g_spdk_app.shutdown_cb = NULL;
154 	} else {
155 		spdk_app_stop(0);
156 	}
157 }
158 
159 void
160 spdk_app_start_shutdown(void)
161 {
162 	spdk_thread_send_critical_msg(spdk_thread_get_app_thread(), app_start_shutdown);
163 }
164 
165 static void
166 __shutdown_signal(int signo)
167 {
168 	if (!g_shutdown_sig_received) {
169 		g_shutdown_sig_received = true;
170 		spdk_app_start_shutdown();
171 	}
172 }
173 
174 static int
175 app_opts_validate(const char *app_opts)
176 {
177 	int i = 0, j;
178 
179 	for (i = 0; app_opts[i] != '\0'; i++) {
180 		/* ignore getopt control characters */
181 		if (app_opts[i] == ':' || app_opts[i] == '+' || app_opts[i] == '-') {
182 			continue;
183 		}
184 
185 		for (j = 0; SPDK_APP_GETOPT_STRING[j] != '\0'; j++) {
186 			if (app_opts[i] == SPDK_APP_GETOPT_STRING[j]) {
187 				return app_opts[i];
188 			}
189 		}
190 	}
191 	return 0;
192 }
193 
194 static void
195 calculate_mempool_size(struct spdk_app_opts *opts,
196 		       struct spdk_app_opts *opts_user)
197 {
198 	uint32_t core_count = spdk_env_get_core_count();
199 
200 	if (!opts_user->msg_mempool_size) {
201 		/* The user didn't specify msg_mempool_size, so let's calculate it.
202 		   Set the default (SPDK_DEFAULT_MSG_MEMPOOL_SIZE) if less than
203 		   64 cores, and use 4k per core otherwise */
204 		opts->msg_mempool_size = spdk_max(SPDK_DEFAULT_MSG_MEMPOOL_SIZE,
205 						  core_count * SPDK_APP_PER_CORE_MSG_MEMPOOL_SIZE);
206 	} else {
207 		opts->msg_mempool_size = opts_user->msg_mempool_size;
208 	}
209 }
210 
211 void
212 spdk_app_opts_init(struct spdk_app_opts *opts, size_t opts_size)
213 {
214 	if (!opts) {
215 		SPDK_ERRLOG("opts should not be NULL\n");
216 		return;
217 	}
218 
219 	if (!opts_size) {
220 		SPDK_ERRLOG("opts_size should not be zero value\n");
221 		return;
222 	}
223 
224 	memset(opts, 0, opts_size);
225 	opts->opts_size = opts_size;
226 
227 #define SET_FIELD(field, value) \
228 	if (offsetof(struct spdk_app_opts, field) + sizeof(opts->field) <= opts_size) { \
229 		opts->field = value; \
230 	} \
231 
232 	SET_FIELD(enable_coredump, true);
233 	SET_FIELD(shm_id, -1);
234 	SET_FIELD(mem_size, SPDK_APP_DPDK_DEFAULT_MEM_SIZE);
235 	SET_FIELD(main_core, SPDK_APP_DPDK_DEFAULT_MAIN_CORE);
236 	SET_FIELD(mem_channel, SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL);
237 	SET_FIELD(base_virtaddr, SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR);
238 	SET_FIELD(print_level, SPDK_APP_DEFAULT_LOG_PRINT_LEVEL);
239 	SET_FIELD(rpc_addr, SPDK_DEFAULT_RPC_ADDR);
240 	SET_FIELD(num_entries, SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES);
241 	SET_FIELD(delay_subsystem_init, false);
242 	SET_FIELD(disable_signal_handlers, false);
243 	SET_FIELD(interrupt_mode, false);
244 	/* Don't set msg_mempool_size here, it is set or calculated later */
245 	SET_FIELD(rpc_allowlist, NULL);
246 	SET_FIELD(rpc_log_file, NULL);
247 	SET_FIELD(rpc_log_level, SPDK_LOG_DISABLED);
248 #undef SET_FIELD
249 }
250 
251 static int
252 app_setup_signal_handlers(struct spdk_app_opts *opts)
253 {
254 	struct sigaction	sigact;
255 	sigset_t		sigmask;
256 	int			rc;
257 
258 	sigemptyset(&sigmask);
259 	memset(&sigact, 0, sizeof(sigact));
260 	sigemptyset(&sigact.sa_mask);
261 
262 	sigact.sa_handler = SIG_IGN;
263 	rc = sigaction(SIGPIPE, &sigact, NULL);
264 	if (rc < 0) {
265 		SPDK_ERRLOG("sigaction(SIGPIPE) failed\n");
266 		return rc;
267 	}
268 
269 	/* Install the same handler for SIGINT and SIGTERM */
270 	g_shutdown_sig_received = false;
271 	sigact.sa_handler = __shutdown_signal;
272 	rc = sigaction(SIGINT, &sigact, NULL);
273 	if (rc < 0) {
274 		SPDK_ERRLOG("sigaction(SIGINT) failed\n");
275 		return rc;
276 	}
277 	sigaddset(&sigmask, SIGINT);
278 
279 	rc = sigaction(SIGTERM, &sigact, NULL);
280 	if (rc < 0) {
281 		SPDK_ERRLOG("sigaction(SIGTERM) failed\n");
282 		return rc;
283 	}
284 	sigaddset(&sigmask, SIGTERM);
285 
286 	pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL);
287 
288 	return 0;
289 }
290 
291 static void
292 app_start_application(int rc, void *arg1)
293 {
294 	assert(spdk_thread_is_app_thread(NULL));
295 
296 	if (rc) {
297 		SPDK_ERRLOG("Failed to load subsystems for RUNTIME state with code: %d\n", rc);
298 		spdk_app_stop(rc);
299 		return;
300 	}
301 
302 	if (g_spdk_app.rpc_addr) {
303 		spdk_rpc_server_resume(g_spdk_app.rpc_addr);
304 	}
305 
306 	g_start_fn(g_start_arg);
307 }
308 
309 static void
310 app_subsystem_init_done(int rc, void *arg1)
311 {
312 	if (rc) {
313 		SPDK_ERRLOG("Subsystem initialization failed with code: %d\n", rc);
314 		spdk_app_stop(rc);
315 		return;
316 	}
317 
318 	spdk_rpc_set_allowlist(g_spdk_app.rpc_allowlist);
319 	spdk_rpc_set_state(SPDK_RPC_RUNTIME);
320 
321 	if (g_spdk_app.json_data) {
322 		/* Load SPDK_RPC_RUNTIME RPCs from config file */
323 		assert(spdk_rpc_get_state() == SPDK_RPC_RUNTIME);
324 		spdk_subsystem_load_config(g_spdk_app.json_data, g_spdk_app.json_data_size,
325 					   app_start_application, NULL,
326 					   !g_spdk_app.json_config_ignore_errors);
327 	} else {
328 		app_start_application(0, NULL);
329 	}
330 }
331 
332 static void
333 app_do_spdk_subsystem_init(int rc, void *arg1)
334 {
335 	struct spdk_rpc_opts opts;
336 
337 	if (rc) {
338 		spdk_app_stop(rc);
339 		return;
340 	}
341 
342 	if (g_spdk_app.rpc_addr) {
343 		opts.size = SPDK_SIZEOF(&opts, log_level);
344 		opts.log_file = g_spdk_app.rpc_log_file;
345 		opts.log_level = g_spdk_app.rpc_log_level;
346 
347 		rc = spdk_rpc_initialize(g_spdk_app.rpc_addr, &opts);
348 		if (rc) {
349 			spdk_app_stop(rc);
350 			return;
351 		}
352 		if (g_delay_subsystem_init) {
353 			return;
354 		}
355 		spdk_rpc_server_pause(g_spdk_app.rpc_addr);
356 	} else {
357 		SPDK_DEBUGLOG(app_rpc, "RPC server not started\n");
358 	}
359 	spdk_subsystem_init(app_subsystem_init_done, NULL);
360 }
361 
362 static int
363 app_opts_add_pci_addr(struct spdk_app_opts *opts, struct spdk_pci_addr **list, char *bdf)
364 {
365 	struct spdk_pci_addr *tmp = *list;
366 	size_t i = opts->num_pci_addr;
367 
368 	tmp = realloc(tmp, sizeof(*tmp) * (i + 1));
369 	if (tmp == NULL) {
370 		SPDK_ERRLOG("realloc error\n");
371 		return -ENOMEM;
372 	}
373 
374 	*list = tmp;
375 	if (spdk_pci_addr_parse(*list + i, bdf) < 0) {
376 		SPDK_ERRLOG("Invalid address %s\n", bdf);
377 		return -EINVAL;
378 	}
379 
380 	opts->num_pci_addr++;
381 	return 0;
382 }
383 
384 static int
385 app_setup_env(struct spdk_app_opts *opts)
386 {
387 	struct spdk_env_opts env_opts = {};
388 	int rc;
389 
390 	if (opts == NULL) {
391 		rc = spdk_env_init(NULL);
392 		if (rc != 0) {
393 			SPDK_ERRLOG("Unable to reinitialize SPDK env\n");
394 		}
395 
396 		return rc;
397 	}
398 
399 	spdk_env_opts_init(&env_opts);
400 
401 	env_opts.name = opts->name;
402 	env_opts.core_mask = opts->reactor_mask;
403 	env_opts.lcore_map = opts->lcore_map;
404 	env_opts.shm_id = opts->shm_id;
405 	env_opts.mem_channel = opts->mem_channel;
406 	env_opts.main_core = opts->main_core;
407 	env_opts.mem_size = opts->mem_size;
408 	env_opts.hugepage_single_segments = opts->hugepage_single_segments;
409 	env_opts.unlink_hugepage = opts->unlink_hugepage;
410 	env_opts.hugedir = opts->hugedir;
411 	env_opts.no_pci = opts->no_pci;
412 	env_opts.num_pci_addr = opts->num_pci_addr;
413 	env_opts.pci_blocked = opts->pci_blocked;
414 	env_opts.pci_allowed = opts->pci_allowed;
415 	env_opts.base_virtaddr = opts->base_virtaddr;
416 	env_opts.env_context = opts->env_context;
417 	env_opts.iova_mode = opts->iova_mode;
418 	env_opts.vf_token = opts->vf_token;
419 	env_opts.no_huge = opts->no_huge;
420 
421 	rc = spdk_env_init(&env_opts);
422 	free(env_opts.pci_blocked);
423 	free(env_opts.pci_allowed);
424 
425 	if (rc < 0) {
426 		SPDK_ERRLOG("Unable to initialize SPDK env\n");
427 	}
428 
429 	return rc;
430 }
431 
432 static int
433 app_setup_trace(struct spdk_app_opts *opts)
434 {
435 	char		shm_name[64];
436 	uint64_t	tpoint_group_mask, tpoint_mask = -1ULL;
437 	char		*end = NULL, *tpoint_group_mask_str, *tpoint_group_str = NULL;
438 	char		*tp_g_str, *tpoint_group, *tpoints;
439 	bool		error_found = false;
440 	uint64_t	group_id;
441 
442 	if (opts->shm_id >= 0) {
443 		snprintf(shm_name, sizeof(shm_name), "/%s%s%d", opts->name,
444 			 SPDK_TRACE_SHM_NAME_BASE, opts->shm_id);
445 	} else {
446 		snprintf(shm_name, sizeof(shm_name), "/%s%spid%d", opts->name,
447 			 SPDK_TRACE_SHM_NAME_BASE, (int)getpid());
448 	}
449 
450 	if (spdk_trace_init(shm_name, opts->num_entries, 0) != 0) {
451 		return -1;
452 	}
453 
454 	if (opts->tpoint_group_mask == NULL) {
455 		return 0;
456 	}
457 
458 	tpoint_group_mask_str = strdup(opts->tpoint_group_mask);
459 	if (tpoint_group_mask_str == NULL) {
460 		SPDK_ERRLOG("Unable to get string of tpoint group mask from opts.\n");
461 		return -1;
462 	}
463 	/* Save a pointer to the original value of the tpoint group mask string
464 	 * to free later, because spdk_strsepq() modifies given char*. */
465 	tp_g_str = tpoint_group_mask_str;
466 	while ((tpoint_group_str = spdk_strsepq(&tpoint_group_mask_str, ",")) != NULL) {
467 		if (strchr(tpoint_group_str, ':')) {
468 			/* Get the tpoint group mask */
469 			tpoint_group = spdk_strsepq(&tpoint_group_str, ":");
470 			/* Get the tpoint mask inside that group */
471 			tpoints = spdk_strsepq(&tpoint_group_str, ":");
472 
473 			errno = 0;
474 			tpoint_group_mask = strtoull(tpoint_group, &end, 16);
475 			if (*end != '\0' || errno) {
476 				tpoint_group_mask = spdk_trace_create_tpoint_group_mask(tpoint_group);
477 				if (tpoint_group_mask == 0) {
478 					error_found = true;
479 					break;
480 				}
481 			}
482 			/* Check if tpoint group mask has only one bit set.
483 			 * This is to avoid enabling individual tpoints in
484 			 * more than one tracepoint group at once. */
485 			if (!spdk_u64_is_pow2(tpoint_group_mask)) {
486 				SPDK_ERRLOG("Tpoint group mask: %s contains multiple tpoint groups.\n", tpoint_group);
487 				SPDK_ERRLOG("This is not supported, to prevent from activating tpoints by mistake.\n");
488 				error_found = true;
489 				break;
490 			}
491 
492 			errno = 0;
493 			tpoint_mask = strtoull(tpoints, &end, 16);
494 			if (*end != '\0' || errno) {
495 				error_found = true;
496 				break;
497 			}
498 		} else {
499 			errno = 0;
500 			tpoint_group_mask = strtoull(tpoint_group_str, &end, 16);
501 			if (*end != '\0' || errno) {
502 				tpoint_group_mask = spdk_trace_create_tpoint_group_mask(tpoint_group_str);
503 				if (tpoint_group_mask == 0) {
504 					error_found = true;
505 					break;
506 				}
507 			}
508 			tpoint_mask = -1ULL;
509 		}
510 
511 		for (group_id = 0; group_id < SPDK_TRACE_MAX_GROUP_ID; ++group_id) {
512 			if (tpoint_group_mask & (1 << group_id)) {
513 				spdk_trace_set_tpoints(group_id, tpoint_mask);
514 			}
515 		}
516 	}
517 
518 	if (error_found) {
519 		SPDK_ERRLOG("invalid tpoint mask %s\n", opts->tpoint_group_mask);
520 		free(tp_g_str);
521 		return -1;
522 	} else {
523 		SPDK_NOTICELOG("Tracepoint Group Mask %s specified.\n", opts->tpoint_group_mask);
524 		SPDK_NOTICELOG("Use 'spdk_trace -s %s %s %d' to capture a snapshot of events at runtime.\n",
525 			       opts->name,
526 			       opts->shm_id >= 0 ? "-i" : "-p",
527 			       opts->shm_id >= 0 ? opts->shm_id : getpid());
528 #if defined(__linux__)
529 		SPDK_NOTICELOG("'spdk_trace' without parameters will also work if this is the only\n");
530 		SPDK_NOTICELOG("SPDK application currently running.\n");
531 		SPDK_NOTICELOG("Or copy /dev/shm%s for offline analysis/debug.\n", shm_name);
532 #endif
533 	}
534 	free(tp_g_str);
535 
536 	return 0;
537 }
538 
539 static void
540 bootstrap_fn(void *arg1)
541 {
542 	spdk_rpc_set_allowlist(g_spdk_app.rpc_allowlist);
543 
544 	if (g_spdk_app.json_data) {
545 		/* Load SPDK_RPC_STARTUP RPCs from config file */
546 		assert(spdk_rpc_get_state() == SPDK_RPC_STARTUP);
547 		spdk_subsystem_load_config(g_spdk_app.json_data, g_spdk_app.json_data_size,
548 					   app_do_spdk_subsystem_init, NULL,
549 					   !g_spdk_app.json_config_ignore_errors);
550 	} else {
551 		app_do_spdk_subsystem_init(0, NULL);
552 	}
553 }
554 
555 static void
556 app_copy_opts(struct spdk_app_opts *opts, struct spdk_app_opts *opts_user, size_t opts_size)
557 {
558 	spdk_app_opts_init(opts, sizeof(*opts));
559 	opts->opts_size = opts_size;
560 
561 #define SET_FIELD(field) \
562         if (offsetof(struct spdk_app_opts, field) + sizeof(opts->field) <= (opts->opts_size)) { \
563 		opts->field = opts_user->field; \
564 	} \
565 
566 	SET_FIELD(name);
567 	SET_FIELD(json_config_file);
568 	SET_FIELD(json_config_ignore_errors);
569 	SET_FIELD(rpc_addr);
570 	SET_FIELD(reactor_mask);
571 	SET_FIELD(lcore_map);
572 	SET_FIELD(tpoint_group_mask);
573 	SET_FIELD(shm_id);
574 	SET_FIELD(shutdown_cb);
575 	SET_FIELD(enable_coredump);
576 	SET_FIELD(mem_channel);
577 	SET_FIELD(main_core);
578 	SET_FIELD(mem_size);
579 	SET_FIELD(no_pci);
580 	SET_FIELD(hugepage_single_segments);
581 	SET_FIELD(unlink_hugepage);
582 	SET_FIELD(no_huge);
583 	SET_FIELD(hugedir);
584 	SET_FIELD(print_level);
585 	SET_FIELD(num_pci_addr);
586 	SET_FIELD(pci_blocked);
587 	SET_FIELD(pci_allowed);
588 	SET_FIELD(iova_mode);
589 	SET_FIELD(delay_subsystem_init);
590 	SET_FIELD(num_entries);
591 	SET_FIELD(env_context);
592 	SET_FIELD(log);
593 	SET_FIELD(base_virtaddr);
594 	SET_FIELD(disable_signal_handlers);
595 	SET_FIELD(interrupt_mode);
596 	SET_FIELD(msg_mempool_size);
597 	SET_FIELD(rpc_allowlist);
598 	SET_FIELD(vf_token);
599 	SET_FIELD(rpc_log_file);
600 	SET_FIELD(rpc_log_level);
601 	SET_FIELD(json_data);
602 	SET_FIELD(json_data_size);
603 
604 	/* You should not remove this statement, but need to update the assert statement
605 	 * if you add a new field, and also add a corresponding SET_FIELD statement */
606 	SPDK_STATIC_ASSERT(sizeof(struct spdk_app_opts) == 252, "Incorrect size");
607 
608 #undef SET_FIELD
609 }
610 
611 static int
612 unclaim_cpu_cores(uint32_t *failed_core)
613 {
614 	char core_name[40];
615 	uint32_t i;
616 	int rc;
617 
618 	for (i = 0; i < MAX_CPU_CORES; i++) {
619 		if (g_core_locks[i] != -1) {
620 			snprintf(core_name, sizeof(core_name), "/var/tmp/spdk_cpu_lock_%03d", i);
621 			rc = close(g_core_locks[i]);
622 			if (rc) {
623 				SPDK_ERRLOG("Failed to close lock fd for core %d, errno: %d\n", i, errno);
624 				goto error;
625 			}
626 
627 			g_core_locks[i] = -1;
628 			rc = unlink(core_name);
629 			if (rc) {
630 				SPDK_ERRLOG("Failed to unlink lock fd for core %d, errno: %d\n", i, errno);
631 				goto error;
632 			}
633 		}
634 	}
635 
636 	return 0;
637 
638 error:
639 	if (failed_core != NULL) {
640 		/* Set number of core we failed to claim. */
641 		*failed_core = i;
642 	}
643 	return -1;
644 }
645 
646 static int
647 claim_cpu_cores(uint32_t *failed_core)
648 {
649 	char core_name[40];
650 	int core_fd, pid;
651 	int *core_map;
652 	uint32_t core;
653 
654 	struct flock core_lock = {
655 		.l_type = F_WRLCK,
656 		.l_whence = SEEK_SET,
657 		.l_start = 0,
658 		.l_len = 0,
659 	};
660 
661 	SPDK_ENV_FOREACH_CORE(core) {
662 		if (g_core_locks[core] != -1) {
663 			/* If this core is locked already, do not try lock it again. */
664 			continue;
665 		}
666 
667 		snprintf(core_name, sizeof(core_name), "/var/tmp/spdk_cpu_lock_%03d", core);
668 		core_fd = open(core_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
669 		if (core_fd == -1) {
670 			SPDK_ERRLOG("Could not open %s (%s).\n", core_name, spdk_strerror(errno));
671 			/* Return number of core we failed to claim. */
672 			goto error;
673 		}
674 
675 		if (ftruncate(core_fd, sizeof(int)) != 0) {
676 			SPDK_ERRLOG("Could not truncate %s (%s).\n", core_name, spdk_strerror(errno));
677 			close(core_fd);
678 			goto error;
679 		}
680 
681 		core_map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, core_fd, 0);
682 		if (core_map == MAP_FAILED) {
683 			SPDK_ERRLOG("Could not mmap core %s (%s).\n", core_name, spdk_strerror(errno));
684 			close(core_fd);
685 			goto error;
686 		}
687 
688 		if (fcntl(core_fd, F_SETLK, &core_lock) != 0) {
689 			pid = *core_map;
690 			SPDK_ERRLOG("Cannot create lock on core %" PRIu32 ", probably process %d has claimed it.\n",
691 				    core, pid);
692 			munmap(core_map, sizeof(int));
693 			close(core_fd);
694 			goto error;
695 		}
696 
697 		/* We write the PID to the core lock file so that other processes trying
698 		* to claim the same core will know what process is holding the lock. */
699 		*core_map = (int)getpid();
700 		munmap(core_map, sizeof(int));
701 		g_core_locks[core] = core_fd;
702 		/* Keep core_fd open to maintain the lock. */
703 	}
704 
705 	return 0;
706 
707 error:
708 	if (failed_core != NULL) {
709 		/* Set number of core we failed to claim. */
710 		*failed_core = core;
711 	}
712 	unclaim_cpu_cores(NULL);
713 	return -1;
714 }
715 
716 int
717 spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
718 	       void *arg1)
719 {
720 	int			rc;
721 	char			*tty;
722 	struct spdk_cpuset	tmp_cpumask = {};
723 	static bool		g_env_was_setup = false;
724 	struct spdk_app_opts opts_local = {};
725 	struct spdk_app_opts *opts = &opts_local;
726 	uint32_t i;
727 
728 	if (!opts_user) {
729 		SPDK_ERRLOG("opts_user should not be NULL\n");
730 		return 1;
731 	}
732 
733 	if (!opts_user->opts_size) {
734 		SPDK_ERRLOG("The opts_size in opts_user structure should not be zero value\n");
735 		return 1;
736 	}
737 
738 	if (opts_user->name == NULL) {
739 		SPDK_ERRLOG("spdk_app_opts::name not specified\n");
740 		return 1;
741 	}
742 
743 	app_copy_opts(opts, opts_user, opts_user->opts_size);
744 
745 	if (!start_fn) {
746 		SPDK_ERRLOG("start_fn should not be NULL\n");
747 		return 1;
748 	}
749 
750 	if (!opts->rpc_addr && opts->delay_subsystem_init) {
751 		SPDK_ERRLOG("Cannot use '--wait-for-rpc' if no RPC server is going to be started.\n");
752 		return 1;
753 	}
754 
755 	if (!(opts->lcore_map || opts->reactor_mask)) {
756 		/* Set default CPU mask */
757 		opts->reactor_mask = SPDK_APP_DPDK_DEFAULT_CORE_MASK;
758 	}
759 
760 	tty = ttyname(STDERR_FILENO);
761 	if (opts->print_level > SPDK_LOG_WARN &&
762 	    isatty(STDERR_FILENO) &&
763 	    tty &&
764 	    !strncmp(tty, "/dev/tty", strlen("/dev/tty"))) {
765 		printf("Warning: printing stderr to console terminal without -q option specified.\n");
766 		printf("Suggest using --silence-noticelog to disable logging to stderr and\n");
767 		printf("monitor syslog, or redirect stderr to a file.\n");
768 		printf("(Delaying for 10 seconds...)\n");
769 		sleep(10);
770 	}
771 
772 	spdk_log_set_print_level(opts->print_level);
773 
774 #ifndef SPDK_NO_RLIMIT
775 	if (opts->enable_coredump) {
776 		struct rlimit core_limits;
777 
778 		core_limits.rlim_cur = core_limits.rlim_max = SPDK_APP_DEFAULT_CORE_LIMIT;
779 		setrlimit(RLIMIT_CORE, &core_limits);
780 	}
781 #endif
782 
783 	if (opts->interrupt_mode) {
784 		spdk_interrupt_mode_enable();
785 	}
786 
787 	memset(&g_spdk_app, 0, sizeof(g_spdk_app));
788 
789 	g_spdk_app.json_config_ignore_errors = opts->json_config_ignore_errors;
790 	g_spdk_app.rpc_addr = opts->rpc_addr;
791 	g_spdk_app.rpc_allowlist = opts->rpc_allowlist;
792 	g_spdk_app.rpc_log_file = opts->rpc_log_file;
793 	g_spdk_app.rpc_log_level = opts->rpc_log_level;
794 	g_spdk_app.shm_id = opts->shm_id;
795 	g_spdk_app.shutdown_cb = opts->shutdown_cb;
796 	g_spdk_app.rc = 0;
797 	g_spdk_app.stopped = false;
798 
799 	spdk_log_set_level(SPDK_APP_DEFAULT_LOG_LEVEL);
800 
801 	/* Pass NULL to app_setup_env if SPDK app has been set up, in order to
802 	 * indicate that this is a reinitialization.
803 	 */
804 	if (app_setup_env(g_env_was_setup ? NULL : opts) < 0) {
805 		return 1;
806 	}
807 
808 	/* Calculate mempool size now that the env layer has configured the core count
809 	 * for the application */
810 	calculate_mempool_size(opts, opts_user);
811 
812 	spdk_log_open(opts->log);
813 
814 	/* Initialize each lock to -1 to indicate "empty" status */
815 	for (i = 0; i < MAX_CPU_CORES; i++) {
816 		g_core_locks[i] = -1;
817 	}
818 
819 	if (!g_disable_cpumask_locks) {
820 		if (claim_cpu_cores(NULL)) {
821 			SPDK_ERRLOG("Unable to acquire lock on assigned core mask - exiting.\n");
822 			return 1;
823 		}
824 	} else {
825 		SPDK_NOTICELOG("CPU core locks deactivated.\n");
826 	}
827 
828 	SPDK_NOTICELOG("Total cores available: %d\n", spdk_env_get_core_count());
829 
830 	if ((rc = spdk_reactors_init(opts->msg_mempool_size)) != 0) {
831 		SPDK_ERRLOG("Reactor Initialization failed: rc = %d\n", rc);
832 		return 1;
833 	}
834 
835 	spdk_cpuset_set_cpu(&tmp_cpumask, spdk_env_get_current_core(), true);
836 
837 	/* Now that the reactors have been initialized, we can create the app thread. */
838 	spdk_thread_create("app_thread", &tmp_cpumask);
839 	if (!spdk_thread_get_app_thread()) {
840 		SPDK_ERRLOG("Unable to create an spdk_thread for initialization\n");
841 		return 1;
842 	}
843 
844 	/*
845 	 * Disable and ignore trace setup if setting num_entries
846 	 * to be 0.
847 	 *
848 	 * Note the call to app_setup_trace() is located here
849 	 * ahead of app_setup_signal_handlers().
850 	 * That's because there is not an easy/direct clean
851 	 * way of unwinding alloc'd resources that can occur
852 	 * in app_setup_signal_handlers().
853 	 */
854 	if (opts->num_entries != 0 && app_setup_trace(opts) != 0) {
855 		return 1;
856 	}
857 
858 	if (!opts->disable_signal_handlers && app_setup_signal_handlers(opts) != 0) {
859 		return 1;
860 	}
861 
862 	g_delay_subsystem_init = opts->delay_subsystem_init;
863 	g_start_fn = start_fn;
864 	g_start_arg = arg1;
865 
866 	if (opts->json_config_file != NULL) {
867 		if (opts->json_data) {
868 			SPDK_ERRLOG("App opts json_config_file and json_data are mutually exclusive\n");
869 			return 1;
870 		}
871 
872 		g_spdk_app.json_data = spdk_posix_file_load_from_name(opts->json_config_file,
873 				       &g_spdk_app.json_data_size);
874 		if (!g_spdk_app.json_data) {
875 			SPDK_ERRLOG("Read JSON configuration file %s failed: %s\n",
876 				    opts->json_config_file, spdk_strerror(errno));
877 			return 1;
878 		}
879 	} else if (opts->json_data) {
880 		g_spdk_app.json_data = calloc(1, opts->json_data_size);
881 		if (!g_spdk_app.json_data) {
882 			SPDK_ERRLOG("Failed to allocate JSON data buffer\n");
883 			return 1;
884 		}
885 
886 		memcpy(g_spdk_app.json_data, opts->json_data, opts->json_data_size);
887 		g_spdk_app.json_data_size = opts->json_data_size;
888 	}
889 
890 	spdk_thread_send_msg(spdk_thread_get_app_thread(), bootstrap_fn, NULL);
891 
892 	/* This blocks until spdk_app_stop is called */
893 	spdk_reactors_start();
894 
895 	g_env_was_setup = true;
896 
897 	return g_spdk_app.rc;
898 }
899 
900 void
901 spdk_app_fini(void)
902 {
903 	spdk_trace_cleanup();
904 	spdk_reactors_fini();
905 	spdk_env_fini();
906 	spdk_log_close();
907 	unclaim_cpu_cores(NULL);
908 }
909 
910 static void
911 subsystem_fini_done(void *arg1)
912 {
913 	spdk_rpc_finish();
914 	spdk_reactors_stop(NULL);
915 }
916 
917 static void
918 _start_subsystem_fini(void *arg1)
919 {
920 	if (g_scheduling_in_progress) {
921 		spdk_thread_send_msg(spdk_thread_get_app_thread(), _start_subsystem_fini, NULL);
922 		return;
923 	}
924 
925 	spdk_subsystem_fini(subsystem_fini_done, NULL);
926 }
927 
928 static int
929 log_deprecation_hits(void *ctx, struct spdk_deprecation *dep)
930 {
931 	uint64_t hits = spdk_deprecation_get_hits(dep);
932 
933 	if (hits == 0) {
934 		return 0;
935 	}
936 
937 	SPDK_WARNLOG("%s: deprecation '%s' scheduled for removal in %s hit %" PRIu64 " times\n",
938 		     spdk_deprecation_get_tag(dep), spdk_deprecation_get_description(dep),
939 		     spdk_deprecation_get_remove_release(dep), hits);
940 	return 0;
941 }
942 
943 static void
944 app_stop(void *arg1)
945 {
946 	free(g_spdk_app.json_data);
947 
948 	if (g_spdk_app.rc == 0) {
949 		g_spdk_app.rc = (int)(intptr_t)arg1;
950 	}
951 
952 	if (g_spdk_app.stopped) {
953 		SPDK_NOTICELOG("spdk_app_stop called twice\n");
954 		return;
955 	}
956 
957 	g_spdk_app.stopped = true;
958 	spdk_log_for_each_deprecation(NULL, log_deprecation_hits);
959 	_start_subsystem_fini(NULL);
960 }
961 
962 void
963 spdk_app_stop(int rc)
964 {
965 	if (rc) {
966 		SPDK_WARNLOG("spdk_app_stop'd on non-zero\n");
967 	}
968 
969 	/*
970 	 * We want to run spdk_subsystem_fini() from the same thread where spdk_subsystem_init()
971 	 * was called.
972 	 */
973 	spdk_thread_send_msg(spdk_thread_get_app_thread(), app_stop, (void *)(intptr_t)rc);
974 }
975 
976 static void
977 usage_memory_size(void)
978 {
979 #ifndef __linux__
980 	if (g_default_opts.mem_size <= 0) {
981 		printf("all hugepage memory)\n");
982 	} else
983 #endif
984 	{
985 		printf("%dMB)\n", g_default_opts.mem_size >= 0 ? g_default_opts.mem_size : 0);
986 	}
987 }
988 
989 static void
990 usage(void (*app_usage)(void))
991 {
992 	printf("%s [options]\n", g_executable_name);
993 	/* Keep entries inside categories roughly sorted by frequency of use. */
994 	printf("\nCPU options:\n");
995 	printf(" -m, --cpumask <mask or list>    core mask (like 0xF) or core list of '[]' embraced for DPDK\n");
996 	printf("                                 (like [0,1,10])\n");
997 	printf("     --lcores <list>       lcore to CPU mapping list. The list is in the format:\n");
998 	printf("                           <lcores[@CPUs]>[<,lcores[@CPUs]>...]\n");
999 	printf("                           lcores and cpus list are grouped by '(' and ')', e.g '--lcores \"(5-7)@(10-12)\"'\n");
1000 	printf("                           Within the group, '-' is used for range separator,\n");
1001 	printf("                           ',' is used for single number separator.\n");
1002 	printf("                           '( )' can be omitted for single element group,\n");
1003 	printf("                           '@' can be omitted if cpus and lcores have the same value\n");
1004 	printf("     --disable-cpumask-locks    Disable CPU core lock files.\n");
1005 	printf("     --interrupt-mode      set app to interrupt mode (Warning: CPU usage will be reduced only if all\n");
1006 	printf("                           pollers in the app support interrupt mode)\n");
1007 	printf(" -p, --main-core <id>      main (primary) core for DPDK\n");
1008 
1009 	printf("\nConfiguration options:\n");
1010 	printf(" -c, --config, --json  <config>     JSON config file\n");
1011 	printf(" -r, --rpc-socket <path>   RPC listen address (default %s)\n", SPDK_DEFAULT_RPC_ADDR);
1012 	printf("     --no-rpc-server       skip RPC server initialization. This option ignores '--rpc-socket' value.\n");
1013 	printf("     --wait-for-rpc        wait for RPCs to initialize subsystems\n");
1014 	printf("     --rpcs-allowed	   comma-separated list of permitted RPCS\n");
1015 	printf("     --json-ignore-init-errors    don't exit on invalid config entry\n");
1016 
1017 	printf("\nMemory options:\n");
1018 	printf("     --iova-mode <pa/va>   set IOVA mode ('pa' for IOVA_PA and 'va' for IOVA_VA)\n");
1019 	printf("     --base-virtaddr <addr>      the base virtual address for DPDK (default: 0x200000000000)\n");
1020 	printf("     --huge-dir <path>     use a specific hugetlbfs mount to reserve memory from\n");
1021 	printf(" -R, --huge-unlink         unlink huge files after initialization\n");
1022 	printf(" -n, --mem-channels <num>  number of memory channels used for DPDK\n");
1023 	printf(" -s, --mem-size <size>     memory size in MB for DPDK (default: ");
1024 	usage_memory_size();
1025 	printf("     --msg-mempool-size <size>  global message memory pool size in count (default: %d)\n",
1026 	       SPDK_DEFAULT_MSG_MEMPOOL_SIZE);
1027 	printf("     --no-huge             run without using hugepages\n");
1028 	printf(" -i, --shm-id <id>         shared memory ID (optional)\n");
1029 	printf(" -g, --single-file-segments   force creating just one hugetlbfs file\n");
1030 
1031 	printf("\nPCI options:\n");
1032 	printf(" -A, --pci-allowed <bdf>   pci addr to allow (-B and -A cannot be used at the same time)\n");
1033 	printf(" -B, --pci-blocked <bdf>   pci addr to block (can be used more than once)\n");
1034 	printf(" -u, --no-pci              disable PCI access\n");
1035 	printf("     --vfio-vf-token       VF token (UUID) shared between SR-IOV PF and VFs for vfio_pci driver\n");
1036 
1037 	printf("\nLog options:\n");
1038 	spdk_log_usage(stdout, "-L");
1039 	printf("     --silence-noticelog   disable notice level logging to stderr\n");
1040 
1041 	printf("\nTrace options:\n");
1042 	printf("     --num-trace-entries <num>   number of trace entries for each core, must be power of 2,\n");
1043 	printf("                                 setting 0 to disable trace (default %d)\n",
1044 	       SPDK_APP_DEFAULT_NUM_TRACE_ENTRIES);
1045 	printf("                                 Tracepoints vary in size and can use more than one trace entry.\n");
1046 	spdk_trace_mask_usage(stdout, "-e");
1047 
1048 	printf("\nOther options:\n");
1049 	printf(" -h, --help                show this usage\n");
1050 	printf(" -v, --version             print SPDK version\n");
1051 	printf(" -d, --limit-coredump      do not set max coredump size to RLIM_INFINITY\n");
1052 	printf("     --env-context         Opaque context for use of the env implementation\n");
1053 
1054 	if (app_usage) {
1055 		printf("\nApplication specific:\n");
1056 		app_usage();
1057 	}
1058 }
1059 
1060 spdk_app_parse_args_rvals_t
1061 spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
1062 		    const char *app_getopt_str, const struct option *app_long_opts,
1063 		    int (*app_parse)(int ch, char *arg),
1064 		    void (*app_usage)(void))
1065 {
1066 	int ch, rc, opt_idx, global_long_opts_len, app_long_opts_len;
1067 	struct option *cmdline_options;
1068 	char *cmdline_short_opts = NULL;
1069 	char *shm_id_str = NULL;
1070 	enum spdk_app_parse_args_rvals retval = SPDK_APP_PARSE_ARGS_FAIL;
1071 	long int tmp;
1072 
1073 	memcpy(&g_default_opts, opts, sizeof(g_default_opts));
1074 
1075 	if (opts->json_config_file && access(opts->json_config_file, R_OK) != 0) {
1076 		SPDK_WARNLOG("Can't read JSON configuration file '%s'\n", opts->json_config_file);
1077 		opts->json_config_file = NULL;
1078 	}
1079 
1080 	if (app_long_opts == NULL) {
1081 		app_long_opts_len = 0;
1082 	} else {
1083 		for (app_long_opts_len = 0;
1084 		     app_long_opts[app_long_opts_len].name != NULL;
1085 		     app_long_opts_len++);
1086 	}
1087 
1088 	global_long_opts_len = SPDK_COUNTOF(g_cmdline_options);
1089 
1090 	cmdline_options = calloc(global_long_opts_len + app_long_opts_len + 1, sizeof(*cmdline_options));
1091 	if (!cmdline_options) {
1092 		SPDK_ERRLOG("Out of memory\n");
1093 		return SPDK_APP_PARSE_ARGS_FAIL;
1094 	}
1095 
1096 	memcpy(&cmdline_options[0], g_cmdline_options, sizeof(g_cmdline_options));
1097 	if (app_long_opts) {
1098 		memcpy(&cmdline_options[global_long_opts_len], app_long_opts,
1099 		       app_long_opts_len * sizeof(*app_long_opts));
1100 	}
1101 
1102 	if (app_getopt_str != NULL) {
1103 		ch = app_opts_validate(app_getopt_str);
1104 		if (ch) {
1105 			SPDK_ERRLOG("Duplicated option '%c' between app-specific command line parameter and generic spdk opts.\n",
1106 				    ch);
1107 			goto out;
1108 		}
1109 
1110 		if (!app_parse) {
1111 			SPDK_ERRLOG("Parse function is required when app-specific command line parameters are provided.\n");
1112 			goto out;
1113 		}
1114 	}
1115 
1116 	cmdline_short_opts = spdk_sprintf_alloc("%s%s", app_getopt_str, SPDK_APP_GETOPT_STRING);
1117 	if (!cmdline_short_opts) {
1118 		SPDK_ERRLOG("Out of memory\n");
1119 		goto out;
1120 	}
1121 
1122 	g_executable_name = argv[0];
1123 
1124 	while ((ch = getopt_long(argc, argv, cmdline_short_opts, cmdline_options, &opt_idx)) != -1) {
1125 		switch (ch) {
1126 		case CONFIG_FILE_OPT_IDX:
1127 		case JSON_CONFIG_OPT_IDX:
1128 			opts->json_config_file = optarg;
1129 			break;
1130 		case JSON_CONFIG_IGNORE_INIT_ERRORS_IDX:
1131 			opts->json_config_ignore_errors = true;
1132 			break;
1133 		case LIMIT_COREDUMP_OPT_IDX:
1134 			opts->enable_coredump = false;
1135 			break;
1136 		case TPOINT_GROUP_OPT_IDX:
1137 			opts->tpoint_group_mask = optarg;
1138 			break;
1139 		case SINGLE_FILE_SEGMENTS_OPT_IDX:
1140 			opts->hugepage_single_segments = true;
1141 			break;
1142 		case HELP_OPT_IDX:
1143 			usage(app_usage);
1144 			retval = SPDK_APP_PARSE_ARGS_HELP;
1145 			goto out;
1146 		case SHM_ID_OPT_IDX:
1147 			shm_id_str = optarg;
1148 			/* a negative shm-id disables shared configuration file */
1149 			if (optarg[0] == '-') {
1150 				shm_id_str++;
1151 			}
1152 			/* check if the positive value of provided shm_id can be parsed as
1153 			 * an integer
1154 			 */
1155 			opts->shm_id = spdk_strtol(shm_id_str, 0);
1156 			if (opts->shm_id < 0) {
1157 				SPDK_ERRLOG("Invalid shared memory ID %s\n", optarg);
1158 				goto out;
1159 			}
1160 			if (optarg[0] == '-') {
1161 				opts->shm_id = -opts->shm_id;
1162 			}
1163 			break;
1164 		case CPUMASK_OPT_IDX:
1165 			if (opts->lcore_map) {
1166 				SPDK_ERRLOG("lcore map and core mask can't be set simultaneously\n");
1167 				goto out;
1168 			}
1169 			opts->reactor_mask = optarg;
1170 			break;
1171 		case LCORES_OPT_IDX:
1172 			if (opts->reactor_mask) {
1173 				SPDK_ERRLOG("lcore map and core mask can't be set simultaneously\n");
1174 				goto out;
1175 			}
1176 			opts->lcore_map = optarg;
1177 			break;
1178 		case DISABLE_CPUMASK_LOCKS_OPT_IDX:
1179 			g_disable_cpumask_locks = true;
1180 			break;
1181 		case MEM_CHANNELS_OPT_IDX:
1182 			opts->mem_channel = spdk_strtol(optarg, 0);
1183 			if (opts->mem_channel < 0) {
1184 				SPDK_ERRLOG("Invalid memory channel %s\n", optarg);
1185 				goto out;
1186 			}
1187 			break;
1188 		case MAIN_CORE_OPT_IDX:
1189 			opts->main_core = spdk_strtol(optarg, 0);
1190 			if (opts->main_core < 0) {
1191 				SPDK_ERRLOG("Invalid main core %s\n", optarg);
1192 				goto out;
1193 			}
1194 			break;
1195 		case SILENCE_NOTICELOG_OPT_IDX:
1196 			opts->print_level = SPDK_LOG_WARN;
1197 			break;
1198 		case RPC_SOCKET_OPT_IDX:
1199 			opts->rpc_addr = optarg;
1200 			break;
1201 		case NO_RPC_SERVER_OPT_IDX:
1202 			opts->rpc_addr = NULL;
1203 			break;
1204 		case MEM_SIZE_OPT_IDX: {
1205 			uint64_t mem_size_mb;
1206 			bool mem_size_has_prefix;
1207 
1208 			rc = spdk_parse_capacity(optarg, &mem_size_mb, &mem_size_has_prefix);
1209 			if (rc != 0) {
1210 				SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg);
1211 				usage(app_usage);
1212 				goto out;
1213 			}
1214 
1215 			if (mem_size_has_prefix) {
1216 				/* the mem size is in MB by default, so if a prefix was
1217 				 * specified, we need to manually convert to MB.
1218 				 */
1219 				mem_size_mb /= 1024 * 1024;
1220 			}
1221 
1222 			if (mem_size_mb > INT_MAX) {
1223 				SPDK_ERRLOG("invalid memory pool size `-s %s`\n", optarg);
1224 				usage(app_usage);
1225 				goto out;
1226 			}
1227 
1228 			opts->mem_size = (int) mem_size_mb;
1229 			break;
1230 		}
1231 		case MSG_MEMPOOL_SIZE_OPT_IDX:
1232 			tmp = spdk_strtol(optarg, 10);
1233 			if (tmp <= 0) {
1234 				SPDK_ERRLOG("Invalid message memory pool size %s\n", optarg);
1235 				goto out;
1236 			}
1237 
1238 			opts->msg_mempool_size = (size_t)tmp;
1239 			break;
1240 
1241 		case NO_PCI_OPT_IDX:
1242 			opts->no_pci = true;
1243 			break;
1244 		case WAIT_FOR_RPC_OPT_IDX:
1245 			opts->delay_subsystem_init = true;
1246 			break;
1247 		case PCI_BLOCKED_OPT_IDX:
1248 			if (opts->pci_allowed) {
1249 				free(opts->pci_allowed);
1250 				opts->pci_allowed = NULL;
1251 				SPDK_ERRLOG("-B and -A cannot be used at the same time\n");
1252 				usage(app_usage);
1253 				goto out;
1254 			}
1255 
1256 			rc = app_opts_add_pci_addr(opts, &opts->pci_blocked, optarg);
1257 			if (rc != 0) {
1258 				free(opts->pci_blocked);
1259 				opts->pci_blocked = NULL;
1260 				goto out;
1261 			}
1262 			break;
1263 
1264 		case NO_HUGE_OPT_IDX:
1265 			opts->no_huge = true;
1266 			break;
1267 
1268 		case LOGFLAG_OPT_IDX:
1269 			rc = spdk_log_set_flag(optarg);
1270 			if (rc < 0) {
1271 				SPDK_ERRLOG("unknown flag: %s\n", optarg);
1272 				usage(app_usage);
1273 				goto out;
1274 			}
1275 #ifdef DEBUG
1276 			opts->print_level = SPDK_LOG_DEBUG;
1277 #endif
1278 			break;
1279 		case HUGE_UNLINK_OPT_IDX:
1280 			opts->unlink_hugepage = true;
1281 			break;
1282 		case PCI_ALLOWED_OPT_IDX:
1283 			if (opts->pci_blocked) {
1284 				free(opts->pci_blocked);
1285 				opts->pci_blocked = NULL;
1286 				SPDK_ERRLOG("-B and -W cannot be used at the same time\n");
1287 				usage(app_usage);
1288 				goto out;
1289 			}
1290 
1291 			rc = app_opts_add_pci_addr(opts, &opts->pci_allowed, optarg);
1292 			if (rc != 0) {
1293 				free(opts->pci_allowed);
1294 				opts->pci_allowed = NULL;
1295 				goto out;
1296 			}
1297 			break;
1298 		case BASE_VIRTADDR_OPT_IDX:
1299 			tmp = spdk_strtoll(optarg, 0);
1300 			if (tmp <= 0) {
1301 				SPDK_ERRLOG("Invalid base-virtaddr %s\n", optarg);
1302 				usage(app_usage);
1303 				goto out;
1304 			}
1305 			opts->base_virtaddr = (uint64_t)tmp;
1306 			break;
1307 		case HUGE_DIR_OPT_IDX:
1308 			opts->hugedir = optarg;
1309 			break;
1310 		case IOVA_MODE_OPT_IDX:
1311 			opts->iova_mode = optarg;
1312 			break;
1313 		case NUM_TRACE_ENTRIES_OPT_IDX:
1314 			tmp = spdk_strtoll(optarg, 0);
1315 			if (tmp < 0) {
1316 				SPDK_ERRLOG("Invalid num-trace-entries %s\n", optarg);
1317 				usage(app_usage);
1318 				goto out;
1319 			}
1320 			opts->num_entries = (uint64_t)tmp;
1321 			if (opts->num_entries > 0 && opts->num_entries & (opts->num_entries - 1)) {
1322 				SPDK_ERRLOG("num-trace-entries must be power of 2\n");
1323 				usage(app_usage);
1324 				goto out;
1325 			}
1326 			break;
1327 		case ENV_CONTEXT_OPT_IDX:
1328 			opts->env_context = optarg;
1329 			break;
1330 		case RPCS_ALLOWED_OPT_IDX:
1331 			opts->rpc_allowlist = (const char **)spdk_strarray_from_string(optarg, ",");
1332 			if (opts->rpc_allowlist == NULL) {
1333 				SPDK_ERRLOG("Invalid --rpcs-allowed argument\n");
1334 				usage(app_usage);
1335 				goto out;
1336 			}
1337 			break;
1338 		case ENV_VF_TOKEN_OPT_IDX:
1339 			opts->vf_token = optarg;
1340 			break;
1341 		case INTERRUPT_MODE_OPT_IDX:
1342 			opts->interrupt_mode = true;
1343 			break;
1344 		case VERSION_OPT_IDX:
1345 			printf(SPDK_VERSION_STRING"\n");
1346 			retval = SPDK_APP_PARSE_ARGS_HELP;
1347 			goto out;
1348 		case '?':
1349 			/*
1350 			 * In the event getopt() above detects an option
1351 			 * in argv that is NOT in the getopt_str,
1352 			 * getopt() will return a '?' indicating failure.
1353 			 */
1354 			usage(app_usage);
1355 			goto out;
1356 		default:
1357 			if (!app_parse) {
1358 				SPDK_ERRLOG("Unsupported app-specific command line parameter '%c'.\n", ch);
1359 				goto out;
1360 			}
1361 
1362 			rc = app_parse(ch, optarg);
1363 			if (rc) {
1364 				SPDK_ERRLOG("Parsing app-specific command line parameter '%c' failed: %d\n", ch, rc);
1365 				goto out;
1366 			}
1367 		}
1368 	}
1369 
1370 	retval = SPDK_APP_PARSE_ARGS_SUCCESS;
1371 out:
1372 	if (retval != SPDK_APP_PARSE_ARGS_SUCCESS) {
1373 		free(opts->pci_blocked);
1374 		opts->pci_blocked = NULL;
1375 		free(opts->pci_allowed);
1376 		opts->pci_allowed = NULL;
1377 		spdk_strarray_free((char **)opts->rpc_allowlist);
1378 		opts->rpc_allowlist = NULL;
1379 	}
1380 	free(cmdline_short_opts);
1381 	free(cmdline_options);
1382 	return retval;
1383 }
1384 
1385 void
1386 spdk_app_usage(void)
1387 {
1388 	if (g_executable_name == NULL) {
1389 		SPDK_ERRLOG("%s not valid before calling spdk_app_parse_args()\n", __func__);
1390 		return;
1391 	}
1392 
1393 	usage(NULL);
1394 }
1395 
1396 static void
1397 rpc_framework_start_init_cpl(int rc, void *arg1)
1398 {
1399 	struct spdk_jsonrpc_request *request = arg1;
1400 
1401 	assert(spdk_thread_is_app_thread(NULL));
1402 
1403 	if (rc) {
1404 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1405 						 "framework_initialization failed");
1406 		return;
1407 	}
1408 
1409 	app_subsystem_init_done(0, NULL);
1410 
1411 	spdk_jsonrpc_send_bool_response(request, true);
1412 }
1413 
1414 static void
1415 rpc_framework_start_init(struct spdk_jsonrpc_request *request,
1416 			 const struct spdk_json_val *params)
1417 {
1418 	if (params != NULL) {
1419 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1420 						 "framework_start_init requires no parameters");
1421 		return;
1422 	}
1423 
1424 	spdk_rpc_server_pause(g_spdk_app.rpc_addr);
1425 	spdk_subsystem_init(rpc_framework_start_init_cpl, request);
1426 }
1427 SPDK_RPC_REGISTER("framework_start_init", rpc_framework_start_init, SPDK_RPC_STARTUP)
1428 
1429 struct subsystem_init_poller_ctx {
1430 	struct spdk_poller *init_poller;
1431 	struct spdk_jsonrpc_request *request;
1432 };
1433 
1434 static int
1435 rpc_subsystem_init_poller_ctx(void *ctx)
1436 {
1437 	struct subsystem_init_poller_ctx *poller_ctx = ctx;
1438 
1439 	if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME) {
1440 		spdk_jsonrpc_send_bool_response(poller_ctx->request, true);
1441 		spdk_poller_unregister(&poller_ctx->init_poller);
1442 		free(poller_ctx);
1443 	}
1444 
1445 	return SPDK_POLLER_BUSY;
1446 }
1447 
1448 static void
1449 rpc_framework_wait_init(struct spdk_jsonrpc_request *request,
1450 			const struct spdk_json_val *params)
1451 {
1452 	struct subsystem_init_poller_ctx *ctx;
1453 
1454 	if (spdk_rpc_get_state() == SPDK_RPC_RUNTIME) {
1455 		spdk_jsonrpc_send_bool_response(request, true);
1456 	} else {
1457 		ctx = malloc(sizeof(struct subsystem_init_poller_ctx));
1458 		if (ctx == NULL) {
1459 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1460 							 "Unable to allocate memory for the request context\n");
1461 			return;
1462 		}
1463 		ctx->request = request;
1464 		ctx->init_poller = SPDK_POLLER_REGISTER(rpc_subsystem_init_poller_ctx, ctx, 0);
1465 	}
1466 }
1467 SPDK_RPC_REGISTER("framework_wait_init", rpc_framework_wait_init,
1468 		  SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
1469 
1470 static void
1471 rpc_framework_disable_cpumask_locks(struct spdk_jsonrpc_request *request,
1472 				    const struct spdk_json_val *params)
1473 {
1474 	char msg[128];
1475 	int rc;
1476 	uint32_t failed_core;
1477 
1478 	if (params != NULL) {
1479 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1480 						 "framework_disable_cpumask_locks"
1481 						 "requires no arguments");
1482 		return;
1483 	}
1484 
1485 	rc = unclaim_cpu_cores(&failed_core);
1486 	if (rc) {
1487 		snprintf(msg, sizeof(msg), "Failed to unclaim CPU core: %" PRIu32, failed_core);
1488 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
1489 		return;
1490 	}
1491 
1492 	spdk_jsonrpc_send_bool_response(request, true);
1493 }
1494 SPDK_RPC_REGISTER("framework_disable_cpumask_locks", rpc_framework_disable_cpumask_locks,
1495 		  SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
1496 
1497 static void
1498 rpc_framework_enable_cpumask_locks(struct spdk_jsonrpc_request *request,
1499 				   const struct spdk_json_val *params)
1500 {
1501 	char msg[128];
1502 	int rc;
1503 	uint32_t failed_core;
1504 
1505 	if (params != NULL) {
1506 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1507 						 "framework_enable_cpumask_locks"
1508 						 "requires no arguments");
1509 		return;
1510 	}
1511 
1512 	rc = claim_cpu_cores(&failed_core);
1513 	if (rc) {
1514 		snprintf(msg, sizeof(msg), "Failed to claim CPU core: %" PRIu32, failed_core);
1515 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
1516 		return;
1517 	}
1518 
1519 	spdk_jsonrpc_send_bool_response(request, true);
1520 }
1521 SPDK_RPC_REGISTER("framework_enable_cpumask_locks", rpc_framework_enable_cpumask_locks,
1522 		  SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
1523