Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/nvme.h"
9 : : #include "spdk/queue.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/util.h"
12 : : #include "spdk/log.h"
13 : : #include "spdk/rpc.h"
14 : :
15 : : static const char *g_rpc_addr = "/var/tmp/spdk.sock";
16 : :
17 : : struct dev_ctx {
18 : : TAILQ_ENTRY(dev_ctx) tailq;
19 : : bool is_new;
20 : : bool is_removed;
21 : : bool is_draining;
22 : : struct spdk_nvme_ctrlr *ctrlr;
23 : : struct spdk_nvme_ns *ns;
24 : : struct spdk_nvme_qpair *qpair;
25 : : uint32_t io_size_blocks;
26 : : uint64_t size_in_ios;
27 : : uint64_t io_completed;
28 : : uint64_t prev_io_completed;
29 : : uint64_t current_queue_depth;
30 : : uint64_t offset_in_ios;
31 : : char name[1024];
32 : : };
33 : :
34 : : struct perf_task {
35 : : struct dev_ctx *dev;
36 : : void *buf;
37 : : };
38 : :
39 : : static TAILQ_HEAD(, dev_ctx) g_devs = TAILQ_HEAD_INITIALIZER(g_devs);
40 : :
41 : : static uint64_t g_tsc_rate;
42 : :
43 : : static uint32_t g_io_size_bytes = 4096;
44 : : static int g_queue_depth = 4;
45 : : static int g_time_in_sec;
46 : : static int g_expected_insert_times = -1;
47 : : static int g_expected_removal_times = -1;
48 : : static int g_insert_times;
49 : : static int g_removal_times;
50 : : static int g_shm_id = -1;
51 : : static const char *g_iova_mode = NULL;
52 : : static uint64_t g_timeout_in_us = SPDK_SEC_TO_USEC;
53 : : static struct spdk_nvme_detach_ctx *g_detach_ctx;
54 : :
55 : : static bool g_wait_for_rpc = false;
56 : : static bool g_rpc_received = false;
57 : :
58 : : static void task_complete(struct perf_task *task);
59 : :
60 : : static void timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
61 : : struct spdk_nvme_qpair *qpair, uint16_t cid);
62 : :
63 : : static void
64 : 34 : register_dev(struct spdk_nvme_ctrlr *ctrlr)
65 : : {
66 : : struct dev_ctx *dev;
67 : 34 : const struct spdk_nvme_ctrlr_data *cdata = spdk_nvme_ctrlr_get_data(ctrlr);
68 : :
69 : 34 : dev = calloc(1, sizeof(*dev));
70 [ - + ]: 34 : if (dev == NULL) {
71 : 0 : perror("dev_ctx malloc");
72 : 0 : exit(1);
73 : : }
74 : :
75 [ - + ]: 34 : snprintf(dev->name, sizeof(dev->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
76 : :
77 : 34 : dev->ctrlr = ctrlr;
78 : 34 : dev->is_new = true;
79 : 34 : dev->is_removed = false;
80 : 34 : dev->is_draining = false;
81 : :
82 : 34 : spdk_nvme_ctrlr_register_timeout_callback(ctrlr, g_timeout_in_us, g_timeout_in_us, timeout_cb,
83 : : NULL);
84 : :
85 : 34 : dev->ns = spdk_nvme_ctrlr_get_ns(ctrlr, 1);
86 : :
87 [ + - - + ]: 34 : if (!dev->ns || !spdk_nvme_ns_is_active(dev->ns)) {
88 [ # # # # ]: 0 : fprintf(stderr, "Controller %s: No active namespace; skipping\n", dev->name);
89 : 0 : goto skip;
90 : : }
91 : :
92 [ + - ]: 34 : if (spdk_nvme_ns_get_size(dev->ns) < g_io_size_bytes ||
93 [ - + ]: 34 : spdk_nvme_ns_get_sector_size(dev->ns) > g_io_size_bytes) {
94 [ # # ]: 0 : fprintf(stderr, "Controller %s: Invalid "
95 : : "ns size %" PRIu64 " / block size %u for I/O size %u\n",
96 [ # # ]: 0 : dev->name,
97 : : spdk_nvme_ns_get_size(dev->ns),
98 : : spdk_nvme_ns_get_sector_size(dev->ns),
99 : : g_io_size_bytes);
100 : 0 : goto skip;
101 : : }
102 : :
103 [ - + ]: 34 : dev->size_in_ios = spdk_nvme_ns_get_size(dev->ns) / g_io_size_bytes;
104 [ - + ]: 34 : dev->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(dev->ns);
105 : :
106 : 34 : dev->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
107 [ - + ]: 34 : if (!dev->qpair) {
108 [ # # # # ]: 0 : fprintf(stderr, "ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
109 : 0 : goto skip;
110 : : }
111 : 34 : g_insert_times++;
112 : 34 : TAILQ_INSERT_TAIL(&g_devs, dev, tailq);
113 : 34 : return;
114 : :
115 : 0 : skip:
116 : 0 : free(dev);
117 : : }
118 : :
119 : : static void
120 : 34 : unregister_dev(struct dev_ctx *dev)
121 : : {
122 [ - + - + ]: 34 : fprintf(stderr, "unregister_dev: %s\n", dev->name);
123 : :
124 : 34 : spdk_nvme_ctrlr_free_io_qpair(dev->qpair);
125 : 34 : spdk_nvme_detach_async(dev->ctrlr, &g_detach_ctx);
126 : :
127 [ + + ]: 34 : TAILQ_REMOVE(&g_devs, dev, tailq);
128 : 34 : free(dev);
129 : 34 : }
130 : :
131 : : static struct perf_task *
132 : 112 : alloc_task(struct dev_ctx *dev)
133 : : {
134 : : struct perf_task *task;
135 : :
136 : 112 : task = calloc(1, sizeof(*task));
137 [ - + ]: 112 : if (task == NULL) {
138 : 0 : return NULL;
139 : : }
140 : :
141 : 112 : task->buf = spdk_dma_zmalloc(g_io_size_bytes, 0x200, NULL);
142 [ - + ]: 112 : if (task->buf == NULL) {
143 : 0 : free(task);
144 : 0 : return NULL;
145 : : }
146 : :
147 : 112 : task->dev = dev;
148 : :
149 : 112 : return task;
150 : : }
151 : :
152 : : static void
153 : 112 : free_task(struct perf_task *task)
154 : : {
155 : 112 : spdk_dma_free(task->buf);
156 : 112 : free(task);
157 : 112 : }
158 : :
159 : : static void io_complete(void *ctx, const struct spdk_nvme_cpl *completion);
160 : :
161 : : static void
162 : 687164 : submit_single_io(struct perf_task *task)
163 : : {
164 : 687164 : struct dev_ctx *dev = task->dev;
165 : : uint64_t offset_in_ios;
166 : : int rc;
167 : :
168 : 687164 : offset_in_ios = dev->offset_in_ios++;
169 [ - + ]: 687164 : if (dev->offset_in_ios == dev->size_in_ios) {
170 : 0 : dev->offset_in_ios = 0;
171 : : }
172 : :
173 : 1078417 : rc = spdk_nvme_ns_cmd_read(dev->ns, dev->qpair, task->buf,
174 : 687164 : offset_in_ios * dev->io_size_blocks,
175 : : dev->io_size_blocks, io_complete, task, 0);
176 : :
177 [ - + ]: 687164 : if (rc != 0) {
178 [ # # # # ]: 0 : fprintf(stderr, "starting I/O failed\n");
179 : 0 : free_task(task);
180 : : } else {
181 : 687164 : dev->current_queue_depth++;
182 : : }
183 : 687164 : }
184 : :
185 : : static void
186 : 687164 : task_complete(struct perf_task *task)
187 : : {
188 : : struct dev_ctx *dev;
189 : :
190 : 687164 : dev = task->dev;
191 : 687164 : dev->current_queue_depth--;
192 : 687164 : dev->io_completed++;
193 : :
194 : : /*
195 : : * is_draining indicates when time has expired for the test run
196 : : * and we are just waiting for the previously submitted I/O
197 : : * to complete. In this case, do not submit a new I/O to replace
198 : : * the one just completed.
199 : : */
200 [ + + + + : 687164 : if (!dev->is_draining && !dev->is_removed) {
- + + + ]
201 : 687052 : submit_single_io(task);
202 : : } else {
203 : 112 : free_task(task);
204 : : }
205 : 687164 : }
206 : :
207 : : static void
208 : 687164 : io_complete(void *ctx, const struct spdk_nvme_cpl *completion)
209 : : {
210 : 687164 : task_complete((struct perf_task *)ctx);
211 : 687164 : }
212 : :
213 : : static void
214 : 162698 : check_io(struct dev_ctx *dev)
215 : : {
216 : 162698 : spdk_nvme_qpair_process_completions(dev->qpair, 0);
217 : 162698 : }
218 : :
219 : : static void
220 : 28 : submit_io(struct dev_ctx *dev, int queue_depth)
221 : : {
222 : : struct perf_task *task;
223 : :
224 [ + + ]: 140 : while (queue_depth-- > 0) {
225 : 112 : task = alloc_task(dev);
226 [ - + ]: 112 : if (task == NULL) {
227 [ # # # # ]: 0 : fprintf(stderr, "task allocation failed\n");
228 : 0 : exit(1);
229 : : }
230 : :
231 : 112 : submit_single_io(task);
232 : : }
233 : 28 : }
234 : :
235 : : static void
236 : 10 : drain_io(struct dev_ctx *dev)
237 : : {
238 : 10 : dev->is_draining = true;
239 [ + + ]: 14 : while (dev->current_queue_depth > 0) {
240 : 4 : check_io(dev);
241 : : }
242 : 10 : }
243 : :
244 : : static void
245 : 146 : print_stats(void)
246 : : {
247 : : struct dev_ctx *dev;
248 : :
249 [ + + ]: 397 : TAILQ_FOREACH(dev, &g_devs, tailq) {
250 [ - + ]: 424 : fprintf(stderr, "%-43.43s: %10" PRIu64 " I/Os completed (+%" PRIu64 ")\n",
251 [ - + ]: 251 : dev->name,
252 : : dev->io_completed,
253 : 251 : dev->io_completed - dev->prev_io_completed);
254 : 251 : dev->prev_io_completed = dev->io_completed;
255 : : }
256 : :
257 [ - + ]: 146 : fprintf(stderr, "\n");
258 : 146 : }
259 : :
260 : : static bool
261 : 34 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
262 : : struct spdk_nvme_ctrlr_opts *opts)
263 : : {
264 [ - + - + ]: 34 : fprintf(stderr, "Attaching to %s\n", trid->traddr);
265 : :
266 : 34 : return true;
267 : : }
268 : :
269 : : static void
270 : 34 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
271 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
272 : : {
273 [ - + - + ]: 34 : fprintf(stderr, "Attached to %s\n", trid->traddr);
274 : :
275 : 34 : register_dev(ctrlr);
276 : 34 : }
277 : :
278 : : static void
279 : 27 : remove_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr)
280 : : {
281 : : struct dev_ctx *dev;
282 : :
283 [ + - ]: 35 : TAILQ_FOREACH(dev, &g_devs, tailq) {
284 [ + + ]: 35 : if (dev->ctrlr == ctrlr) {
285 : : /*
286 : : * Mark the device as removed, but don't detach yet.
287 : : *
288 : : * The I/O handling code will detach once it sees that
289 : : * is_removed is true and all outstanding I/O have been completed.
290 : : */
291 : 27 : dev->is_removed = true;
292 [ - + - + ]: 27 : fprintf(stderr, "Controller removed: %s\n", dev->name);
293 : 27 : return;
294 : : }
295 : : }
296 : :
297 : : /*
298 : : * If we get here, this remove_cb is for a controller that we are not tracking
299 : : * in g_devs (for example, because we skipped it during register_dev),
300 : : * so immediately detach it.
301 : : */
302 : 0 : spdk_nvme_detach_async(ctrlr, &g_detach_ctx);
303 : : }
304 : :
305 : : static void
306 : 0 : timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
307 : : struct spdk_nvme_qpair *qpair, uint16_t cid)
308 : : {
309 : : /* leave hotplug monitor loop, use the timeout_cb to monitor the hotplug */
310 [ # # ]: 0 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, remove_cb) != 0) {
311 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
312 : : }
313 : 0 : }
314 : :
315 : : static void
316 : 6 : io_loop(void)
317 : : {
318 : : struct dev_ctx *dev, *dev_tmp;
319 : : uint64_t tsc_end;
320 : : uint64_t next_stats_tsc;
321 : : int rc;
322 : :
323 [ - + ]: 6 : if (g_time_in_sec > 0) {
324 : 0 : tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate;
325 : : } else {
326 : : /* User specified 0 seconds for timeout, which means no timeout.
327 : : * So just set tsc_end to UINT64_MAX which ensures the loop
328 : : * will never time out.
329 : : */
330 : 6 : tsc_end = UINT64_MAX;
331 : : }
332 : :
333 : 6 : next_stats_tsc = spdk_get_ticks();
334 : :
335 : 95379 : while (1) {
336 : : uint64_t now;
337 : :
338 : : /*
339 : : * Check for completed I/O for each controller. A new
340 : : * I/O will be submitted in the io_complete callback
341 : : * to replace each I/O that is completed.
342 : : */
343 [ + + ]: 258079 : TAILQ_FOREACH(dev, &g_devs, tailq) {
344 [ + + + + ]: 162694 : if (dev->is_new) {
345 : : /* Submit initial I/O for this controller. */
346 : 28 : submit_io(dev, g_queue_depth);
347 : 28 : dev->is_new = false;
348 : : }
349 : :
350 : 162694 : check_io(dev);
351 : : }
352 : :
353 : : /*
354 : : * Check for hotplug events.
355 : : */
356 [ - + ]: 95385 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, remove_cb) != 0) {
357 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
358 : 0 : break;
359 : : }
360 : :
361 : : /*
362 : : * Check for devices which were hot-removed and have finished
363 : : * processing outstanding I/Os.
364 : : *
365 : : * unregister_dev() may remove devs from the list, so use the
366 : : * removal-safe iterator.
367 : : */
368 [ + + ]: 258103 : TAILQ_FOREACH_SAFE(dev, &g_devs, tailq, dev_tmp) {
369 [ + + + + : 162718 : if (dev->is_removed && dev->current_queue_depth == 0) {
+ + ]
370 : 24 : g_removal_times++;
371 : 24 : unregister_dev(dev);
372 : : }
373 : : }
374 : :
375 [ + + ]: 95385 : if (g_detach_ctx) {
376 : 24 : rc = spdk_nvme_detach_poll_async(g_detach_ctx);
377 [ + - ]: 24 : if (rc == 0) {
378 : 24 : g_detach_ctx = NULL;
379 : : }
380 : : }
381 : :
382 [ + + + - ]: 95385 : if (g_insert_times == g_expected_insert_times && g_removal_times == g_expected_removal_times) {
383 : 6 : break;
384 : : }
385 : :
386 : 95379 : now = spdk_get_ticks();
387 [ - + ]: 95379 : if (now > tsc_end) {
388 : 0 : SPDK_ERRLOG("Timing out hotplug application!\n");
389 : 0 : break;
390 : : }
391 [ + + ]: 95379 : if (now > next_stats_tsc) {
392 : 146 : print_stats();
393 : 146 : next_stats_tsc += g_tsc_rate;
394 : : }
395 : : }
396 : :
397 [ + + ]: 16 : TAILQ_FOREACH_SAFE(dev, &g_devs, tailq, dev_tmp) {
398 : 10 : drain_io(dev);
399 : 10 : unregister_dev(dev);
400 : : }
401 : :
402 [ + - ]: 6 : if (g_detach_ctx) {
403 : 6 : spdk_nvme_detach_poll(g_detach_ctx);
404 : : }
405 : 6 : }
406 : :
407 : : static void
408 : 0 : usage(char *program_name)
409 : : {
410 [ # # ]: 0 : printf("%s options", program_name);
411 : 0 : printf("\n");
412 [ # # ]: 0 : printf("\t[-c timeout for each command in second(default:1s)]\n");
413 [ # # ]: 0 : printf("\t[-i shm id (optional)]\n");
414 [ # # ]: 0 : printf("\t[-n expected hot insert times]\n");
415 [ # # ]: 0 : printf("\t[-r expected hot removal times]\n");
416 [ # # ]: 0 : printf("\t[-t time in seconds to wait for all events (default: forever)]\n");
417 [ # # ]: 0 : printf("\t[-m iova mode: pa or va (optional)\n");
418 [ # # ]: 0 : printf("\t[-l log level]\n");
419 [ # # ]: 0 : printf("\t Available log levels:\n");
420 [ # # ]: 0 : printf("\t disabled, error, warning, notice, info, debug\n");
421 [ # # ]: 0 : printf("\t[--wait-for-rpc wait for RPC perform_tests\n");
422 [ # # ]: 0 : printf("\t to proceed with starting IO on NVMe disks]\n");
423 : 0 : }
424 : :
425 : : static const struct option g_wait_option[] = {
426 : : #define WAIT_FOR_RPC_OPT_IDX 257
427 : : {"wait-for-rpc", no_argument, NULL, WAIT_FOR_RPC_OPT_IDX},
428 : : };
429 : :
430 : : static int
431 : 6 : parse_args(int argc, char **argv)
432 : : {
433 : 3 : int op, opt_idx;
434 : : long int val;
435 : :
436 : : /* default value */
437 : 6 : g_time_in_sec = 0;
438 : :
439 [ + + + + ]: 36 : while ((op = getopt_long(argc, argv, "c:i:l:m:n:r:t:", g_wait_option, &opt_idx)) != -1) {
440 [ - + ]: 30 : if (op == '?') {
441 : 0 : usage(argv[0]);
442 : 0 : return 1;
443 : : }
444 : :
445 [ - + - + : 30 : switch (op) {
- ]
446 : 0 : case WAIT_FOR_RPC_OPT_IDX:
447 : 0 : g_wait_for_rpc = true;
448 : 0 : break;
449 : 24 : case 'c':
450 : : case 'i':
451 : : case 'n':
452 : : case 'r':
453 : : case 't':
454 : 24 : val = spdk_strtol(optarg, 10);
455 [ - + ]: 24 : if (val < 0) {
456 [ # # ]: 0 : fprintf(stderr, "Converting a string to integer failed\n");
457 : 0 : return val;
458 : : }
459 : : switch (op) {
460 : 0 : case 'c':
461 : 0 : g_timeout_in_us = val * SPDK_SEC_TO_USEC;
462 : 0 : break;
463 : 6 : case 'i':
464 : 6 : g_shm_id = val;
465 : 6 : break;
466 : 6 : case 'n':
467 : 6 : g_expected_insert_times = val;
468 : 6 : break;
469 : 6 : case 'r':
470 : 6 : g_expected_removal_times = val;
471 : 6 : break;
472 : 6 : case 't':
473 : 6 : g_time_in_sec = val;
474 : 6 : break;
475 : : }
476 : 24 : break;
477 : 0 : case 'm':
478 : 0 : g_iova_mode = optarg;
479 : 0 : break;
480 : 6 : case 'l':
481 [ - + - + ]: 6 : if (!strcmp(optarg, "disabled")) {
482 : 0 : spdk_log_set_print_level(SPDK_LOG_DISABLED);
483 [ - + - + ]: 6 : } else if (!strcmp(optarg, "error")) {
484 : 0 : spdk_log_set_print_level(SPDK_LOG_ERROR);
485 [ + + + - ]: 6 : } else if (!strcmp(optarg, "warning")) {
486 : 6 : spdk_log_set_print_level(SPDK_LOG_WARN);
487 [ # # # # ]: 0 : } else if (!strcmp(optarg, "notice")) {
488 : 0 : spdk_log_set_print_level(SPDK_LOG_NOTICE);
489 [ # # # # ]: 0 : } else if (!strcmp(optarg, "info")) {
490 : 0 : spdk_log_set_print_level(SPDK_LOG_INFO);
491 [ # # # # ]: 0 : } else if (!strcmp(optarg, "debug")) {
492 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
493 : : } else {
494 [ # # ]: 0 : fprintf(stderr, "Unrecognized log level: %s\n", optarg);
495 : 0 : return 1;
496 : : }
497 : 6 : break;
498 : 0 : default:
499 : 0 : usage(argv[0]);
500 : 0 : return 1;
501 : : }
502 : : }
503 : :
504 : 6 : return 0;
505 : : }
506 : :
507 : :
508 : : static int
509 : 6 : register_controllers(void)
510 : : {
511 [ - + - + ]: 6 : fprintf(stderr, "Initializing NVMe Controllers\n");
512 : :
513 [ - + ]: 6 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, remove_cb) != 0) {
514 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
515 : 0 : return 1;
516 : : }
517 : : /* Reset g_insert_times to 0 so that we do not count controllers attached at start as hotplug events. */
518 : 6 : g_insert_times = 0;
519 : 6 : return 0;
520 : : }
521 : :
522 : : /* Hotplug RPC */
523 : : static void
524 : 0 : rpc_perform_tests(struct spdk_jsonrpc_request *request,
525 : : const struct spdk_json_val *params)
526 : : {
527 [ # # ]: 0 : if (params) {
528 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
529 : : "'perform_tests' requires no arguments");
530 : 0 : return;
531 : : }
532 : :
533 : 0 : spdk_jsonrpc_send_bool_response(request, true);
534 : :
535 : 0 : g_rpc_received = true;
536 : : }
537 : 6 : SPDK_RPC_REGISTER("perform_tests", rpc_perform_tests, SPDK_RPC_RUNTIME);
538 : :
539 : : static void
540 : 0 : wait_for_rpc_call(void)
541 : : {
542 [ # # # # ]: 0 : fprintf(stderr,
543 : : "Listening for perform_tests to start the application...\n");
544 : 0 : spdk_rpc_listen(g_rpc_addr);
545 : 0 : spdk_rpc_set_state(SPDK_RPC_RUNTIME);
546 : :
547 [ # # # # ]: 0 : while (!g_rpc_received) {
548 : 0 : spdk_rpc_accept();
549 : : }
550 : : /* Run spdk_rpc_accept() one more time to trigger
551 : : * spdk_jsonrpv_server_poll() and send the RPC response. */
552 : 0 : spdk_rpc_accept();
553 : 0 : }
554 : :
555 : : int
556 : 6 : main(int argc, char **argv)
557 : : {
558 : : int rc;
559 : 3 : struct spdk_env_opts opts;
560 : :
561 : 6 : rc = parse_args(argc, argv);
562 [ - + ]: 6 : if (rc != 0) {
563 : 0 : return rc;
564 : : }
565 : :
566 : 6 : spdk_env_opts_init(&opts);
567 : 6 : opts.name = "hotplug";
568 : 6 : opts.core_mask = "0x1";
569 [ + - ]: 6 : if (g_shm_id > -1) {
570 : 6 : opts.shm_id = g_shm_id;
571 : : }
572 [ - + ]: 6 : if (g_iova_mode) {
573 : 0 : opts.iova_mode = g_iova_mode;
574 : : }
575 [ - + ]: 6 : if (spdk_env_init(&opts) < 0) {
576 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
577 : 0 : return 1;
578 : : }
579 : :
580 : 6 : g_tsc_rate = spdk_get_ticks_hz();
581 : :
582 : : /* Detect the controllers that are plugged in at startup. */
583 [ - + ]: 6 : if (register_controllers() != 0) {
584 : 0 : rc = 1;
585 : 0 : goto cleanup;
586 : : }
587 : :
588 [ - + - + ]: 6 : if (g_wait_for_rpc) {
589 : 0 : wait_for_rpc_call();
590 : : }
591 : :
592 [ - + - + ]: 6 : fprintf(stderr, "Initialization complete. Starting I/O...\n");
593 : 6 : io_loop();
594 : :
595 [ + - - + ]: 6 : if (g_expected_insert_times != -1 && g_insert_times != g_expected_insert_times) {
596 [ # # # # ]: 0 : fprintf(stderr, "Expected inserts %d != actual inserts %d\n",
597 : : g_expected_insert_times, g_insert_times);
598 : 0 : rc = 1;
599 : 0 : goto cleanup;
600 : : }
601 : :
602 [ - + + - ]: 6 : if (g_expected_removal_times != -1 && g_removal_times != g_expected_removal_times) {
603 [ # # # # ]: 0 : fprintf(stderr, "Expected removals %d != actual removals %d\n",
604 : : g_expected_removal_times, g_removal_times);
605 : 0 : rc = 1;
606 : : }
607 : :
608 : 6 : cleanup:
609 : 6 : spdk_rpc_close();
610 : 6 : spdk_env_fini();
611 : 6 : return rc;
612 : : }
|