Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/event.h"
9 : : #include "spdk/nvme.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/thread.h"
12 : :
13 : : static char g_path[256];
14 : : static struct spdk_poller *g_poller;
15 : : /* default sleep time in ms */
16 : : static uint32_t g_sleep_time = 1000;
17 : : static uint32_t g_io_queue_size;
18 : :
19 : : struct ctrlr_entry {
20 : : struct spdk_nvme_ctrlr *ctrlr;
21 : : TAILQ_ENTRY(ctrlr_entry) link;
22 : : };
23 : :
24 : : static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
25 : :
26 : : static void
27 : 6 : cleanup(void)
28 : : {
29 : : struct ctrlr_entry *ctrlr_entry, *tmp;
30 : 6 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
31 : :
32 [ + + # # : 16 : TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
# # # # #
# ]
33 [ + + # # : 10 : TAILQ_REMOVE(&g_controllers, ctrlr_entry, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
34 [ # # # # ]: 10 : spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr);
35 [ # # # # ]: 10 : spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
36 : 10 : free(ctrlr_entry);
37 : 0 : }
38 : :
39 [ + - ]: 6 : if (detach_ctx) {
40 : 6 : spdk_nvme_detach_poll(detach_ctx);
41 : 0 : }
42 : 6 : }
43 : :
44 : : static void
45 : 0 : usage(char *executable_name)
46 : : {
47 [ # # ]: 0 : printf("%s [options]\n", executable_name);
48 [ # # ]: 0 : printf("options:\n");
49 [ # # ]: 0 : printf(" -i shared memory ID [required]\n");
50 [ # # ]: 0 : printf(" -m mask core mask for DPDK\n");
51 [ # # ]: 0 : printf(" -n channel number of memory channels used for DPDK\n");
52 [ # # ]: 0 : printf(" -L flag enable log flag\n");
53 [ # # ]: 0 : printf(" -p core main (primary) core for DPDK\n");
54 [ # # ]: 0 : printf(" -s size memory size in MB for DPDK\n");
55 [ # # ]: 0 : printf(" -t msec sleep time (ms) between checking for admin completions\n");
56 [ # # ]: 0 : printf(" -q size override default io_queue_size when attaching controllers\n");
57 [ # # ]: 0 : printf(" -H show this usage\n");
58 : 0 : }
59 : :
60 : : static bool
61 : 10 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
62 : : struct spdk_nvme_ctrlr_opts *opts)
63 : : {
64 [ - + ]: 10 : if (g_io_queue_size > 0) {
65 [ # # # # ]: 0 : opts->io_queue_size = g_io_queue_size;
66 : 0 : }
67 : 10 : return true;
68 : : }
69 : :
70 : : static void
71 : 10 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
72 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
73 : : {
74 : : struct ctrlr_entry *entry;
75 : :
76 : 10 : entry = malloc(sizeof(struct ctrlr_entry));
77 [ - + ]: 10 : if (entry == NULL) {
78 [ # # # # ]: 0 : fprintf(stderr, "Malloc error\n");
79 [ # # ]: 0 : exit(1);
80 : : }
81 : :
82 [ # # # # ]: 10 : entry->ctrlr = ctrlr;
83 [ # # # # : 10 : TAILQ_INSERT_TAIL(&g_controllers, entry, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
84 [ - + ]: 10 : if (spdk_nvme_cuse_register(ctrlr) != 0) {
85 [ # # # # ]: 0 : fprintf(stderr, "could not register ctrlr with cuse\n");
86 : 0 : }
87 : 10 : }
88 : :
89 : : static int
90 : 255 : stub_sleep(void *arg)
91 : : {
92 : : struct ctrlr_entry *ctrlr_entry, *tmp;
93 : :
94 : 255 : usleep(g_sleep_time * 1000);
95 [ + + # # : 740 : TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
# # # # #
# ]
96 [ # # # # ]: 485 : spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr);
97 : 0 : }
98 : 255 : return 0;
99 : : }
100 : :
101 : : static void
102 : 6 : stub_start(void *arg1)
103 : : {
104 : 6 : int shm_id = (intptr_t)arg1;
105 : :
106 [ - + ]: 6 : snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id);
107 : :
108 : : /* If sentinel file already exists from earlier crashed stub, delete
109 : : * it now to avoid mknod() failure after spdk_nvme_probe() completes.
110 : : */
111 [ - + ]: 6 : unlink(g_path);
112 : :
113 : 6 : spdk_unaffinitize_thread();
114 : :
115 [ - + ]: 6 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
116 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
117 [ # # ]: 0 : exit(1);
118 : : }
119 : :
120 [ - + - + ]: 6 : if (mknod(g_path, S_IFREG, 0) != 0) {
121 [ # # # # ]: 0 : fprintf(stderr, "could not create sentinel file %s\n", g_path);
122 [ # # ]: 0 : exit(1);
123 : : }
124 : :
125 : 6 : g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0);
126 : 6 : }
127 : :
128 : : static void
129 : 6 : stub_shutdown(void)
130 : : {
131 : 6 : spdk_poller_unregister(&g_poller);
132 [ - + ]: 6 : unlink(g_path);
133 : 6 : spdk_app_stop(0);
134 : 6 : }
135 : :
136 : : int
137 : 6 : main(int argc, char **argv)
138 : : {
139 : : int ch;
140 : 6 : struct spdk_app_opts opts = {};
141 : : long int val;
142 : :
143 : : /* default value in opts structure */
144 : 6 : spdk_app_opts_init(&opts, sizeof(opts));
145 : :
146 : 6 : opts.name = "stub";
147 : 6 : opts.rpc_addr = NULL;
148 : 6 : opts.env_context = "--proc-type=primary";
149 : :
150 [ + + + + : 24 : while ((ch = getopt(argc, argv, "i:m:n:p:q:s:t:HL:")) != -1) {
+ + ]
151 [ + + ]: 18 : if (ch == 'm') {
152 : 6 : opts.reactor_mask = optarg;
153 [ - + ]: 12 : } else if (ch == 'L') {
154 [ # # ]: 0 : if (spdk_log_set_flag(optarg) != 0) {
155 : 0 : SPDK_ERRLOG("unknown flag: %s\n", optarg);
156 [ # # # # ]: 0 : usage(argv[0]);
157 [ # # ]: 0 : exit(EXIT_FAILURE);
158 : : }
159 : : #ifdef DEBUG
160 : 0 : opts.print_level = SPDK_LOG_DEBUG;
161 : : #endif
162 [ + - - + ]: 12 : } else if (ch == '?' || ch == 'H') {
163 [ # # # # ]: 0 : usage(argv[0]);
164 [ # # ]: 0 : exit(EXIT_SUCCESS);
165 : : } else {
166 : 12 : val = spdk_strtol(optarg, 10);
167 [ - + ]: 12 : if (val < 0) {
168 [ # # # # ]: 0 : fprintf(stderr, "Converting a string to integer failed\n");
169 [ # # ]: 0 : exit(1);
170 : : }
171 [ + - - + : 12 : switch (ch) {
- - - ]
172 : 6 : case 'i':
173 : 6 : opts.shm_id = val;
174 : 6 : break;
175 : 0 : case 'n':
176 : 0 : opts.mem_channel = val;
177 : 0 : break;
178 : 0 : case 'p':
179 : 0 : opts.main_core = val;
180 : 0 : break;
181 : 6 : case 's':
182 : 6 : opts.mem_size = val;
183 : 6 : break;
184 : 0 : case 't':
185 : 0 : g_sleep_time = val;
186 : 0 : break;
187 : 0 : case 'q':
188 : 0 : g_io_queue_size = val;
189 : 0 : break;
190 : 0 : default:
191 [ # # # # ]: 0 : usage(argv[0]);
192 [ # # ]: 0 : exit(EXIT_FAILURE);
193 : : }
194 : : }
195 : : }
196 : :
197 [ - + ]: 6 : if (opts.shm_id < 0) {
198 [ # # # # ]: 0 : fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]);
199 [ # # # # ]: 0 : usage(argv[0]);
200 [ # # ]: 0 : exit(1);
201 : : }
202 : :
203 : 6 : opts.shutdown_cb = stub_shutdown;
204 : :
205 : 6 : ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id);
206 : :
207 : 6 : cleanup();
208 : 6 : spdk_app_fini();
209 : :
210 : 6 : return ch;
211 : : }
|