xref: /spdk/test/app/stub/stub.c (revision 87696292e0d13f39e62de721324e2a577f503de7)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
34b521e17SJim Harris  *   All rights reserved.
44b521e17SJim Harris  */
54b521e17SJim Harris 
64b521e17SJim Harris #include "spdk/stdinc.h"
74b521e17SJim Harris 
8fa3dd136SJim Harris #include "spdk/event.h"
94b521e17SJim Harris #include "spdk/nvme.h"
10f56de7b8SShuhei Matsumoto #include "spdk/string.h"
1105130f2dSJim Harris #include "spdk/thread.h"
124b521e17SJim Harris 
13675dc02bSJim Harris static char g_path[256];
1405130f2dSJim Harris static struct spdk_poller *g_poller;
15ad3634afSCurt Bruns /* default sleep time in ms */
16ad3634afSCurt Bruns static uint32_t g_sleep_time = 1000;
1790b54d76SJim Harris static uint32_t g_io_queue_size;
18675dc02bSJim Harris 
19bad2c8e8SChangpeng Liu struct ctrlr_entry {
20bad2c8e8SChangpeng Liu 	struct spdk_nvme_ctrlr *ctrlr;
21da08be0fSShuhei Matsumoto 	TAILQ_ENTRY(ctrlr_entry) link;
22bad2c8e8SChangpeng Liu };
23bad2c8e8SChangpeng Liu 
24da08be0fSShuhei Matsumoto static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
25bad2c8e8SChangpeng Liu 
26bad2c8e8SChangpeng Liu static void
27bad2c8e8SChangpeng Liu cleanup(void)
28bad2c8e8SChangpeng Liu {
29da08be0fSShuhei Matsumoto 	struct ctrlr_entry *ctrlr_entry, *tmp;
307a85c283SShuhei Matsumoto 	struct spdk_nvme_detach_ctx *detach_ctx = NULL;
31bad2c8e8SChangpeng Liu 
32da08be0fSShuhei Matsumoto 	TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
33da08be0fSShuhei Matsumoto 		TAILQ_REMOVE(&g_controllers, ctrlr_entry, link);
349fa44ca4SJim Harris 		spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr);
357a85c283SShuhei Matsumoto 		spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
36bad2c8e8SChangpeng Liu 		free(ctrlr_entry);
37bad2c8e8SChangpeng Liu 	}
387a85c283SShuhei Matsumoto 
394fe4040aSShuhei Matsumoto 	if (detach_ctx) {
404fe4040aSShuhei Matsumoto 		spdk_nvme_detach_poll(detach_ctx);
417a85c283SShuhei Matsumoto 	}
42bad2c8e8SChangpeng Liu }
43bad2c8e8SChangpeng Liu 
444b521e17SJim Harris static void
454b521e17SJim Harris usage(char *executable_name)
464b521e17SJim Harris {
474b521e17SJim Harris 	printf("%s [options]\n", executable_name);
484b521e17SJim Harris 	printf("options:\n");
491f5bbe02SDaniel Verkamp 	printf(" -i shared memory ID [required]\n");
504b521e17SJim Harris 	printf(" -m mask    core mask for DPDK\n");
514b521e17SJim Harris 	printf(" -n channel number of memory channels used for DPDK\n");
52*87696292SKonrad Sztyber 	printf(" -L flag    enable log flag\n");
533795c1cfSJim Harris 	printf(" -p core    main (primary) core for DPDK\n");
544b521e17SJim Harris 	printf(" -s size    memory size in MB for DPDK\n");
55ad3634afSCurt Bruns 	printf(" -t msec    sleep time (ms) between checking for admin completions\n");
5690b54d76SJim Harris 	printf(" -q size    override default io_queue_size when attaching controllers\n");
574b521e17SJim Harris 	printf(" -H         show this usage\n");
584b521e17SJim Harris }
594b521e17SJim Harris 
604b521e17SJim Harris static bool
614b521e17SJim Harris probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
624b521e17SJim Harris 	 struct spdk_nvme_ctrlr_opts *opts)
634b521e17SJim Harris {
6490b54d76SJim Harris 	if (g_io_queue_size > 0) {
6590b54d76SJim Harris 		opts->io_queue_size = g_io_queue_size;
6690b54d76SJim Harris 	}
674b521e17SJim Harris 	return true;
684b521e17SJim Harris }
694b521e17SJim Harris 
704b521e17SJim Harris static void
714b521e17SJim Harris attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
724b521e17SJim Harris 	  struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
734b521e17SJim Harris {
74bad2c8e8SChangpeng Liu 	struct ctrlr_entry *entry;
75bad2c8e8SChangpeng Liu 
76bad2c8e8SChangpeng Liu 	entry = malloc(sizeof(struct ctrlr_entry));
77bad2c8e8SChangpeng Liu 	if (entry == NULL) {
78bad2c8e8SChangpeng Liu 		fprintf(stderr, "Malloc error\n");
79bad2c8e8SChangpeng Liu 		exit(1);
80bad2c8e8SChangpeng Liu 	}
81bad2c8e8SChangpeng Liu 
82bad2c8e8SChangpeng Liu 	entry->ctrlr = ctrlr;
83da08be0fSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_controllers, entry, link);
849fa44ca4SJim Harris 	if (spdk_nvme_cuse_register(ctrlr) != 0) {
859fa44ca4SJim Harris 		fprintf(stderr, "could not register ctrlr with cuse\n");
869fa44ca4SJim Harris 	}
874b521e17SJim Harris }
884b521e17SJim Harris 
8905130f2dSJim Harris static int
9005130f2dSJim Harris stub_sleep(void *arg)
9105130f2dSJim Harris {
92ad3634afSCurt Bruns 	struct ctrlr_entry *ctrlr_entry, *tmp;
93ad3634afSCurt Bruns 
94ad3634afSCurt Bruns 	usleep(g_sleep_time * 1000);
95ad3634afSCurt Bruns 	TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
96ad3634afSCurt Bruns 		spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr);
97ad3634afSCurt Bruns 	}
9805130f2dSJim Harris 	return 0;
9905130f2dSJim Harris }
10005130f2dSJim Harris 
101fa3dd136SJim Harris static void
102deb8ee5cSBen Walker stub_start(void *arg1)
103fa3dd136SJim Harris {
104fa3dd136SJim Harris 	int shm_id = (intptr_t)arg1;
105fa3dd136SJim Harris 
106ef72f4c5SJim Harris 	snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id);
107ef72f4c5SJim Harris 
108ef72f4c5SJim Harris 	/* If sentinel file already exists from earlier crashed stub, delete
109ef72f4c5SJim Harris 	 * it now to avoid mknod() failure after spdk_nvme_probe() completes.
110ef72f4c5SJim Harris 	 */
111ef72f4c5SJim Harris 	unlink(g_path);
112ef72f4c5SJim Harris 
113fa3dd136SJim Harris 	spdk_unaffinitize_thread();
114fa3dd136SJim Harris 
115fa3dd136SJim Harris 	if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
116fa3dd136SJim Harris 		fprintf(stderr, "spdk_nvme_probe() failed\n");
117fa3dd136SJim Harris 		exit(1);
118fa3dd136SJim Harris 	}
119fa3dd136SJim Harris 
120fa3dd136SJim Harris 	if (mknod(g_path, S_IFREG, 0) != 0) {
121fa3dd136SJim Harris 		fprintf(stderr, "could not create sentinel file %s\n", g_path);
122fa3dd136SJim Harris 		exit(1);
123fa3dd136SJim Harris 	}
12405130f2dSJim Harris 
125ab0bc5c2SShuhei Matsumoto 	g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0);
126fa3dd136SJim Harris }
127fa3dd136SJim Harris 
128fa3dd136SJim Harris static void
129fa3dd136SJim Harris stub_shutdown(void)
130fa3dd136SJim Harris {
13105130f2dSJim Harris 	spdk_poller_unregister(&g_poller);
132fa3dd136SJim Harris 	unlink(g_path);
133fa3dd136SJim Harris 	spdk_app_stop(0);
134fa3dd136SJim Harris }
135fa3dd136SJim Harris 
1364b521e17SJim Harris int
1374b521e17SJim Harris main(int argc, char **argv)
1384b521e17SJim Harris {
1394b521e17SJim Harris 	int ch;
140fa3dd136SJim Harris 	struct spdk_app_opts opts = {};
141f56de7b8SShuhei Matsumoto 	long int val;
1424b521e17SJim Harris 
1434b521e17SJim Harris 	/* default value in opts structure */
14448701bd9SZiye Yang 	spdk_app_opts_init(&opts, sizeof(opts));
1454b521e17SJim Harris 
1464b521e17SJim Harris 	opts.name = "stub";
1476bef902cSJim Harris 	opts.rpc_addr = NULL;
148be619872SJim Harris 	opts.env_context = "--proc-type=primary";
1494b521e17SJim Harris 
150*87696292SKonrad Sztyber 	while ((ch = getopt(argc, argv, "i:m:n:p:q:s:t:HL:")) != -1) {
151f56de7b8SShuhei Matsumoto 		if (ch == 'm') {
152f56de7b8SShuhei Matsumoto 			opts.reactor_mask = optarg;
153*87696292SKonrad Sztyber 		} else if (ch == 'L') {
154*87696292SKonrad Sztyber 			if (spdk_log_set_flag(optarg) != 0) {
155*87696292SKonrad Sztyber 				SPDK_ERRLOG("unknown flag: %s\n", optarg);
156*87696292SKonrad Sztyber 				usage(argv[0]);
157*87696292SKonrad Sztyber 				exit(EXIT_FAILURE);
158*87696292SKonrad Sztyber 			}
159*87696292SKonrad Sztyber #ifdef DEBUG
160*87696292SKonrad Sztyber 			opts.print_level = SPDK_LOG_DEBUG;
161*87696292SKonrad Sztyber #endif
162cf3ed0e1Swanghailiangx 		} else if (ch == '?' || ch == 'H') {
163f56de7b8SShuhei Matsumoto 			usage(argv[0]);
164cf3ed0e1Swanghailiangx 			exit(EXIT_SUCCESS);
165f56de7b8SShuhei Matsumoto 		} else {
166f56de7b8SShuhei Matsumoto 			val = spdk_strtol(optarg, 10);
167f56de7b8SShuhei Matsumoto 			if (val < 0) {
168f56de7b8SShuhei Matsumoto 				fprintf(stderr, "Converting a string to integer failed\n");
169f56de7b8SShuhei Matsumoto 				exit(1);
170f56de7b8SShuhei Matsumoto 			}
1714b521e17SJim Harris 			switch (ch) {
1724b521e17SJim Harris 			case 'i':
173f56de7b8SShuhei Matsumoto 				opts.shm_id = val;
1744b521e17SJim Harris 				break;
1754b521e17SJim Harris 			case 'n':
176f56de7b8SShuhei Matsumoto 				opts.mem_channel = val;
1774b521e17SJim Harris 				break;
1784b521e17SJim Harris 			case 'p':
1793795c1cfSJim Harris 				opts.main_core = val;
1804b521e17SJim Harris 				break;
1814b521e17SJim Harris 			case 's':
182f56de7b8SShuhei Matsumoto 				opts.mem_size = val;
1834b521e17SJim Harris 				break;
184ad3634afSCurt Bruns 			case 't':
185ad3634afSCurt Bruns 				g_sleep_time = val;
186ad3634afSCurt Bruns 				break;
18790b54d76SJim Harris 			case 'q':
18890b54d76SJim Harris 				g_io_queue_size = val;
18990b54d76SJim Harris 				break;
1904b521e17SJim Harris 			default:
1914b521e17SJim Harris 				usage(argv[0]);
192cf3ed0e1Swanghailiangx 				exit(EXIT_FAILURE);
1934b521e17SJim Harris 			}
1944b521e17SJim Harris 		}
195f56de7b8SShuhei Matsumoto 	}
1964b521e17SJim Harris 
1971f5bbe02SDaniel Verkamp 	if (opts.shm_id < 0) {
1981f5bbe02SDaniel Verkamp 		fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]);
1991f5bbe02SDaniel Verkamp 		usage(argv[0]);
2001f5bbe02SDaniel Verkamp 		exit(1);
2011f5bbe02SDaniel Verkamp 	}
2021f5bbe02SDaniel Verkamp 
203fa3dd136SJim Harris 	opts.shutdown_cb = stub_shutdown;
2044b521e17SJim Harris 
20536287957SBen Walker 	ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id);
206bad2c8e8SChangpeng Liu 
207bad2c8e8SChangpeng Liu 	cleanup();
20869a762caSPawel Wodkowski 	spdk_app_fini();
2094b521e17SJim Harris 
210b9be940aSLance Hartmann 	return ch;
2114b521e17SJim Harris }
212