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 : :
18 : : struct ctrlr_entry {
19 : : struct spdk_nvme_ctrlr *ctrlr;
20 : : TAILQ_ENTRY(ctrlr_entry) link;
21 : : };
22 : :
23 : : static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
24 : :
25 : : static void
26 : 6 : cleanup(void)
27 : : {
28 : : struct ctrlr_entry *ctrlr_entry, *tmp;
29 : 6 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
30 : :
31 [ + + ]: 16 : TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
32 [ + + ]: 10 : TAILQ_REMOVE(&g_controllers, ctrlr_entry, link);
33 : 10 : spdk_nvme_cuse_unregister(ctrlr_entry->ctrlr);
34 : 10 : spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
35 : 10 : free(ctrlr_entry);
36 : : }
37 : :
38 [ + - ]: 6 : if (detach_ctx) {
39 : 6 : spdk_nvme_detach_poll(detach_ctx);
40 : : }
41 : 6 : }
42 : :
43 : : static void
44 : 0 : usage(char *executable_name)
45 : : {
46 [ # # ]: 0 : printf("%s [options]\n", executable_name);
47 [ # # ]: 0 : printf("options:\n");
48 [ # # ]: 0 : printf(" -i shared memory ID [required]\n");
49 [ # # ]: 0 : printf(" -m mask core mask for DPDK\n");
50 [ # # ]: 0 : printf(" -n channel number of memory channels used for DPDK\n");
51 [ # # ]: 0 : printf(" -p core main (primary) core for DPDK\n");
52 [ # # ]: 0 : printf(" -s size memory size in MB for DPDK\n");
53 [ # # ]: 0 : printf(" -t msec sleep time (ms) between checking for admin completions\n");
54 [ # # ]: 0 : printf(" -H show this usage\n");
55 : 0 : }
56 : :
57 : : static bool
58 : 10 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
59 : : struct spdk_nvme_ctrlr_opts *opts)
60 : : {
61 : : /*
62 : : * Set the io_queue_size to UINT16_MAX to initialize
63 : : * the controller with the possible largest queue size.
64 : : */
65 : 10 : opts->io_queue_size = UINT16_MAX;
66 : 10 : return true;
67 : : }
68 : :
69 : : static void
70 : 10 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
71 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
72 : : {
73 : : struct ctrlr_entry *entry;
74 : :
75 : 10 : entry = malloc(sizeof(struct ctrlr_entry));
76 [ - + ]: 10 : if (entry == NULL) {
77 [ # # # # ]: 0 : fprintf(stderr, "Malloc error\n");
78 : 0 : exit(1);
79 : : }
80 : :
81 : 10 : entry->ctrlr = ctrlr;
82 : 10 : TAILQ_INSERT_TAIL(&g_controllers, entry, link);
83 [ - + ]: 10 : if (spdk_nvme_cuse_register(ctrlr) != 0) {
84 [ # # # # ]: 0 : fprintf(stderr, "could not register ctrlr with cuse\n");
85 : : }
86 : 10 : }
87 : :
88 : : static int
89 : 263 : stub_sleep(void *arg)
90 : : {
91 : : struct ctrlr_entry *ctrlr_entry, *tmp;
92 : :
93 : 263 : usleep(g_sleep_time * 1000);
94 [ + + ]: 763 : TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp) {
95 : 500 : spdk_nvme_ctrlr_process_admin_completions(ctrlr_entry->ctrlr);
96 : : }
97 : 263 : return 0;
98 : : }
99 : :
100 : : static void
101 : 6 : stub_start(void *arg1)
102 : : {
103 : 6 : int shm_id = (intptr_t)arg1;
104 : :
105 : 6 : spdk_unaffinitize_thread();
106 : :
107 [ - + ]: 6 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
108 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
109 : 0 : exit(1);
110 : : }
111 : :
112 [ - + ]: 6 : snprintf(g_path, sizeof(g_path), "/var/run/spdk_stub%d", shm_id);
113 [ - + - + ]: 6 : if (mknod(g_path, S_IFREG, 0) != 0) {
114 [ # # # # ]: 0 : fprintf(stderr, "could not create sentinel file %s\n", g_path);
115 : 0 : exit(1);
116 : : }
117 : :
118 : 6 : g_poller = SPDK_POLLER_REGISTER(stub_sleep, NULL, 0);
119 : 6 : }
120 : :
121 : : static void
122 : 6 : stub_shutdown(void)
123 : : {
124 : 6 : spdk_poller_unregister(&g_poller);
125 [ - + ]: 6 : unlink(g_path);
126 : 6 : spdk_app_stop(0);
127 : 6 : }
128 : :
129 : : int
130 : 6 : main(int argc, char **argv)
131 : : {
132 : : int ch;
133 : 6 : struct spdk_app_opts opts = {};
134 : : long int val;
135 : :
136 : : /* default value in opts structure */
137 : 6 : spdk_app_opts_init(&opts, sizeof(opts));
138 : :
139 : 6 : opts.name = "stub";
140 : 6 : opts.rpc_addr = NULL;
141 : :
142 [ + + + + : 24 : while ((ch = getopt(argc, argv, "i:m:n:p:s:t:H")) != -1) {
+ + ]
143 [ + + ]: 18 : if (ch == 'm') {
144 : 6 : opts.reactor_mask = optarg;
145 [ + - - + ]: 12 : } else if (ch == '?' || ch == 'H') {
146 : 0 : usage(argv[0]);
147 : 0 : exit(EXIT_SUCCESS);
148 : : } else {
149 : 12 : val = spdk_strtol(optarg, 10);
150 [ - + ]: 12 : if (val < 0) {
151 [ # # # # ]: 0 : fprintf(stderr, "Converting a string to integer failed\n");
152 : 0 : exit(1);
153 : : }
154 [ + - - + : 12 : switch (ch) {
- - ]
155 : 6 : case 'i':
156 : 6 : opts.shm_id = val;
157 : 6 : break;
158 : 0 : case 'n':
159 : 0 : opts.mem_channel = val;
160 : 0 : break;
161 : 0 : case 'p':
162 : 0 : opts.main_core = val;
163 : 0 : break;
164 : 6 : case 's':
165 : 6 : opts.mem_size = val;
166 : 6 : break;
167 : 0 : case 't':
168 : 0 : g_sleep_time = val;
169 : 0 : break;
170 : 0 : default:
171 : 0 : usage(argv[0]);
172 : 0 : exit(EXIT_FAILURE);
173 : : }
174 : : }
175 : : }
176 : :
177 [ - + ]: 6 : if (opts.shm_id < 0) {
178 [ # # # # ]: 0 : fprintf(stderr, "%s: -i shared memory ID must be specified\n", argv[0]);
179 : 0 : usage(argv[0]);
180 : 0 : exit(1);
181 : : }
182 : :
183 : 6 : opts.shutdown_cb = stub_shutdown;
184 : :
185 : 6 : ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id);
186 : :
187 : 6 : cleanup();
188 : 6 : spdk_app_fini();
189 : :
190 : 6 : return ch;
191 : : }
|