Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include "spdk_internal/cunit.h"
8 : :
9 : : #include "common/lib/ut_multithread.c"
10 : : #include "unit/lib/json_mock.c"
11 : :
12 : : #include "spdk/config.h"
13 : : /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */
14 : : #undef SPDK_CONFIG_VTUNE
15 : :
16 : : #include "bdev/bdev.c"
17 : :
18 : : #define BDEV_UT_NUM_THREADS 3
19 : :
20 [ - + - + ]: 272 : DEFINE_STUB(spdk_notify_send, uint64_t, (const char *type, const char *ctx), 0);
21 [ - + # # ]: 184 : DEFINE_STUB(spdk_notify_type_register, struct spdk_notify_type *, (const char *type), NULL);
22 : 0 : DEFINE_STUB_V(spdk_scsi_nvme_translate, (const struct spdk_bdev_io *bdev_io, int *sc, int *sk,
23 : : int *asc, int *ascq));
24 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_get_dma_device_id, const char *, (struct spdk_memory_domain *domain),
25 : : "test_domain");
26 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_get_dma_device_type, enum spdk_dma_device_type,
27 : : (struct spdk_memory_domain *domain), 0);
28 : 0 : DEFINE_STUB_V(spdk_accel_sequence_finish,
29 : : (struct spdk_accel_sequence *seq, spdk_accel_completion_cb cb_fn, void *cb_arg));
30 : 0 : DEFINE_STUB_V(spdk_accel_sequence_abort, (struct spdk_accel_sequence *seq));
31 : 0 : DEFINE_STUB_V(spdk_accel_sequence_reverse, (struct spdk_accel_sequence *seq));
32 [ # # # # ]: 0 : DEFINE_STUB(spdk_accel_append_copy, int,
33 : : (struct spdk_accel_sequence **seq, struct spdk_io_channel *ch, struct iovec *dst_iovs,
34 : : uint32_t dst_iovcnt, struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
35 : : struct iovec *src_iovs, uint32_t src_iovcnt, struct spdk_memory_domain *src_domain,
36 : : void *src_domain_ctx, spdk_accel_step_cb cb_fn, void *cb_arg), 0);
37 [ # # # # ]: 0 : DEFINE_STUB(spdk_accel_append_dif_verify_copy, int,
38 : : (struct spdk_accel_sequence **seq, struct spdk_io_channel *ch,
39 : : struct iovec *dst_iovs, size_t dst_iovcnt,
40 : : struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
41 : : struct iovec *src_iovs, size_t src_iovcnt,
42 : : struct spdk_memory_domain *src_domain, void *src_domain_ctx,
43 : : uint32_t num_blocks,
44 : : const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err,
45 : : spdk_accel_step_cb cb_fn, void *cb_arg), 0);
46 [ # # # # ]: 0 : DEFINE_STUB(spdk_accel_append_dif_generate_copy, int,
47 : : (struct spdk_accel_sequence **seq,
48 : : struct spdk_io_channel *ch,
49 : : struct iovec *dst_iovs, size_t dst_iovcnt,
50 : : struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
51 : : struct iovec *src_iovs, size_t src_iovcnt,
52 : : struct spdk_memory_domain *src_domain, void *src_domain_ctx,
53 : : uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
54 : : spdk_accel_step_cb cb_fn, void *cb_arg), 0);
55 [ # # # # ]: 0 : DEFINE_STUB(spdk_accel_get_memory_domain, struct spdk_memory_domain *, (void), NULL);
56 [ # # # # ]: 0 : DEFINE_STUB(spdk_accel_get_buf, int, (struct spdk_io_channel *ch, uint64_t len, void **buf,
57 : : struct spdk_memory_domain **domain, void **domain_ctx), 0);
58 : 0 : DEFINE_STUB_V(spdk_accel_put_buf, (struct spdk_io_channel *ch, void *buf,
59 : : struct spdk_memory_domain *domain, void *domain_ctx));
60 : :
61 [ # # ]: 0 : DEFINE_RETURN_MOCK(spdk_memory_domain_pull_data, int);
62 : : int
63 : 0 : spdk_memory_domain_pull_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
64 : : struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt,
65 : : spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
66 : : {
67 [ # # # # : 0 : HANDLE_RETURN_MOCK(spdk_memory_domain_pull_data);
# # ]
68 : :
69 : 0 : cpl_cb(cpl_cb_arg, 0);
70 : 0 : return 0;
71 : 0 : }
72 : :
73 [ # # ]: 0 : DEFINE_RETURN_MOCK(spdk_memory_domain_push_data, int);
74 : : int
75 : 0 : spdk_memory_domain_push_data(struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
76 : : struct iovec *dst_iov, uint32_t dst_iovcnt, struct iovec *src_iov, uint32_t src_iovcnt,
77 : : spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
78 : : {
79 [ # # # # : 0 : HANDLE_RETURN_MOCK(spdk_memory_domain_push_data);
# # ]
80 : :
81 : 0 : cpl_cb(cpl_cb_arg, 0);
82 : 0 : return 0;
83 : 0 : }
84 : :
85 : : static int g_accel_io_device;
86 : :
87 : : struct spdk_io_channel *
88 : 144 : spdk_accel_get_io_channel(void)
89 : : {
90 : 144 : return spdk_get_io_channel(&g_accel_io_device);
91 : : }
92 : :
93 : : struct ut_bdev {
94 : : struct spdk_bdev bdev;
95 : : void *io_target;
96 : : };
97 : :
98 : : struct ut_bdev_io {
99 : : TAILQ_ENTRY(ut_bdev_io) link;
100 : : };
101 : :
102 : : struct ut_bdev_channel {
103 : : TAILQ_HEAD(, ut_bdev_io) outstanding_io;
104 : : uint32_t outstanding_cnt;
105 : : uint32_t avail_cnt;
106 : : struct spdk_thread *thread;
107 : : TAILQ_ENTRY(ut_bdev_channel) link;
108 : : };
109 : :
110 : : int g_io_device;
111 : : struct ut_bdev g_bdev;
112 : : struct spdk_bdev_desc *g_desc;
113 : : bool g_teardown_done = false;
114 : : bool g_get_io_channel = true;
115 : : bool g_create_ch = true;
116 : : bool g_init_complete_called = false;
117 : : bool g_fini_start_called = true;
118 : : int g_status = 0;
119 : : int g_count = 0;
120 : : struct spdk_histogram_data *g_histogram = NULL;
121 : : TAILQ_HEAD(, ut_bdev_channel) g_ut_channels;
122 : :
123 : : static int
124 : 136 : ut_accel_ch_create_cb(void *io_device, void *ctx)
125 : : {
126 : 136 : return 0;
127 : : }
128 : :
129 : : static void
130 : 136 : ut_accel_ch_destroy_cb(void *io_device, void *ctx)
131 : : {
132 : 136 : }
133 : :
134 : : static int
135 : 144 : stub_create_ch(void *io_device, void *ctx_buf)
136 : : {
137 : 144 : struct ut_bdev_channel *ch = ctx_buf;
138 : :
139 [ + + + + ]: 144 : if (g_create_ch == false) {
140 : 4 : return -1;
141 : : }
142 : :
143 : 140 : TAILQ_INIT(&ch->outstanding_io);
144 : 140 : ch->outstanding_cnt = 0;
145 : : /*
146 : : * When avail gets to 0, the submit_request function will return ENOMEM.
147 : : * Most tests to not want ENOMEM to occur, so by default set this to a
148 : : * big value that won't get hit. The ENOMEM tests can then override this
149 : : * value to something much smaller to induce ENOMEM conditions.
150 : : */
151 : 140 : ch->avail_cnt = 2048;
152 : 140 : ch->thread = spdk_get_thread();
153 : :
154 : 140 : TAILQ_INSERT_TAIL(&g_ut_channels, ch, link);
155 : :
156 : 140 : return 0;
157 : 36 : }
158 : :
159 : : static void
160 : 140 : stub_destroy_ch(void *io_device, void *ctx_buf)
161 : : {
162 : 140 : struct ut_bdev_channel *ch = ctx_buf;
163 : :
164 [ + + ]: 140 : TAILQ_REMOVE(&g_ut_channels, ch, link);
165 : 140 : }
166 : :
167 : : static struct spdk_io_channel *
168 : 152 : stub_get_io_channel(void *ctx)
169 : : {
170 : 152 : struct ut_bdev *ut_bdev = ctx;
171 : :
172 [ + + + + ]: 152 : if (g_get_io_channel == true) {
173 : 148 : return spdk_get_io_channel(ut_bdev->io_target);
174 : : } else {
175 : 4 : return NULL;
176 : : }
177 : 38 : }
178 : :
179 : : static int
180 : 136 : stub_destruct(void *ctx)
181 : : {
182 : 136 : return 0;
183 : : }
184 : :
185 : : static void
186 : 44 : stub_reset_channel(void *ctx)
187 : : {
188 : 44 : struct ut_bdev_channel *ch = ctx;
189 : : struct ut_bdev_io *bio;
190 : :
191 [ + + ]: 124 : while (!TAILQ_EMPTY(&ch->outstanding_io)) {
192 : 80 : bio = TAILQ_FIRST(&ch->outstanding_io);
193 [ + + ]: 80 : TAILQ_REMOVE(&ch->outstanding_io, bio, link);
194 : 80 : ch->outstanding_cnt--;
195 : 80 : spdk_bdev_io_complete(spdk_bdev_io_from_ctx(bio), SPDK_BDEV_IO_STATUS_ABORTED);
196 : 80 : ch->avail_cnt++;
197 : : }
198 : 44 : }
199 : :
200 : : static void
201 : 568 : stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
202 : : {
203 : 568 : struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch), *tmp_ch;
204 : : struct spdk_bdev_io *io;
205 : : struct ut_bdev_io *bio;
206 : :
207 [ + + ]: 568 : if (bdev_io->type == SPDK_BDEV_IO_TYPE_RESET) {
208 [ + + ]: 76 : TAILQ_FOREACH(tmp_ch, &g_ut_channels, link) {
209 [ + + ]: 44 : if (spdk_get_thread() == tmp_ch->thread) {
210 : 32 : stub_reset_channel(tmp_ch);
211 : 8 : } else {
212 : 12 : spdk_thread_send_msg(tmp_ch->thread, stub_reset_channel, tmp_ch);
213 : : }
214 : 11 : }
215 [ + + ]: 544 : } else if (bdev_io->type == SPDK_BDEV_IO_TYPE_ABORT) {
216 [ + - ]: 8 : TAILQ_FOREACH(bio, &ch->outstanding_io, link) {
217 : 8 : io = spdk_bdev_io_from_ctx(bio);
218 [ + + ]: 8 : if (io == bdev_io->u.abort.bio_to_abort) {
219 [ - + ]: 8 : TAILQ_REMOVE(&ch->outstanding_io, bio, link);
220 : 8 : ch->outstanding_cnt--;
221 : 8 : spdk_bdev_io_complete(io, SPDK_BDEV_IO_STATUS_ABORTED);
222 : 8 : ch->avail_cnt++;
223 : :
224 : 8 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
225 : 8 : return;
226 : : }
227 : 0 : }
228 : :
229 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
230 : 0 : return;
231 : : }
232 : :
233 [ + + ]: 560 : if (ch->avail_cnt > 0) {
234 : 540 : TAILQ_INSERT_TAIL(&ch->outstanding_io, (struct ut_bdev_io *)bdev_io->driver_ctx, link);
235 : 540 : ch->outstanding_cnt++;
236 : 540 : ch->avail_cnt--;
237 : 135 : } else {
238 : 20 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
239 : : }
240 : 142 : }
241 : :
242 : : static uint32_t
243 : 216 : stub_complete_io(void *io_target, uint32_t num_to_complete)
244 : : {
245 : 216 : struct spdk_io_channel *_ch = spdk_get_io_channel(io_target);
246 : 216 : struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch);
247 : : struct ut_bdev_io *bio;
248 : : struct spdk_bdev_io *io;
249 : 216 : bool complete_all = (num_to_complete == 0);
250 : 216 : uint32_t num_completed = 0;
251 : :
252 [ + + + + ]: 668 : while (complete_all || num_completed < num_to_complete) {
253 [ + + ]: 580 : if (TAILQ_EMPTY(&ch->outstanding_io)) {
254 : 128 : break;
255 : : }
256 : 452 : bio = TAILQ_FIRST(&ch->outstanding_io);
257 [ + + ]: 452 : TAILQ_REMOVE(&ch->outstanding_io, bio, link);
258 : 452 : io = spdk_bdev_io_from_ctx(bio);
259 : 452 : ch->outstanding_cnt--;
260 : 452 : spdk_bdev_io_complete(io, SPDK_BDEV_IO_STATUS_SUCCESS);
261 : 452 : ch->avail_cnt++;
262 : 452 : num_completed++;
263 : : }
264 : 216 : spdk_put_io_channel(_ch);
265 : 216 : return num_completed;
266 : : }
267 : :
268 : : static bool
269 : 416 : stub_io_type_supported(void *ctx, enum spdk_bdev_io_type type)
270 : : {
271 : 416 : return true;
272 : : }
273 : :
274 : : static struct spdk_bdev_fn_table fn_table = {
275 : : .get_io_channel = stub_get_io_channel,
276 : : .destruct = stub_destruct,
277 : : .submit_request = stub_submit_request,
278 : : .io_type_supported = stub_io_type_supported,
279 : : };
280 : :
281 : : struct spdk_bdev_module bdev_ut_if;
282 : :
283 : : static int
284 : 92 : module_init(void)
285 : : {
286 : 92 : spdk_bdev_module_init_done(&bdev_ut_if);
287 : 92 : return 0;
288 : : }
289 : :
290 : : static void
291 : 92 : module_fini(void)
292 : : {
293 : 92 : }
294 : :
295 : : static void
296 : 92 : init_complete(void)
297 : : {
298 : 92 : g_init_complete_called = true;
299 : 92 : }
300 : :
301 : : static void
302 : 92 : fini_start(void)
303 : : {
304 : 92 : g_fini_start_called = true;
305 : 92 : }
306 : :
307 : : static int
308 : 184 : get_ctx_size(void)
309 : : {
310 : 184 : return sizeof(struct ut_bdev_io);
311 : : }
312 : :
313 : : struct spdk_bdev_module bdev_ut_if = {
314 : : .name = "bdev_ut",
315 : : .module_init = module_init,
316 : : .module_fini = module_fini,
317 : : .async_init = true,
318 : : .init_complete = init_complete,
319 : : .fini_start = fini_start,
320 : : .get_ctx_size = get_ctx_size,
321 : : };
322 : :
323 : 4 : SPDK_BDEV_MODULE_REGISTER(bdev_ut, &bdev_ut_if)
324 : :
325 : : static void
326 : 128 : register_bdev(struct ut_bdev *ut_bdev, char *name, void *io_target)
327 : : {
328 [ - + ]: 128 : memset(ut_bdev, 0, sizeof(*ut_bdev));
329 : :
330 : 128 : ut_bdev->io_target = io_target;
331 : 128 : ut_bdev->bdev.ctxt = ut_bdev;
332 : 128 : ut_bdev->bdev.name = name;
333 : 128 : ut_bdev->bdev.fn_table = &fn_table;
334 : 128 : ut_bdev->bdev.module = &bdev_ut_if;
335 : 128 : ut_bdev->bdev.blocklen = 4096;
336 : 128 : ut_bdev->bdev.blockcnt = 1024;
337 : :
338 : 128 : spdk_bdev_register(&ut_bdev->bdev);
339 : 128 : }
340 : :
341 : : static void
342 : 116 : unregister_bdev(struct ut_bdev *ut_bdev)
343 : : {
344 : : /* Handle any deferred messages. */
345 : 116 : poll_threads();
346 : 116 : spdk_bdev_unregister(&ut_bdev->bdev, NULL, NULL);
347 : : /* Handle the async bdev unregister. */
348 : 116 : poll_threads();
349 : 116 : }
350 : :
351 : : static void
352 : 88 : bdev_init_cb(void *done, int rc)
353 : : {
354 : 88 : CU_ASSERT(rc == 0);
355 : 88 : *(bool *)done = true;
356 : 88 : }
357 : :
358 : : static void
359 : 20 : _bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
360 : : void *event_ctx)
361 : : {
362 [ + + + ]: 20 : switch (type) {
363 : 12 : case SPDK_BDEV_EVENT_REMOVE:
364 [ + + ]: 16 : if (event_ctx != NULL) {
365 : 4 : *(bool *)event_ctx = true;
366 : 1 : }
367 : 16 : break;
368 : 3 : case SPDK_BDEV_EVENT_RESIZE:
369 [ + - ]: 4 : if (event_ctx != NULL) {
370 : 4 : *(int *)event_ctx += 1;
371 : 1 : }
372 : 4 : break;
373 : 0 : default:
374 : 0 : CU_ASSERT(false);
375 : 0 : break;
376 : : }
377 : 20 : }
378 : :
379 : : static void
380 : 88 : setup_test(void)
381 : : {
382 : 88 : bool done = false;
383 : : int rc;
384 : :
385 : 88 : TAILQ_INIT(&g_ut_channels);
386 : :
387 : 88 : allocate_cores(BDEV_UT_NUM_THREADS);
388 : 88 : allocate_threads(BDEV_UT_NUM_THREADS);
389 : 88 : set_thread(0);
390 : :
391 : 88 : rc = spdk_iobuf_initialize();
392 : 88 : CU_ASSERT(rc == 0);
393 : 88 : spdk_bdev_initialize(bdev_init_cb, &done);
394 : 88 : spdk_io_device_register(&g_io_device, stub_create_ch, stub_destroy_ch,
395 : : sizeof(struct ut_bdev_channel), NULL);
396 : 88 : spdk_io_device_register(&g_accel_io_device, ut_accel_ch_create_cb,
397 : : ut_accel_ch_destroy_cb, 0, NULL);
398 : 88 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
399 : 88 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
400 : 88 : }
401 : :
402 : : static void
403 : 180 : finish_cb(void *cb_arg)
404 : : {
405 : 180 : g_teardown_done = true;
406 : 180 : }
407 : :
408 : : static void
409 : 84 : teardown_test(void)
410 : : {
411 : 84 : set_thread(0);
412 : 84 : g_teardown_done = false;
413 : 84 : spdk_bdev_close(g_desc);
414 : 84 : g_desc = NULL;
415 : 84 : unregister_bdev(&g_bdev);
416 : 84 : spdk_io_device_unregister(&g_io_device, NULL);
417 : 84 : spdk_bdev_finish(finish_cb, NULL);
418 : 84 : spdk_io_device_unregister(&g_accel_io_device, NULL);
419 : 84 : spdk_iobuf_finish(finish_cb, NULL);
420 : 84 : poll_threads();
421 [ - + ]: 84 : memset(&g_bdev, 0, sizeof(g_bdev));
422 [ - + ]: 84 : CU_ASSERT(g_teardown_done == true);
423 : 84 : g_teardown_done = false;
424 : 84 : free_threads();
425 : 84 : free_cores();
426 : 84 : CU_ASSERT(TAILQ_EMPTY(&g_ut_channels))
427 : 84 : }
428 : :
429 : : static uint32_t
430 : 28 : bdev_io_tailq_cnt(bdev_io_tailq_t *tailq)
431 : : {
432 : : struct spdk_bdev_io *io;
433 : 28 : uint32_t cnt = 0;
434 : :
435 [ + + ]: 1000 : TAILQ_FOREACH(io, tailq, internal.link) {
436 : 972 : cnt++;
437 : 243 : }
438 : :
439 : 28 : return cnt;
440 : : }
441 : :
442 : : static void
443 : 4 : basic(void)
444 : : {
445 : 4 : g_init_complete_called = false;
446 : 4 : setup_test();
447 [ - + ]: 4 : CU_ASSERT(g_init_complete_called == true);
448 : :
449 : 4 : set_thread(0);
450 : :
451 : 4 : g_get_io_channel = false;
452 : 4 : g_ut_threads[0].ch = spdk_bdev_get_io_channel(g_desc);
453 : 4 : CU_ASSERT(g_ut_threads[0].ch == NULL);
454 : :
455 : 4 : g_get_io_channel = true;
456 : 4 : g_create_ch = false;
457 : 4 : g_ut_threads[0].ch = spdk_bdev_get_io_channel(g_desc);
458 : 4 : CU_ASSERT(g_ut_threads[0].ch == NULL);
459 : :
460 : 4 : g_get_io_channel = true;
461 : 4 : g_create_ch = true;
462 : 4 : g_ut_threads[0].ch = spdk_bdev_get_io_channel(g_desc);
463 : 4 : CU_ASSERT(g_ut_threads[0].ch != NULL);
464 : 4 : spdk_put_io_channel(g_ut_threads[0].ch);
465 : :
466 : 4 : g_fini_start_called = false;
467 : 4 : teardown_test();
468 [ - + ]: 4 : CU_ASSERT(g_fini_start_called == true);
469 : 4 : }
470 : :
471 : : static void
472 : 20 : _bdev_unregistered(void *done, int rc)
473 : : {
474 : 20 : CU_ASSERT(rc == 0);
475 : 20 : *(bool *)done = true;
476 : 20 : }
477 : :
478 : : static void
479 : 4 : unregister_and_close(void)
480 : : {
481 : 3 : bool done, remove_notify;
482 : 4 : struct spdk_bdev_desc *desc = NULL;
483 : :
484 : 4 : setup_test();
485 : 4 : set_thread(0);
486 : :
487 : : /* setup_test() automatically opens the bdev,
488 : : * but this test needs to do that in a different
489 : : * way. */
490 : 4 : spdk_bdev_close(g_desc);
491 : 4 : poll_threads();
492 : :
493 : : /* Try hotremoving a bdev with descriptors which don't provide
494 : : * any context to the notification callback */
495 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &desc);
496 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(desc != NULL);
497 : :
498 : : /* There is an open descriptor on the device. Unregister it,
499 : : * which can't proceed until the descriptor is closed. */
500 : 4 : done = false;
501 : 4 : spdk_bdev_unregister(&g_bdev.bdev, _bdev_unregistered, &done);
502 : :
503 : : /* Poll the threads to allow all events to be processed */
504 : 4 : poll_threads();
505 : :
506 : : /* Make sure the bdev was not unregistered. We still have a
507 : : * descriptor open */
508 [ - + ]: 4 : CU_ASSERT(done == false);
509 : :
510 : 4 : spdk_bdev_close(desc);
511 : 4 : poll_threads();
512 : 4 : desc = NULL;
513 : :
514 : : /* The unregister should have completed */
515 [ - + ]: 4 : CU_ASSERT(done == true);
516 : :
517 : :
518 : : /* Register the bdev again */
519 : 4 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
520 : :
521 : 4 : remove_notify = false;
522 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, &remove_notify, &desc);
523 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(desc != NULL);
524 [ - + ]: 4 : CU_ASSERT(remove_notify == false);
525 : :
526 : : /* There is an open descriptor on the device. Unregister it,
527 : : * which can't proceed until the descriptor is closed. */
528 : 4 : done = false;
529 : 4 : spdk_bdev_unregister(&g_bdev.bdev, _bdev_unregistered, &done);
530 : : /* No polling has occurred, so neither of these should execute */
531 [ - + ]: 4 : CU_ASSERT(remove_notify == false);
532 [ - + ]: 4 : CU_ASSERT(done == false);
533 : :
534 : : /* Prior to the unregister completing, close the descriptor */
535 : 4 : spdk_bdev_close(desc);
536 : :
537 : : /* Poll the threads to allow all events to be processed */
538 : 4 : poll_threads();
539 : :
540 : : /* Remove notify should not have been called because the
541 : : * descriptor is already closed. */
542 [ - + ]: 4 : CU_ASSERT(remove_notify == false);
543 : :
544 : : /* The unregister should have completed */
545 [ - + ]: 4 : CU_ASSERT(done == true);
546 : :
547 : : /* Restore the original g_bdev so that we can use teardown_test(). */
548 : 4 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
549 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
550 : 4 : teardown_test();
551 : 4 : }
552 : :
553 : : static void
554 : 4 : unregister_and_close_different_threads(void)
555 : : {
556 : 3 : bool done;
557 : 4 : struct spdk_bdev_desc *desc = NULL;
558 : :
559 : 4 : setup_test();
560 : 4 : set_thread(0);
561 : :
562 : : /* setup_test() automatically opens the bdev,
563 : : * but this test needs to do that in a different
564 : : * way. */
565 : 4 : spdk_bdev_close(g_desc);
566 : 4 : poll_threads();
567 : :
568 : 4 : set_thread(1);
569 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &desc);
570 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(desc != NULL);
571 : 4 : done = false;
572 : :
573 : 4 : set_thread(0);
574 : 4 : spdk_bdev_unregister(&g_bdev.bdev, _bdev_unregistered, &done);
575 : :
576 : : /* Poll the threads to allow all events to be processed */
577 : 4 : poll_threads();
578 : :
579 : : /* Make sure the bdev was not unregistered. We still have a
580 : : * descriptor open */
581 [ - + ]: 4 : CU_ASSERT(done == false);
582 : :
583 : : /* Close the descriptor on thread 1. Poll the thread and confirm the
584 : : * unregister did not complete, since it was unregistered on thread 0.
585 : : */
586 : 4 : set_thread(1);
587 : 4 : spdk_bdev_close(desc);
588 : 4 : poll_thread(1);
589 [ - + ]: 4 : CU_ASSERT(done == false);
590 : :
591 : : /* Now poll thread 0 and confirm the unregister completed. */
592 : 4 : set_thread(0);
593 : 4 : poll_thread(0);
594 [ - + ]: 4 : CU_ASSERT(done == true);
595 : :
596 : : /* Restore the original g_bdev so that we can use teardown_test(). */
597 : 4 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
598 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
599 : 4 : teardown_test();
600 : 4 : }
601 : :
602 : : static void
603 : 8 : reset_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
604 : : {
605 : 8 : bool *done = cb_arg;
606 : :
607 : 8 : CU_ASSERT(success == true);
608 : 8 : *done = true;
609 : 8 : spdk_bdev_free_io(bdev_io);
610 : 8 : }
611 : :
612 : : static void
613 : 4 : put_channel_during_reset(void)
614 : : {
615 : : struct spdk_io_channel *io_ch;
616 : 4 : bool done = false;
617 : :
618 : 4 : setup_test();
619 : :
620 : 4 : set_thread(0);
621 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
622 : 4 : CU_ASSERT(io_ch != NULL);
623 : :
624 : : /*
625 : : * Start a reset, but then put the I/O channel before
626 : : * the deferred messages for the reset get a chance to
627 : : * execute.
628 : : */
629 : 4 : spdk_bdev_reset(g_desc, io_ch, reset_done, &done);
630 : 4 : spdk_put_io_channel(io_ch);
631 : 4 : poll_threads();
632 : 4 : stub_complete_io(g_bdev.io_target, 0);
633 : :
634 : 4 : teardown_test();
635 : 4 : }
636 : :
637 : : static void
638 : 16 : aborted_reset_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
639 : : {
640 : 16 : enum spdk_bdev_io_status *status = cb_arg;
641 : :
642 [ + + ]: 16 : *status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
643 : 16 : spdk_bdev_free_io(bdev_io);
644 : 16 : }
645 : :
646 : : static void io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
647 : :
648 : : static void
649 : 4 : aborted_reset(void)
650 : : {
651 : : struct spdk_io_channel *io_ch[2];
652 : 4 : enum spdk_bdev_io_status status1 = SPDK_BDEV_IO_STATUS_PENDING,
653 : 4 : status2 = SPDK_BDEV_IO_STATUS_PENDING;
654 : :
655 : 4 : setup_test();
656 : :
657 : 4 : set_thread(0);
658 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
659 : 4 : CU_ASSERT(io_ch[0] != NULL);
660 : 4 : spdk_bdev_reset(g_desc, io_ch[0], aborted_reset_done, &status1);
661 : 4 : poll_threads();
662 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress != NULL);
663 : :
664 : : /*
665 : : * First reset has been submitted on ch0. Now submit a second
666 : : * reset on ch1 which will get queued since there is already a
667 : : * reset in progress.
668 : : */
669 : 4 : set_thread(1);
670 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
671 : 4 : CU_ASSERT(io_ch[1] != NULL);
672 : 4 : spdk_bdev_reset(g_desc, io_ch[1], aborted_reset_done, &status2);
673 : 4 : poll_threads();
674 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress != NULL);
675 : :
676 : : /*
677 : : * Now destroy ch1. This will abort the queued reset. Check that
678 : : * the second reset was completed with failed status. Also check
679 : : * that bdev->internal.reset_in_progress != NULL, since the
680 : : * original reset has not been completed yet. This ensures that
681 : : * the bdev code is correctly noticing that the failed reset is
682 : : * *not* the one that had been submitted to the bdev module.
683 : : */
684 : 4 : set_thread(1);
685 : 4 : spdk_put_io_channel(io_ch[1]);
686 : 4 : poll_threads();
687 : 4 : CU_ASSERT(status2 == SPDK_BDEV_IO_STATUS_FAILED);
688 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress != NULL);
689 : :
690 : : /*
691 : : * Now complete the first reset, verify that it completed with SUCCESS
692 : : * status and that bdev->internal.reset_in_progress is also set back to NULL.
693 : : */
694 : 4 : set_thread(0);
695 : 4 : spdk_put_io_channel(io_ch[0]);
696 : 4 : stub_complete_io(g_bdev.io_target, 0);
697 : 4 : poll_threads();
698 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_SUCCESS);
699 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
700 : :
701 : 4 : teardown_test();
702 : 4 : }
703 : :
704 : : static void
705 : 4 : aborted_reset_no_outstanding_io(void)
706 : : {
707 : : struct spdk_io_channel *io_ch[2];
708 : : struct spdk_bdev_channel *bdev_ch[2];
709 : : struct spdk_bdev *bdev[2];
710 : 4 : enum spdk_bdev_io_status status1 = SPDK_BDEV_IO_STATUS_PENDING,
711 : 4 : status2 = SPDK_BDEV_IO_STATUS_PENDING;
712 : :
713 : 4 : setup_test();
714 : :
715 : : /*
716 : : * This time we test the reset without any outstanding IO
717 : : * present on the bdev channel, so both resets should finish
718 : : * immediately.
719 : : */
720 : :
721 : 4 : set_thread(0);
722 : : /* Set reset_io_drain_timeout to allow bdev
723 : : * reset to stay pending until we call abort. */
724 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
725 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
726 : 4 : bdev[0] = bdev_ch[0]->bdev;
727 : 4 : bdev[0]->reset_io_drain_timeout = SPDK_BDEV_RESET_IO_DRAIN_RECOMMENDED_VALUE;
728 : 4 : CU_ASSERT(io_ch[0] != NULL);
729 : 4 : spdk_bdev_reset(g_desc, io_ch[0], aborted_reset_done, &status1);
730 : 4 : poll_threads();
731 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
732 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_SUCCESS);
733 : 4 : spdk_put_io_channel(io_ch[0]);
734 : :
735 : 4 : set_thread(1);
736 : : /* Set reset_io_drain_timeout to allow bdev
737 : : * reset to stay pending until we call abort. */
738 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
739 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
740 : 4 : bdev[1] = bdev_ch[1]->bdev;
741 : 4 : bdev[1]->reset_io_drain_timeout = SPDK_BDEV_RESET_IO_DRAIN_RECOMMENDED_VALUE;
742 : 4 : CU_ASSERT(io_ch[1] != NULL);
743 : 4 : spdk_bdev_reset(g_desc, io_ch[1], aborted_reset_done, &status2);
744 : 4 : poll_threads();
745 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
746 : 4 : CU_ASSERT(status2 == SPDK_BDEV_IO_STATUS_SUCCESS);
747 : 4 : spdk_put_io_channel(io_ch[1]);
748 : :
749 : 4 : stub_complete_io(g_bdev.io_target, 0);
750 : 4 : poll_threads();
751 : :
752 : 4 : teardown_test();
753 : 4 : }
754 : :
755 : :
756 : : static void
757 : 148 : io_during_io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
758 : : {
759 : 148 : enum spdk_bdev_io_status *status = cb_arg;
760 : :
761 : 148 : *status = bdev_io->internal.status;
762 : 148 : spdk_bdev_free_io(bdev_io);
763 : 148 : }
764 : :
765 : : static void
766 : 4 : io_during_reset(void)
767 : : {
768 : : struct spdk_io_channel *io_ch[2];
769 : : struct spdk_bdev_channel *bdev_ch[2];
770 : 3 : enum spdk_bdev_io_status status0, status1, status_reset;
771 : : int rc;
772 : :
773 : 4 : setup_test();
774 : :
775 : : /*
776 : : * First test normal case - submit an I/O on each of two channels (with no resets)
777 : : * and verify they complete successfully.
778 : : */
779 : 4 : set_thread(0);
780 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
781 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
782 : 4 : CU_ASSERT(bdev_ch[0]->flags == 0);
783 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
784 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status0);
785 : 4 : CU_ASSERT(rc == 0);
786 : :
787 : 4 : set_thread(1);
788 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
789 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
790 : 4 : CU_ASSERT(bdev_ch[1]->flags == 0);
791 : 4 : status1 = SPDK_BDEV_IO_STATUS_PENDING;
792 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status1);
793 : 4 : CU_ASSERT(rc == 0);
794 : :
795 : 4 : poll_threads();
796 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_PENDING);
797 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_PENDING);
798 : :
799 : 4 : set_thread(0);
800 : 4 : stub_complete_io(g_bdev.io_target, 0);
801 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_SUCCESS);
802 : :
803 : 4 : set_thread(1);
804 : 4 : stub_complete_io(g_bdev.io_target, 0);
805 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_SUCCESS);
806 : :
807 : : /*
808 : : * Now submit a reset, and leave it pending while we submit I/O on two different
809 : : * channels. These I/O should be failed by the bdev layer since the reset is in
810 : : * progress.
811 : : */
812 : 4 : set_thread(0);
813 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
814 : 4 : rc = spdk_bdev_reset(g_desc, io_ch[0], io_during_io_done, &status_reset);
815 : 4 : CU_ASSERT(rc == 0);
816 : :
817 : 4 : CU_ASSERT(bdev_ch[0]->flags == 0);
818 : 4 : CU_ASSERT(bdev_ch[1]->flags == 0);
819 : 4 : poll_threads();
820 : 4 : CU_ASSERT(bdev_ch[0]->flags == BDEV_CH_RESET_IN_PROGRESS);
821 : 4 : CU_ASSERT(bdev_ch[1]->flags == BDEV_CH_RESET_IN_PROGRESS);
822 : :
823 : 4 : set_thread(0);
824 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
825 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status0);
826 : 4 : CU_ASSERT(rc == 0);
827 : :
828 : 4 : set_thread(1);
829 : 4 : status1 = SPDK_BDEV_IO_STATUS_PENDING;
830 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status1);
831 : 4 : CU_ASSERT(rc == 0);
832 : :
833 : : /*
834 : : * A reset is in progress so these read I/O should complete with aborted. Note that we
835 : : * need to poll_threads() since I/O completed inline have their completion deferred.
836 : : */
837 : 4 : poll_threads();
838 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_PENDING);
839 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_ABORTED);
840 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_ABORTED);
841 : :
842 : : /*
843 : : * Complete the reset
844 : : */
845 : 4 : set_thread(0);
846 : 4 : stub_complete_io(g_bdev.io_target, 0);
847 : :
848 : : /*
849 : : * Only poll thread 0. We should not get a completion.
850 : : */
851 : 4 : poll_thread(0);
852 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_PENDING);
853 : :
854 : : /*
855 : : * Poll both thread 0 and 1 so the messages can propagate and we
856 : : * get a completion.
857 : : */
858 : 4 : poll_threads();
859 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_SUCCESS);
860 : :
861 : 4 : spdk_put_io_channel(io_ch[0]);
862 : 4 : set_thread(1);
863 : 4 : spdk_put_io_channel(io_ch[1]);
864 : 4 : poll_threads();
865 : :
866 : 4 : teardown_test();
867 : 4 : }
868 : :
869 : : static uint32_t
870 : 56 : count_queued_resets(void *io_target)
871 : : {
872 : 56 : struct spdk_io_channel *_ch = spdk_get_io_channel(io_target);
873 : 56 : struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch);
874 : : struct ut_bdev_io *bio;
875 : : struct spdk_bdev_io *io;
876 : 56 : uint32_t submitted_resets = 0;
877 : :
878 [ + + ]: 100 : TAILQ_FOREACH(bio, &ch->outstanding_io, link) {
879 : 44 : io = spdk_bdev_io_from_ctx(bio);
880 [ + + ]: 44 : if (io->type == SPDK_BDEV_IO_TYPE_RESET) {
881 : 8 : submitted_resets++;
882 : 2 : }
883 : 11 : }
884 : :
885 : 56 : spdk_put_io_channel(_ch);
886 : :
887 : 56 : return submitted_resets;
888 : : }
889 : :
890 : : static void
891 : 4 : reset_completions(void)
892 : : {
893 : : struct spdk_io_channel *io_ch;
894 : : struct spdk_bdev_channel *bdev_ch;
895 : : struct spdk_bdev *bdev;
896 : 3 : enum spdk_bdev_io_status status0, status_reset;
897 : : int rc, iter;
898 : :
899 : 4 : setup_test();
900 : :
901 : : /* This test covers four test cases:
902 : : * 1) reset_io_drain_timeout of a bdev is greater than 0
903 : : * 2) No outstandind IO are present on any bdev channel
904 : : * 3) Outstanding IO finish during bdev reset
905 : : * 4) Outstanding IO do not finish before reset is done waiting
906 : : * for them.
907 : : *
908 : : * Above conditions mainly affect the timing of bdev reset completion
909 : : * and whether a reset should be skipped via spdk_bdev_io_complete()
910 : : * or sent down to the underlying bdev module via bdev_io_submit_reset(). */
911 : :
912 : : /* Test preparation */
913 : 4 : set_thread(0);
914 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
915 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
916 : 4 : CU_ASSERT(bdev_ch->flags == 0);
917 : :
918 : :
919 : : /* Test case 1) reset_io_drain_timeout set to 0. Reset should be sent down immediately. */
920 : 4 : bdev = &g_bdev.bdev;
921 : 4 : bdev->reset_io_drain_timeout = 0;
922 : :
923 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
924 : 4 : rc = spdk_bdev_reset(g_desc, io_ch, io_during_io_done, &status_reset);
925 : 4 : CU_ASSERT(rc == 0);
926 : 4 : poll_threads();
927 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 1);
928 : :
929 : : /* Call reset completion inside bdev module. */
930 : 4 : stub_complete_io(g_bdev.io_target, 0);
931 : 4 : poll_threads();
932 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
933 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_SUCCESS);
934 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
935 : :
936 : :
937 : : /* Test case 2) no outstanding IO are present. Reset should perform one iteration over
938 : : * channels and then be skipped. */
939 : 4 : bdev->reset_io_drain_timeout = SPDK_BDEV_RESET_IO_DRAIN_RECOMMENDED_VALUE;
940 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
941 : :
942 : 4 : rc = spdk_bdev_reset(g_desc, io_ch, io_during_io_done, &status_reset);
943 : 4 : CU_ASSERT(rc == 0);
944 : 4 : poll_threads();
945 : : /* Reset was never submitted to the bdev module. */
946 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
947 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_SUCCESS);
948 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
949 : :
950 : :
951 : : /* Test case 3) outstanding IO finish during bdev reset procedure. Reset should initiate
952 : : * wait poller to check for IO completions every second, until reset_io_drain_timeout is
953 : : * reached, but finish earlier than this threshold. */
954 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
955 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
956 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, io_during_io_done, &status0);
957 : 4 : CU_ASSERT(rc == 0);
958 : :
959 : 4 : rc = spdk_bdev_reset(g_desc, io_ch, io_during_io_done, &status_reset);
960 : 4 : CU_ASSERT(rc == 0);
961 : 4 : poll_threads();
962 : : /* The reset just started and should not have been submitted yet. */
963 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
964 : :
965 : 4 : poll_threads();
966 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_PENDING);
967 : : /* Let the poller wait for about half the time then complete outstanding IO. */
968 [ + + ]: 12 : for (iter = 0; iter < 2; iter++) {
969 : : /* Reset is still processing and not submitted at this point. */
970 : 8 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
971 : 8 : spdk_delay_us(1000 * 1000);
972 : 8 : poll_threads();
973 : 8 : poll_threads();
974 : 2 : }
975 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_PENDING);
976 : 4 : stub_complete_io(g_bdev.io_target, 0);
977 : 4 : poll_threads();
978 : 4 : spdk_delay_us(BDEV_RESET_CHECK_OUTSTANDING_IO_PERIOD);
979 : 4 : poll_threads();
980 : 4 : poll_threads();
981 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_SUCCESS);
982 : : /* Sending reset to the bdev module has been skipped. */
983 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
984 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
985 : :
986 : :
987 : : /* Test case 4) outstanding IO are still present after reset_io_drain_timeout
988 : : * seconds have passed. */
989 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
990 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
991 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, io_during_io_done, &status0);
992 : 4 : CU_ASSERT(rc == 0);
993 : :
994 : 4 : rc = spdk_bdev_reset(g_desc, io_ch, io_during_io_done, &status_reset);
995 : 4 : CU_ASSERT(rc == 0);
996 : 4 : poll_threads();
997 : : /* The reset just started and should not have been submitted yet. */
998 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
999 : :
1000 : 4 : poll_threads();
1001 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_PENDING);
1002 : : /* Let the poller wait for reset_io_drain_timeout seconds. */
1003 [ + + ]: 24 : for (iter = 0; iter < bdev->reset_io_drain_timeout; iter++) {
1004 : 20 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 0);
1005 : 20 : spdk_delay_us(BDEV_RESET_CHECK_OUTSTANDING_IO_PERIOD);
1006 : 20 : poll_threads();
1007 : 20 : poll_threads();
1008 : 5 : }
1009 : :
1010 : : /* After timing out, the reset should have been sent to the module. */
1011 : 4 : CU_ASSERT(count_queued_resets(g_bdev.io_target) == 1);
1012 : : /* Complete reset submitted to the module and the read IO. */
1013 : 4 : stub_complete_io(g_bdev.io_target, 0);
1014 : 4 : poll_threads();
1015 : 4 : CU_ASSERT(status_reset == SPDK_BDEV_IO_STATUS_SUCCESS);
1016 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
1017 : :
1018 : :
1019 : : /* Destroy the channel and end the test. */
1020 : 4 : spdk_put_io_channel(io_ch);
1021 : 4 : poll_threads();
1022 : :
1023 : 4 : teardown_test();
1024 : 4 : }
1025 : :
1026 : :
1027 : : static void
1028 : 4 : basic_qos(void)
1029 : : {
1030 : : struct spdk_io_channel *io_ch[2];
1031 : : struct spdk_bdev_channel *bdev_ch[2];
1032 : : struct spdk_bdev *bdev;
1033 : 3 : enum spdk_bdev_io_status status, abort_status;
1034 : : int rc;
1035 : :
1036 : 4 : setup_test();
1037 : :
1038 : : /* Enable QoS */
1039 : 4 : bdev = &g_bdev.bdev;
1040 : 4 : bdev->internal.qos = calloc(1, sizeof(*bdev->internal.qos));
1041 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev->internal.qos != NULL);
1042 : : /*
1043 : : * Enable read/write IOPS, read only byte per second and
1044 : : * read/write byte per second rate limits.
1045 : : * In this case, all rate limits will take equal effect.
1046 : : */
1047 : : /* 2000 read/write I/O per second, or 2 per millisecond */
1048 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT].limit = 2000;
1049 : : /* 8K read/write byte per millisecond with 4K block size */
1050 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT].limit = 8192000;
1051 : : /* 8K read only byte per millisecond with 4K block size */
1052 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT].limit = 8192000;
1053 : :
1054 : 4 : g_get_io_channel = true;
1055 : :
1056 : 4 : set_thread(0);
1057 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
1058 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
1059 : 4 : CU_ASSERT(bdev_ch[0]->flags == BDEV_CH_QOS_ENABLED);
1060 : :
1061 : 4 : set_thread(1);
1062 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
1063 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
1064 : 4 : CU_ASSERT(bdev_ch[1]->flags == BDEV_CH_QOS_ENABLED);
1065 : :
1066 : : /*
1067 : : * Send an I/O on thread 0, which is where the QoS thread is running.
1068 : : */
1069 : 4 : set_thread(0);
1070 : 4 : status = SPDK_BDEV_IO_STATUS_PENDING;
1071 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status);
1072 : 4 : CU_ASSERT(rc == 0);
1073 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_PENDING);
1074 : 4 : poll_threads();
1075 : 4 : stub_complete_io(g_bdev.io_target, 0);
1076 : 4 : poll_threads();
1077 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_SUCCESS);
1078 : :
1079 : : /* Send an I/O on thread 1. The QoS thread is not running here. */
1080 : 4 : status = SPDK_BDEV_IO_STATUS_PENDING;
1081 : 4 : set_thread(1);
1082 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status);
1083 : 4 : CU_ASSERT(rc == 0);
1084 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_PENDING);
1085 : 4 : poll_threads();
1086 : : /* Complete I/O on thread 0. This should not complete the I/O we submitted. */
1087 : 4 : set_thread(0);
1088 : 4 : stub_complete_io(g_bdev.io_target, 0);
1089 : 4 : poll_threads();
1090 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_PENDING);
1091 : : /* Now complete I/O on original thread 1. */
1092 : 4 : set_thread(1);
1093 : 4 : poll_threads();
1094 : 4 : stub_complete_io(g_bdev.io_target, 0);
1095 : 4 : poll_threads();
1096 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_SUCCESS);
1097 : :
1098 : : /* Reset rate limit for the next test cases. */
1099 : 4 : spdk_delay_us(SPDK_BDEV_QOS_TIMESLICE_IN_USEC);
1100 : 4 : poll_threads();
1101 : :
1102 : : /*
1103 : : * Test abort request when QoS is enabled.
1104 : : */
1105 : :
1106 : : /* Send an I/O on thread 0, which is where the QoS thread is running. */
1107 : 4 : set_thread(0);
1108 : 4 : status = SPDK_BDEV_IO_STATUS_PENDING;
1109 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status);
1110 : 4 : CU_ASSERT(rc == 0);
1111 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_PENDING);
1112 : : /* Send an abort to the I/O on the same thread. */
1113 : 4 : abort_status = SPDK_BDEV_IO_STATUS_PENDING;
1114 : 4 : rc = spdk_bdev_abort(g_desc, io_ch[0], &status, io_during_io_done, &abort_status);
1115 : 4 : CU_ASSERT(rc == 0);
1116 : 4 : CU_ASSERT(abort_status == SPDK_BDEV_IO_STATUS_PENDING);
1117 : 4 : poll_threads();
1118 : 4 : CU_ASSERT(abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
1119 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_ABORTED);
1120 : :
1121 : : /* Send an I/O on thread 1. The QoS thread is not running here. */
1122 : 4 : status = SPDK_BDEV_IO_STATUS_PENDING;
1123 : 4 : set_thread(1);
1124 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status);
1125 : 4 : CU_ASSERT(rc == 0);
1126 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_PENDING);
1127 : 4 : poll_threads();
1128 : : /* Send an abort to the I/O on the same thread. */
1129 : 4 : abort_status = SPDK_BDEV_IO_STATUS_PENDING;
1130 : 4 : rc = spdk_bdev_abort(g_desc, io_ch[1], &status, io_during_io_done, &abort_status);
1131 : 4 : CU_ASSERT(rc == 0);
1132 : 4 : CU_ASSERT(abort_status == SPDK_BDEV_IO_STATUS_PENDING);
1133 : 4 : poll_threads();
1134 : : /* Complete the I/O with failure and the abort with success on thread 1. */
1135 : 4 : CU_ASSERT(abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
1136 : 4 : CU_ASSERT(status == SPDK_BDEV_IO_STATUS_ABORTED);
1137 : :
1138 : 4 : set_thread(0);
1139 : :
1140 : : /*
1141 : : * Close the descriptor only, which should stop the qos channel as
1142 : : * the last descriptor removed.
1143 : : */
1144 : 4 : spdk_bdev_close(g_desc);
1145 : 4 : poll_threads();
1146 : 4 : CU_ASSERT(bdev->internal.qos->ch == NULL);
1147 : :
1148 : : /*
1149 : : * Open the bdev again which shall setup the qos channel as the
1150 : : * channels are valid.
1151 : : */
1152 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
1153 : 4 : poll_threads();
1154 : 4 : CU_ASSERT(bdev->internal.qos->ch != NULL);
1155 : :
1156 : : /* Tear down the channels */
1157 : 4 : set_thread(0);
1158 : 4 : spdk_put_io_channel(io_ch[0]);
1159 : 4 : set_thread(1);
1160 : 4 : spdk_put_io_channel(io_ch[1]);
1161 : 4 : poll_threads();
1162 : 4 : set_thread(0);
1163 : :
1164 : : /* Close the descriptor, which should stop the qos channel */
1165 : 4 : spdk_bdev_close(g_desc);
1166 : 4 : poll_threads();
1167 : 4 : CU_ASSERT(bdev->internal.qos->ch == NULL);
1168 : :
1169 : : /* Open the bdev again, no qos channel setup without valid channels. */
1170 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
1171 : 4 : poll_threads();
1172 : 4 : CU_ASSERT(bdev->internal.qos->ch == NULL);
1173 : :
1174 : : /* Create the channels in reverse order. */
1175 : 4 : set_thread(1);
1176 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
1177 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
1178 : 4 : CU_ASSERT(bdev_ch[1]->flags == BDEV_CH_QOS_ENABLED);
1179 : :
1180 : 4 : set_thread(0);
1181 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
1182 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
1183 : 4 : CU_ASSERT(bdev_ch[0]->flags == BDEV_CH_QOS_ENABLED);
1184 : :
1185 : : /* Confirm that the qos thread is now thread 1 */
1186 : 4 : CU_ASSERT(bdev->internal.qos->ch == bdev_ch[1]);
1187 : :
1188 : : /* Tear down the channels */
1189 : 4 : set_thread(0);
1190 : 4 : spdk_put_io_channel(io_ch[0]);
1191 : 4 : set_thread(1);
1192 : 4 : spdk_put_io_channel(io_ch[1]);
1193 : 4 : poll_threads();
1194 : :
1195 : 4 : set_thread(0);
1196 : :
1197 : 4 : teardown_test();
1198 : 4 : }
1199 : :
1200 : : static void
1201 : 4 : io_during_qos_queue(void)
1202 : : {
1203 : : struct spdk_io_channel *io_ch[2];
1204 : : struct spdk_bdev_channel *bdev_ch[2];
1205 : : struct spdk_bdev *bdev;
1206 : 3 : enum spdk_bdev_io_status status0, status1, status2;
1207 : : int rc;
1208 : :
1209 : 4 : setup_test();
1210 : 4 : MOCK_SET(spdk_get_ticks, 0);
1211 : :
1212 : : /* Enable QoS */
1213 : 4 : bdev = &g_bdev.bdev;
1214 : 4 : bdev->internal.qos = calloc(1, sizeof(*bdev->internal.qos));
1215 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev->internal.qos != NULL);
1216 : :
1217 : : /*
1218 : : * Enable read/write IOPS, read only byte per sec, write only
1219 : : * byte per sec and read/write byte per sec rate limits.
1220 : : * In this case, both read only and write only byte per sec
1221 : : * rate limit will take effect.
1222 : : */
1223 : : /* 4000 read/write I/O per second, or 4 per millisecond */
1224 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT].limit = 4000;
1225 : : /* 8K byte per millisecond with 4K block size */
1226 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT].limit = 8192000;
1227 : : /* 4K byte per millisecond with 4K block size */
1228 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT].limit = 4096000;
1229 : : /* 4K byte per millisecond with 4K block size */
1230 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT].limit = 4096000;
1231 : :
1232 : 4 : g_get_io_channel = true;
1233 : :
1234 : : /* Create channels */
1235 : 4 : set_thread(0);
1236 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
1237 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
1238 : 4 : CU_ASSERT(bdev_ch[0]->flags == BDEV_CH_QOS_ENABLED);
1239 : :
1240 : 4 : set_thread(1);
1241 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
1242 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
1243 : 4 : CU_ASSERT(bdev_ch[1]->flags == BDEV_CH_QOS_ENABLED);
1244 : :
1245 : : /* Send two read I/Os */
1246 : 4 : status1 = SPDK_BDEV_IO_STATUS_PENDING;
1247 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status1);
1248 : 4 : CU_ASSERT(rc == 0);
1249 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_PENDING);
1250 : 4 : set_thread(0);
1251 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
1252 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status0);
1253 : 4 : CU_ASSERT(rc == 0);
1254 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_PENDING);
1255 : : /* Send one write I/O */
1256 : 4 : status2 = SPDK_BDEV_IO_STATUS_PENDING;
1257 : 4 : rc = spdk_bdev_write_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status2);
1258 : 4 : CU_ASSERT(rc == 0);
1259 : 4 : CU_ASSERT(status2 == SPDK_BDEV_IO_STATUS_PENDING);
1260 : :
1261 : : /* Complete any I/O that arrived at the disk */
1262 : 4 : poll_threads();
1263 : 4 : set_thread(1);
1264 : 4 : stub_complete_io(g_bdev.io_target, 0);
1265 : 4 : set_thread(0);
1266 : 4 : stub_complete_io(g_bdev.io_target, 0);
1267 : 4 : poll_threads();
1268 : :
1269 : : /* Only one of the two read I/Os should complete. (logical XOR) */
1270 [ - + ]: 4 : if (status0 == SPDK_BDEV_IO_STATUS_SUCCESS) {
1271 : 0 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_PENDING);
1272 : 0 : } else {
1273 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_SUCCESS);
1274 : : }
1275 : : /* The write I/O should complete. */
1276 : 4 : CU_ASSERT(status2 == SPDK_BDEV_IO_STATUS_SUCCESS);
1277 : :
1278 : : /* Advance in time by a millisecond */
1279 : 4 : spdk_delay_us(1000);
1280 : :
1281 : : /* Complete more I/O */
1282 : 4 : poll_threads();
1283 : 4 : set_thread(1);
1284 : 4 : stub_complete_io(g_bdev.io_target, 0);
1285 : 4 : set_thread(0);
1286 : 4 : stub_complete_io(g_bdev.io_target, 0);
1287 : 4 : poll_threads();
1288 : :
1289 : : /* Now the second read I/O should be done */
1290 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_SUCCESS);
1291 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_SUCCESS);
1292 : :
1293 : : /* Tear down the channels */
1294 : 4 : set_thread(1);
1295 : 4 : spdk_put_io_channel(io_ch[1]);
1296 : 4 : set_thread(0);
1297 : 4 : spdk_put_io_channel(io_ch[0]);
1298 : 4 : poll_threads();
1299 : :
1300 : 4 : teardown_test();
1301 : 4 : }
1302 : :
1303 : : static void
1304 : 4 : io_during_qos_reset(void)
1305 : : {
1306 : : struct spdk_io_channel *io_ch[2];
1307 : : struct spdk_bdev_channel *bdev_ch[2];
1308 : : struct spdk_bdev *bdev;
1309 : 3 : enum spdk_bdev_io_status status0, status1, reset_status;
1310 : : int rc;
1311 : :
1312 : 4 : setup_test();
1313 : 4 : MOCK_SET(spdk_get_ticks, 0);
1314 : :
1315 : : /* Enable QoS */
1316 : 4 : bdev = &g_bdev.bdev;
1317 : 4 : bdev->internal.qos = calloc(1, sizeof(*bdev->internal.qos));
1318 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev->internal.qos != NULL);
1319 : :
1320 : : /*
1321 : : * Enable read/write IOPS, write only byte per sec and
1322 : : * read/write byte per second rate limits.
1323 : : * In this case, read/write byte per second rate limit will
1324 : : * take effect first.
1325 : : */
1326 : : /* 2000 read/write I/O per second, or 2 per millisecond */
1327 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT].limit = 2000;
1328 : : /* 4K byte per millisecond with 4K block size */
1329 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT].limit = 4096000;
1330 : : /* 8K byte per millisecond with 4K block size */
1331 : 4 : bdev->internal.qos->rate_limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT].limit = 8192000;
1332 : :
1333 : 4 : g_get_io_channel = true;
1334 : :
1335 : : /* Create channels */
1336 : 4 : set_thread(0);
1337 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
1338 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
1339 : 4 : CU_ASSERT(bdev_ch[0]->flags == BDEV_CH_QOS_ENABLED);
1340 : :
1341 : 4 : set_thread(1);
1342 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
1343 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
1344 : 4 : CU_ASSERT(bdev_ch[1]->flags == BDEV_CH_QOS_ENABLED);
1345 : :
1346 : : /* Send two I/O. One of these gets queued by QoS. The other is sitting at the disk. */
1347 : 4 : status1 = SPDK_BDEV_IO_STATUS_PENDING;
1348 : 4 : rc = spdk_bdev_write_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &status1);
1349 : 4 : CU_ASSERT(rc == 0);
1350 : 4 : set_thread(0);
1351 : 4 : status0 = SPDK_BDEV_IO_STATUS_PENDING;
1352 : 4 : rc = spdk_bdev_write_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &status0);
1353 : 4 : CU_ASSERT(rc == 0);
1354 : :
1355 : 4 : poll_threads();
1356 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_PENDING);
1357 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_PENDING);
1358 : :
1359 : : /* Reset the bdev. */
1360 : 4 : reset_status = SPDK_BDEV_IO_STATUS_PENDING;
1361 : 4 : rc = spdk_bdev_reset(g_desc, io_ch[0], io_during_io_done, &reset_status);
1362 : 4 : CU_ASSERT(rc == 0);
1363 : :
1364 : : /* Complete any I/O that arrived at the disk */
1365 : 4 : poll_threads();
1366 : 4 : set_thread(1);
1367 : 4 : stub_complete_io(g_bdev.io_target, 0);
1368 : 4 : set_thread(0);
1369 : 4 : stub_complete_io(g_bdev.io_target, 0);
1370 : 4 : poll_threads();
1371 : :
1372 : 4 : CU_ASSERT(reset_status == SPDK_BDEV_IO_STATUS_SUCCESS);
1373 : 4 : CU_ASSERT(status0 == SPDK_BDEV_IO_STATUS_ABORTED);
1374 : 4 : CU_ASSERT(status1 == SPDK_BDEV_IO_STATUS_ABORTED);
1375 : :
1376 : : /* Tear down the channels */
1377 : 4 : set_thread(1);
1378 : 4 : spdk_put_io_channel(io_ch[1]);
1379 : 4 : set_thread(0);
1380 : 4 : spdk_put_io_channel(io_ch[0]);
1381 : 4 : poll_threads();
1382 : :
1383 : 4 : teardown_test();
1384 : 4 : }
1385 : :
1386 : : static void
1387 : 516 : enomem_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1388 : : {
1389 : 516 : enum spdk_bdev_io_status *status = cb_arg;
1390 : :
1391 [ + + ]: 516 : *status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
1392 : 516 : spdk_bdev_free_io(bdev_io);
1393 : 516 : }
1394 : :
1395 : : static void
1396 : 4 : enomem(void)
1397 : 3 : {
1398 : : struct spdk_io_channel *io_ch;
1399 : : struct spdk_bdev_channel *bdev_ch;
1400 : : struct spdk_bdev_shared_resource *shared_resource;
1401 : : struct ut_bdev_channel *ut_ch;
1402 : 4 : const uint32_t IO_ARRAY_SIZE = 64;
1403 : 4 : const uint32_t AVAIL = 20;
1404 [ - + ]: 4 : enum spdk_bdev_io_status status[IO_ARRAY_SIZE], status_reset;
1405 : : uint32_t nomem_cnt, i;
1406 : : struct spdk_bdev_io *first_io;
1407 : : int rc;
1408 : :
1409 : 4 : setup_test();
1410 : :
1411 : 4 : set_thread(0);
1412 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
1413 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
1414 : 4 : shared_resource = bdev_ch->shared_resource;
1415 : 4 : ut_ch = spdk_io_channel_get_ctx(bdev_ch->channel);
1416 : 4 : ut_ch->avail_cnt = AVAIL;
1417 : :
1418 : : /* First submit a number of IOs equal to what the channel can support. */
1419 [ + + ]: 84 : for (i = 0; i < AVAIL; i++) {
1420 : 80 : status[i] = SPDK_BDEV_IO_STATUS_PENDING;
1421 : 80 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[i]);
1422 : 80 : CU_ASSERT(rc == 0);
1423 : 20 : }
1424 : 4 : CU_ASSERT(TAILQ_EMPTY(&shared_resource->nomem_io));
1425 : :
1426 : : /*
1427 : : * Next, submit one additional I/O. This one should fail with ENOMEM and then go onto
1428 : : * the enomem_io list.
1429 : : */
1430 : 4 : status[AVAIL] = SPDK_BDEV_IO_STATUS_PENDING;
1431 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[AVAIL]);
1432 : 4 : CU_ASSERT(rc == 0);
1433 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&shared_resource->nomem_io));
1434 : 4 : first_io = TAILQ_FIRST(&shared_resource->nomem_io);
1435 : :
1436 : : /*
1437 : : * Now submit a bunch more I/O. These should all fail with ENOMEM and get queued behind
1438 : : * the first_io above.
1439 : : */
1440 [ + + ]: 176 : for (i = AVAIL + 1; i < IO_ARRAY_SIZE; i++) {
1441 : 172 : status[i] = SPDK_BDEV_IO_STATUS_PENDING;
1442 : 172 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[i]);
1443 : 172 : CU_ASSERT(rc == 0);
1444 : 43 : }
1445 : :
1446 : : /* Assert that first_io is still at the head of the list. */
1447 : 4 : CU_ASSERT(TAILQ_FIRST(&shared_resource->nomem_io) == first_io);
1448 : 4 : CU_ASSERT(bdev_io_tailq_cnt(&shared_resource->nomem_io) == (IO_ARRAY_SIZE - AVAIL));
1449 : 4 : nomem_cnt = bdev_io_tailq_cnt(&shared_resource->nomem_io);
1450 : 4 : CU_ASSERT(shared_resource->nomem_threshold == (AVAIL - NOMEM_THRESHOLD_COUNT));
1451 : :
1452 : : /*
1453 : : * Complete 1 I/O only. The key check here is bdev_io_tailq_cnt - this should not have
1454 : : * changed since completing just 1 I/O should not trigger retrying the queued nomem_io
1455 : : * list.
1456 : : */
1457 : 4 : stub_complete_io(g_bdev.io_target, 1);
1458 : 4 : CU_ASSERT(bdev_io_tailq_cnt(&shared_resource->nomem_io) == nomem_cnt);
1459 : :
1460 : : /*
1461 : : * Complete enough I/O to hit the nomem_threshold. This should trigger retrying nomem_io,
1462 : : * and we should see I/O get resubmitted to the test bdev module.
1463 : : */
1464 : 4 : stub_complete_io(g_bdev.io_target, NOMEM_THRESHOLD_COUNT - 1);
1465 : 4 : CU_ASSERT(bdev_io_tailq_cnt(&shared_resource->nomem_io) < nomem_cnt);
1466 : 4 : nomem_cnt = bdev_io_tailq_cnt(&shared_resource->nomem_io);
1467 : :
1468 : : /* Complete 1 I/O only. This should not trigger retrying the queued nomem_io. */
1469 : 4 : stub_complete_io(g_bdev.io_target, 1);
1470 : 4 : CU_ASSERT(bdev_io_tailq_cnt(&shared_resource->nomem_io) == nomem_cnt);
1471 : :
1472 : : /*
1473 : : * Send a reset and confirm that all I/O are completed, including the ones that
1474 : : * were queued on the nomem_io list.
1475 : : */
1476 : 4 : status_reset = SPDK_BDEV_IO_STATUS_PENDING;
1477 : 4 : rc = spdk_bdev_reset(g_desc, io_ch, enomem_done, &status_reset);
1478 : 4 : poll_threads();
1479 : 4 : CU_ASSERT(rc == 0);
1480 : : /* This will complete the reset. */
1481 : 4 : stub_complete_io(g_bdev.io_target, 0);
1482 : :
1483 : 4 : CU_ASSERT(bdev_io_tailq_cnt(&shared_resource->nomem_io) == 0);
1484 : 4 : CU_ASSERT(shared_resource->io_outstanding == 0);
1485 : :
1486 : 4 : spdk_put_io_channel(io_ch);
1487 : 4 : poll_threads();
1488 : 4 : teardown_test();
1489 : 4 : }
1490 : :
1491 : : static void
1492 : 4 : enomem_multi_bdev(void)
1493 : 3 : {
1494 : : struct spdk_io_channel *io_ch;
1495 : : struct spdk_bdev_channel *bdev_ch;
1496 : : struct spdk_bdev_shared_resource *shared_resource;
1497 : : struct ut_bdev_channel *ut_ch;
1498 : 4 : const uint32_t IO_ARRAY_SIZE = 64;
1499 : 4 : const uint32_t AVAIL = 20;
1500 [ - + ]: 4 : enum spdk_bdev_io_status status[IO_ARRAY_SIZE];
1501 : : uint32_t i;
1502 : : struct ut_bdev *second_bdev;
1503 : 4 : struct spdk_bdev_desc *second_desc = NULL;
1504 : : struct spdk_bdev_channel *second_bdev_ch;
1505 : : struct spdk_io_channel *second_ch;
1506 : : int rc;
1507 : :
1508 : 4 : setup_test();
1509 : :
1510 : : /* Register second bdev with the same io_target */
1511 : 4 : second_bdev = calloc(1, sizeof(*second_bdev));
1512 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(second_bdev != NULL);
1513 : 4 : register_bdev(second_bdev, "ut_bdev2", g_bdev.io_target);
1514 : 4 : spdk_bdev_open_ext("ut_bdev2", true, _bdev_event_cb, NULL, &second_desc);
1515 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(second_desc != NULL);
1516 : :
1517 : 4 : set_thread(0);
1518 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
1519 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
1520 : 4 : shared_resource = bdev_ch->shared_resource;
1521 : 4 : ut_ch = spdk_io_channel_get_ctx(bdev_ch->channel);
1522 : 4 : ut_ch->avail_cnt = AVAIL;
1523 : :
1524 : 4 : second_ch = spdk_bdev_get_io_channel(second_desc);
1525 : 4 : second_bdev_ch = spdk_io_channel_get_ctx(second_ch);
1526 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(shared_resource == second_bdev_ch->shared_resource);
1527 : :
1528 : : /* Saturate io_target through bdev A. */
1529 [ + + ]: 84 : for (i = 0; i < AVAIL; i++) {
1530 : 80 : status[i] = SPDK_BDEV_IO_STATUS_PENDING;
1531 : 80 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[i]);
1532 : 80 : CU_ASSERT(rc == 0);
1533 : 20 : }
1534 : 4 : CU_ASSERT(TAILQ_EMPTY(&shared_resource->nomem_io));
1535 : :
1536 : : /*
1537 : : * Now submit I/O through the second bdev. This should fail with ENOMEM
1538 : : * and then go onto the nomem_io list.
1539 : : */
1540 : 4 : status[AVAIL] = SPDK_BDEV_IO_STATUS_PENDING;
1541 : 4 : rc = spdk_bdev_read_blocks(second_desc, second_ch, NULL, 0, 1, enomem_done, &status[AVAIL]);
1542 : 4 : CU_ASSERT(rc == 0);
1543 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&shared_resource->nomem_io));
1544 : :
1545 : : /* Complete first bdev's I/O. This should retry sending second bdev's nomem_io */
1546 : 4 : stub_complete_io(g_bdev.io_target, AVAIL);
1547 : :
1548 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&shared_resource->nomem_io));
1549 : 4 : CU_ASSERT(shared_resource->io_outstanding == 1);
1550 : :
1551 : : /* Now complete our retried I/O */
1552 : 4 : stub_complete_io(g_bdev.io_target, 1);
1553 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(shared_resource->io_outstanding == 0);
1554 : :
1555 : 4 : spdk_put_io_channel(io_ch);
1556 : 4 : spdk_put_io_channel(second_ch);
1557 : 4 : spdk_bdev_close(second_desc);
1558 : 4 : unregister_bdev(second_bdev);
1559 : 4 : poll_threads();
1560 : 4 : free(second_bdev);
1561 : 4 : teardown_test();
1562 : 4 : }
1563 : :
1564 : : static void
1565 : 4 : enomem_multi_bdev_unregister(void)
1566 : 3 : {
1567 : : struct spdk_io_channel *io_ch;
1568 : : struct spdk_bdev_channel *bdev_ch;
1569 : : struct spdk_bdev_shared_resource *shared_resource;
1570 : : struct ut_bdev_channel *ut_ch;
1571 : 4 : const uint32_t IO_ARRAY_SIZE = 64;
1572 : 4 : const uint32_t AVAIL = 20;
1573 [ - + ]: 4 : enum spdk_bdev_io_status status[IO_ARRAY_SIZE];
1574 : : uint32_t i;
1575 : : int rc;
1576 : :
1577 : 4 : setup_test();
1578 : :
1579 : 4 : set_thread(0);
1580 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
1581 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
1582 : 4 : shared_resource = bdev_ch->shared_resource;
1583 : 4 : ut_ch = spdk_io_channel_get_ctx(bdev_ch->channel);
1584 : 4 : ut_ch->avail_cnt = AVAIL;
1585 : :
1586 : : /* Saturate io_target through the bdev. */
1587 [ + + ]: 84 : for (i = 0; i < AVAIL; i++) {
1588 : 80 : status[i] = SPDK_BDEV_IO_STATUS_PENDING;
1589 : 80 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[i]);
1590 : 80 : CU_ASSERT(rc == 0);
1591 : 20 : }
1592 : 4 : CU_ASSERT(TAILQ_EMPTY(&shared_resource->nomem_io));
1593 : :
1594 : : /*
1595 : : * Now submit I/O through the bdev. This should fail with ENOMEM
1596 : : * and then go onto the nomem_io list.
1597 : : */
1598 : 4 : status[AVAIL] = SPDK_BDEV_IO_STATUS_PENDING;
1599 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[AVAIL]);
1600 : 4 : CU_ASSERT(rc == 0);
1601 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&shared_resource->nomem_io));
1602 : :
1603 : : /* Unregister the bdev to abort the IOs from nomem_io queue. */
1604 : 4 : unregister_bdev(&g_bdev);
1605 : 4 : CU_ASSERT(status[AVAIL] == SPDK_BDEV_IO_STATUS_FAILED);
1606 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&shared_resource->nomem_io));
1607 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(shared_resource->io_outstanding == AVAIL);
1608 : :
1609 : : /* Complete the bdev's I/O. */
1610 : 4 : stub_complete_io(g_bdev.io_target, AVAIL);
1611 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(shared_resource->io_outstanding == 0);
1612 : :
1613 : 4 : spdk_put_io_channel(io_ch);
1614 : 4 : poll_threads();
1615 : 4 : teardown_test();
1616 : 4 : }
1617 : :
1618 : : static void
1619 : 4 : enomem_multi_io_target(void)
1620 : 3 : {
1621 : : struct spdk_io_channel *io_ch;
1622 : : struct spdk_bdev_channel *bdev_ch;
1623 : : struct ut_bdev_channel *ut_ch;
1624 : 4 : const uint32_t IO_ARRAY_SIZE = 64;
1625 : 4 : const uint32_t AVAIL = 20;
1626 [ - + ]: 4 : enum spdk_bdev_io_status status[IO_ARRAY_SIZE];
1627 : : uint32_t i;
1628 : 3 : int new_io_device;
1629 : : struct ut_bdev *second_bdev;
1630 : 4 : struct spdk_bdev_desc *second_desc = NULL;
1631 : : struct spdk_bdev_channel *second_bdev_ch;
1632 : : struct spdk_io_channel *second_ch;
1633 : : int rc;
1634 : :
1635 : 4 : setup_test();
1636 : :
1637 : : /* Create new io_target and a second bdev using it */
1638 : 4 : spdk_io_device_register(&new_io_device, stub_create_ch, stub_destroy_ch,
1639 : : sizeof(struct ut_bdev_channel), NULL);
1640 : 4 : second_bdev = calloc(1, sizeof(*second_bdev));
1641 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(second_bdev != NULL);
1642 : 4 : register_bdev(second_bdev, "ut_bdev2", &new_io_device);
1643 : 4 : spdk_bdev_open_ext("ut_bdev2", true, _bdev_event_cb, NULL, &second_desc);
1644 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(second_desc != NULL);
1645 : :
1646 : 4 : set_thread(0);
1647 : 4 : io_ch = spdk_bdev_get_io_channel(g_desc);
1648 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
1649 : 4 : ut_ch = spdk_io_channel_get_ctx(bdev_ch->channel);
1650 : 4 : ut_ch->avail_cnt = AVAIL;
1651 : :
1652 : : /* Different io_target should imply a different shared_resource */
1653 : 4 : second_ch = spdk_bdev_get_io_channel(second_desc);
1654 : 4 : second_bdev_ch = spdk_io_channel_get_ctx(second_ch);
1655 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev_ch->shared_resource != second_bdev_ch->shared_resource);
1656 : :
1657 : : /* Saturate io_target through bdev A. */
1658 [ + + ]: 84 : for (i = 0; i < AVAIL; i++) {
1659 : 80 : status[i] = SPDK_BDEV_IO_STATUS_PENDING;
1660 : 80 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[i]);
1661 : 80 : CU_ASSERT(rc == 0);
1662 : 20 : }
1663 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch->shared_resource->nomem_io));
1664 : :
1665 : : /* Issue one more I/O to fill ENOMEM list. */
1666 : 4 : status[AVAIL] = SPDK_BDEV_IO_STATUS_PENDING;
1667 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch, NULL, 0, 1, enomem_done, &status[AVAIL]);
1668 : 4 : CU_ASSERT(rc == 0);
1669 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&bdev_ch->shared_resource->nomem_io));
1670 : :
1671 : : /*
1672 : : * Now submit I/O through the second bdev. This should go through and complete
1673 : : * successfully because we're using a different io_device underneath.
1674 : : */
1675 : 4 : status[AVAIL] = SPDK_BDEV_IO_STATUS_PENDING;
1676 : 4 : rc = spdk_bdev_read_blocks(second_desc, second_ch, NULL, 0, 1, enomem_done, &status[AVAIL]);
1677 : 4 : CU_ASSERT(rc == 0);
1678 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&second_bdev_ch->shared_resource->nomem_io));
1679 : 4 : stub_complete_io(second_bdev->io_target, 1);
1680 : :
1681 : : /* Cleanup; Complete outstanding I/O. */
1682 : 4 : stub_complete_io(g_bdev.io_target, AVAIL);
1683 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&bdev_ch->shared_resource->nomem_io));
1684 : : /* Complete the ENOMEM I/O */
1685 : 4 : stub_complete_io(g_bdev.io_target, 1);
1686 : 4 : CU_ASSERT(bdev_ch->shared_resource->io_outstanding == 0);
1687 : :
1688 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&bdev_ch->shared_resource->nomem_io));
1689 : 4 : CU_ASSERT(bdev_ch->shared_resource->io_outstanding == 0);
1690 : 4 : spdk_put_io_channel(io_ch);
1691 : 4 : spdk_put_io_channel(second_ch);
1692 : 4 : spdk_bdev_close(second_desc);
1693 : 4 : unregister_bdev(second_bdev);
1694 : 4 : spdk_io_device_unregister(&new_io_device, NULL);
1695 : 4 : poll_threads();
1696 : 4 : free(second_bdev);
1697 : 4 : teardown_test();
1698 : 4 : }
1699 : :
1700 : : static void
1701 : 36 : qos_dynamic_enable_done(void *cb_arg, int status)
1702 : : {
1703 : 36 : int *rc = cb_arg;
1704 : 36 : *rc = status;
1705 : 36 : }
1706 : :
1707 : : static void
1708 : 4 : qos_dynamic_enable(void)
1709 : : {
1710 : : struct spdk_io_channel *io_ch[2];
1711 : : struct spdk_bdev_channel *bdev_ch[2];
1712 : : struct spdk_bdev *bdev;
1713 : 3 : enum spdk_bdev_io_status bdev_io_status[2];
1714 : 4 : uint64_t limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES] = {};
1715 : 3 : int status, second_status, rc, i;
1716 : :
1717 : 4 : setup_test();
1718 : 4 : MOCK_SET(spdk_get_ticks, 0);
1719 : :
1720 [ + + ]: 20 : for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {
1721 : 16 : limits[i] = UINT64_MAX;
1722 : 4 : }
1723 : :
1724 : 4 : bdev = &g_bdev.bdev;
1725 : :
1726 : 4 : g_get_io_channel = true;
1727 : :
1728 : : /* Create channels */
1729 : 4 : set_thread(0);
1730 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
1731 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
1732 : 4 : CU_ASSERT(bdev_ch[0]->flags == 0);
1733 : :
1734 : 4 : set_thread(1);
1735 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
1736 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
1737 : 4 : CU_ASSERT(bdev_ch[1]->flags == 0);
1738 : :
1739 : 4 : set_thread(0);
1740 : :
1741 : : /*
1742 : : * Enable QoS: Read/Write IOPS, Read/Write byte,
1743 : : * Read only byte and Write only byte per second
1744 : : * rate limits.
1745 : : * More than 10 I/Os allowed per timeslice.
1746 : : */
1747 : 4 : status = -1;
1748 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 10000;
1749 : 4 : limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT] = 100;
1750 : 4 : limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT] = 100;
1751 : 4 : limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT] = 10;
1752 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1753 : 4 : poll_threads();
1754 : 4 : CU_ASSERT(status == 0);
1755 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
1756 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
1757 : :
1758 : : /*
1759 : : * Submit and complete 10 I/O to fill the QoS allotment for this timeslice.
1760 : : * Additional I/O will then be queued.
1761 : : */
1762 : 4 : set_thread(0);
1763 [ + + ]: 44 : for (i = 0; i < 10; i++) {
1764 : 40 : bdev_io_status[0] = SPDK_BDEV_IO_STATUS_PENDING;
1765 : 40 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &bdev_io_status[0]);
1766 : 40 : CU_ASSERT(rc == 0);
1767 : 40 : CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_PENDING);
1768 : 40 : poll_thread(0);
1769 : 40 : stub_complete_io(g_bdev.io_target, 0);
1770 : 40 : CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_SUCCESS);
1771 : 10 : }
1772 : :
1773 : : /*
1774 : : * Send two more I/O. These I/O will be queued since the current timeslice allotment has been
1775 : : * filled already. We want to test that when QoS is disabled that these two I/O:
1776 : : * 1) are not aborted
1777 : : * 2) are sent back to their original thread for resubmission
1778 : : */
1779 : 4 : bdev_io_status[0] = SPDK_BDEV_IO_STATUS_PENDING;
1780 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[0], NULL, 0, 1, io_during_io_done, &bdev_io_status[0]);
1781 : 4 : CU_ASSERT(rc == 0);
1782 : 4 : CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_PENDING);
1783 : 4 : set_thread(1);
1784 : 4 : bdev_io_status[1] = SPDK_BDEV_IO_STATUS_PENDING;
1785 : 4 : rc = spdk_bdev_read_blocks(g_desc, io_ch[1], NULL, 0, 1, io_during_io_done, &bdev_io_status[1]);
1786 : 4 : CU_ASSERT(rc == 0);
1787 : 4 : CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_PENDING);
1788 : 4 : poll_threads();
1789 : :
1790 : : /*
1791 : : * Disable QoS: Read/Write IOPS, Read/Write byte,
1792 : : * Read only byte rate limits
1793 : : */
1794 : 4 : status = -1;
1795 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 0;
1796 : 4 : limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT] = 0;
1797 : 4 : limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT] = 0;
1798 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1799 : 4 : poll_threads();
1800 : 4 : CU_ASSERT(status == 0);
1801 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
1802 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
1803 : :
1804 : : /* Disable QoS: Write only Byte per second rate limit */
1805 : 4 : status = -1;
1806 : 4 : limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT] = 0;
1807 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1808 : 4 : poll_threads();
1809 : 4 : CU_ASSERT(status == 0);
1810 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) == 0);
1811 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) == 0);
1812 : :
1813 : : /*
1814 : : * All I/O should have been resubmitted back on their original thread. Complete
1815 : : * all I/O on thread 0, and ensure that only the thread 0 I/O was completed.
1816 : : */
1817 : 4 : set_thread(0);
1818 : 4 : stub_complete_io(g_bdev.io_target, 0);
1819 : 4 : poll_threads();
1820 : 4 : CU_ASSERT(bdev_io_status[0] == SPDK_BDEV_IO_STATUS_SUCCESS);
1821 : 4 : CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_PENDING);
1822 : :
1823 : : /* Now complete all I/O on thread 1 and ensure the thread 1 I/O was completed. */
1824 : 4 : set_thread(1);
1825 : 4 : stub_complete_io(g_bdev.io_target, 0);
1826 : 4 : poll_threads();
1827 : 4 : CU_ASSERT(bdev_io_status[1] == SPDK_BDEV_IO_STATUS_SUCCESS);
1828 : :
1829 : : /* Disable QoS again */
1830 : 4 : status = -1;
1831 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 0;
1832 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1833 : 4 : poll_threads();
1834 : 4 : CU_ASSERT(status == 0); /* This should succeed */
1835 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) == 0);
1836 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) == 0);
1837 : :
1838 : : /* Enable QoS on thread 0 */
1839 : 4 : status = -1;
1840 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 10000;
1841 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1842 : 4 : poll_threads();
1843 : 4 : CU_ASSERT(status == 0);
1844 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
1845 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
1846 : :
1847 : : /* Disable QoS on thread 1 */
1848 : 4 : set_thread(1);
1849 : 4 : status = -1;
1850 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 0;
1851 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1852 : : /* Don't poll yet. This should leave the channels with QoS enabled */
1853 : 4 : CU_ASSERT(status == -1);
1854 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
1855 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
1856 : :
1857 : : /* Enable QoS. This should immediately fail because the previous disable QoS hasn't completed. */
1858 : 4 : second_status = 0;
1859 : 4 : limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT] = 10;
1860 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &second_status);
1861 : 4 : poll_threads();
1862 : 4 : CU_ASSERT(status == 0); /* The disable should succeed */
1863 : 4 : CU_ASSERT(second_status < 0); /* The enable should fail */
1864 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) == 0);
1865 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) == 0);
1866 : :
1867 : : /* Enable QoS on thread 1. This should succeed now that the disable has completed. */
1868 : 4 : status = -1;
1869 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 10000;
1870 : 4 : spdk_bdev_set_qos_rate_limits(bdev, limits, qos_dynamic_enable_done, &status);
1871 : 4 : poll_threads();
1872 : 4 : CU_ASSERT(status == 0);
1873 : 4 : CU_ASSERT((bdev_ch[0]->flags & BDEV_CH_QOS_ENABLED) != 0);
1874 : 4 : CU_ASSERT((bdev_ch[1]->flags & BDEV_CH_QOS_ENABLED) != 0);
1875 : :
1876 : : /* Tear down the channels */
1877 : 4 : set_thread(0);
1878 : 4 : spdk_put_io_channel(io_ch[0]);
1879 : 4 : set_thread(1);
1880 : 4 : spdk_put_io_channel(io_ch[1]);
1881 : 4 : poll_threads();
1882 : :
1883 : 4 : set_thread(0);
1884 : 4 : teardown_test();
1885 : 4 : }
1886 : :
1887 : : static void
1888 : 8 : histogram_status_cb(void *cb_arg, int status)
1889 : : {
1890 : 8 : g_status = status;
1891 : 8 : }
1892 : :
1893 : : static void
1894 : 8 : histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
1895 : : {
1896 : 8 : g_status = status;
1897 : 8 : g_histogram = histogram;
1898 : 8 : }
1899 : :
1900 : : static void
1901 : 59392 : histogram_io_count(void *ctx, uint64_t start, uint64_t end, uint64_t count,
1902 : : uint64_t total, uint64_t so_far)
1903 : : {
1904 : 59392 : g_count += count;
1905 : 59392 : }
1906 : :
1907 : : static void
1908 : 4 : bdev_histograms_mt(void)
1909 : : {
1910 : : struct spdk_io_channel *ch[2];
1911 : : struct spdk_histogram_data *histogram;
1912 : 3 : uint8_t buf[4096];
1913 : 4 : int status = false;
1914 : : int rc;
1915 : :
1916 : :
1917 : 4 : setup_test();
1918 : :
1919 : 4 : set_thread(0);
1920 : 4 : ch[0] = spdk_bdev_get_io_channel(g_desc);
1921 : 4 : CU_ASSERT(ch[0] != NULL);
1922 : :
1923 : 4 : set_thread(1);
1924 : 4 : ch[1] = spdk_bdev_get_io_channel(g_desc);
1925 : 4 : CU_ASSERT(ch[1] != NULL);
1926 : :
1927 : :
1928 : : /* Enable histogram */
1929 : 4 : spdk_bdev_histogram_enable(&g_bdev.bdev, histogram_status_cb, NULL, true);
1930 : 4 : poll_threads();
1931 : 4 : CU_ASSERT(g_status == 0);
1932 [ - + ]: 4 : CU_ASSERT(g_bdev.bdev.internal.histogram_enabled == true);
1933 : :
1934 : : /* Allocate histogram */
1935 : 4 : histogram = spdk_histogram_data_alloc();
1936 : :
1937 : : /* Check if histogram is zeroed */
1938 : 4 : spdk_bdev_histogram_get(&g_bdev.bdev, histogram, histogram_data_cb, NULL);
1939 : 4 : poll_threads();
1940 : 4 : CU_ASSERT(g_status == 0);
1941 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
1942 : :
1943 : 4 : g_count = 0;
1944 : 4 : spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
1945 : :
1946 : 4 : CU_ASSERT(g_count == 0);
1947 : :
1948 : 4 : set_thread(0);
1949 : 4 : rc = spdk_bdev_write_blocks(g_desc, ch[0], &buf, 0, 1, io_during_io_done, &status);
1950 : 4 : CU_ASSERT(rc == 0);
1951 : :
1952 : 4 : spdk_delay_us(10);
1953 : 4 : stub_complete_io(g_bdev.io_target, 1);
1954 : 4 : poll_threads();
1955 : 4 : CU_ASSERT(status == true);
1956 : :
1957 : :
1958 : 4 : set_thread(1);
1959 : 4 : rc = spdk_bdev_read_blocks(g_desc, ch[1], &buf, 0, 1, io_during_io_done, &status);
1960 : 4 : CU_ASSERT(rc == 0);
1961 : :
1962 : 4 : spdk_delay_us(10);
1963 : 4 : stub_complete_io(g_bdev.io_target, 1);
1964 : 4 : poll_threads();
1965 : 4 : CU_ASSERT(status == true);
1966 : :
1967 : 4 : set_thread(0);
1968 : :
1969 : : /* Check if histogram gathered data from all I/O channels */
1970 : 4 : spdk_bdev_histogram_get(&g_bdev.bdev, histogram, histogram_data_cb, NULL);
1971 : 4 : poll_threads();
1972 : 4 : CU_ASSERT(g_status == 0);
1973 [ - + ]: 4 : CU_ASSERT(g_bdev.bdev.internal.histogram_enabled == true);
1974 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
1975 : :
1976 : 4 : g_count = 0;
1977 : 4 : spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
1978 : 4 : CU_ASSERT(g_count == 2);
1979 : :
1980 : : /* Disable histogram */
1981 : 4 : spdk_bdev_histogram_enable(&g_bdev.bdev, histogram_status_cb, NULL, false);
1982 : 4 : poll_threads();
1983 : 4 : CU_ASSERT(g_status == 0);
1984 [ - + ]: 4 : CU_ASSERT(g_bdev.bdev.internal.histogram_enabled == false);
1985 : :
1986 : 4 : spdk_histogram_data_free(histogram);
1987 : :
1988 : : /* Tear down the channels */
1989 : 4 : set_thread(0);
1990 : 4 : spdk_put_io_channel(ch[0]);
1991 : 4 : set_thread(1);
1992 : 4 : spdk_put_io_channel(ch[1]);
1993 : 4 : poll_threads();
1994 : 4 : set_thread(0);
1995 : 4 : teardown_test();
1996 : :
1997 : 4 : }
1998 : :
1999 : : struct timeout_io_cb_arg {
2000 : : struct iovec iov;
2001 : : uint8_t type;
2002 : : };
2003 : :
2004 : : static int
2005 : 28 : bdev_channel_count_submitted_io(struct spdk_bdev_channel *ch)
2006 : : {
2007 : : struct spdk_bdev_io *bdev_io;
2008 : 28 : int n = 0;
2009 : :
2010 [ - + ]: 28 : if (!ch) {
2011 : 0 : return -1;
2012 : : }
2013 : :
2014 [ + + ]: 56 : TAILQ_FOREACH(bdev_io, &ch->io_submitted, internal.ch_link) {
2015 : 28 : n++;
2016 : 7 : }
2017 : :
2018 : 28 : return n;
2019 : 7 : }
2020 : :
2021 : : static void
2022 : 16 : bdev_channel_io_timeout_cb(void *cb_arg, struct spdk_bdev_io *bdev_io)
2023 : : {
2024 : 16 : struct timeout_io_cb_arg *ctx = cb_arg;
2025 : :
2026 : 16 : ctx->type = bdev_io->type;
2027 : 16 : ctx->iov.iov_base = bdev_io->iov.iov_base;
2028 : 16 : ctx->iov.iov_len = bdev_io->iov.iov_len;
2029 : 16 : }
2030 : :
2031 : : static bool g_io_done;
2032 : :
2033 : : static void
2034 : 36 : io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
2035 : : {
2036 : 36 : g_io_done = true;
2037 : 36 : spdk_bdev_free_io(bdev_io);
2038 : 36 : }
2039 : :
2040 : : static void
2041 : 4 : bdev_set_io_timeout_mt(void)
2042 : : {
2043 : : struct spdk_io_channel *ch[3];
2044 : : struct spdk_bdev_channel *bdev_ch[3];
2045 : 3 : struct timeout_io_cb_arg cb_arg;
2046 : :
2047 : 4 : setup_test();
2048 : :
2049 : 4 : g_bdev.bdev.optimal_io_boundary = 16;
2050 : 4 : g_bdev.bdev.split_on_optimal_io_boundary = true;
2051 : :
2052 : 4 : set_thread(0);
2053 : 4 : ch[0] = spdk_bdev_get_io_channel(g_desc);
2054 : 4 : CU_ASSERT(ch[0] != NULL);
2055 : :
2056 : 4 : set_thread(1);
2057 : 4 : ch[1] = spdk_bdev_get_io_channel(g_desc);
2058 : 4 : CU_ASSERT(ch[1] != NULL);
2059 : :
2060 : 4 : set_thread(2);
2061 : 4 : ch[2] = spdk_bdev_get_io_channel(g_desc);
2062 : 4 : CU_ASSERT(ch[2] != NULL);
2063 : :
2064 : : /* Multi-thread mode
2065 : : * 1, Check the poller was registered successfully
2066 : : * 2, Check the timeout IO and ensure the IO was the submitted by user
2067 : : * 3, Check the link int the bdev_ch works right.
2068 : : * 4, Close desc and put io channel during the timeout poller is polling
2069 : : */
2070 : :
2071 : : /* In desc thread set the timeout */
2072 : 4 : set_thread(0);
2073 : 4 : CU_ASSERT(spdk_bdev_set_timeout(g_desc, 5, bdev_channel_io_timeout_cb, &cb_arg) == 0);
2074 : 4 : CU_ASSERT(g_desc->io_timeout_poller != NULL);
2075 : 4 : CU_ASSERT(g_desc->cb_fn == bdev_channel_io_timeout_cb);
2076 : 4 : CU_ASSERT(g_desc->cb_arg == &cb_arg);
2077 : :
2078 : : /* check the IO submitted list and timeout handler */
2079 : 4 : CU_ASSERT(spdk_bdev_read_blocks(g_desc, ch[0], (void *)0x2000, 0, 1, io_done, NULL) == 0);
2080 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(ch[0]);
2081 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[0]) == 1);
2082 : :
2083 : 4 : set_thread(1);
2084 : 4 : CU_ASSERT(spdk_bdev_write_blocks(g_desc, ch[1], (void *)0x1000, 0, 1, io_done, NULL) == 0);
2085 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(ch[1]);
2086 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[1]) == 1);
2087 : :
2088 : : /* Now test that a single-vector command is split correctly.
2089 : : * Offset 14, length 8, payload 0xF000
2090 : : * Child - Offset 14, length 2, payload 0xF000
2091 : : * Child - Offset 16, length 6, payload 0xF000 + 2 * 512
2092 : : *
2093 : : * Set up the expected values before calling spdk_bdev_read_blocks
2094 : : */
2095 : 4 : set_thread(2);
2096 : 4 : CU_ASSERT(spdk_bdev_read_blocks(g_desc, ch[2], (void *)0xF000, 14, 8, io_done, NULL) == 0);
2097 : 4 : bdev_ch[2] = spdk_io_channel_get_ctx(ch[2]);
2098 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[2]) == 3);
2099 : :
2100 : 4 : set_thread(0);
2101 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2102 : 4 : spdk_delay_us(3 * spdk_get_ticks_hz());
2103 : 4 : poll_threads();
2104 : 4 : CU_ASSERT(cb_arg.type == 0);
2105 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
2106 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 0);
2107 : :
2108 : : /* Now the time reach the limit */
2109 : 4 : spdk_delay_us(3 * spdk_get_ticks_hz());
2110 : 4 : poll_thread(0);
2111 : 4 : CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_READ);
2112 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x2000);
2113 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 1 * g_bdev.bdev.blocklen);
2114 : 4 : stub_complete_io(g_bdev.io_target, 1);
2115 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[0]) == 0);
2116 : :
2117 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2118 : 4 : set_thread(1);
2119 : 4 : poll_thread(1);
2120 : 4 : CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
2121 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x1000);
2122 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 1 * g_bdev.bdev.blocklen);
2123 : 4 : stub_complete_io(g_bdev.io_target, 1);
2124 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[1]) == 0);
2125 : :
2126 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2127 : 4 : set_thread(2);
2128 : 4 : poll_thread(2);
2129 : 4 : CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_READ);
2130 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0xF000);
2131 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 8 * g_bdev.bdev.blocklen);
2132 : 4 : stub_complete_io(g_bdev.io_target, 1);
2133 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[2]) == 2);
2134 : 4 : stub_complete_io(g_bdev.io_target, 1);
2135 : 4 : CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch[2]) == 0);
2136 : :
2137 : : /* Run poll_timeout_done() it means complete the timeout poller */
2138 : 4 : set_thread(0);
2139 : 4 : poll_thread(0);
2140 : 4 : CU_ASSERT(g_desc->refs == 0);
2141 : 4 : CU_ASSERT(spdk_bdev_read_blocks(g_desc, ch[0], (void *)0x1000, 0, 1, io_done, NULL) == 0);
2142 : 4 : set_thread(1);
2143 : 4 : CU_ASSERT(spdk_bdev_write_blocks(g_desc, ch[1], (void *)0x2000, 0, 2, io_done, NULL) == 0);
2144 : 4 : set_thread(2);
2145 : 4 : CU_ASSERT(spdk_bdev_read_blocks(g_desc, ch[2], (void *)0x3000, 0, 3, io_done, NULL) == 0);
2146 : :
2147 : : /* Trigger timeout poller to run again, desc->refs is incremented.
2148 : : * In thread 0 we destroy the io channel before timeout poller runs.
2149 : : * Timeout callback is not called on thread 0.
2150 : : */
2151 : 4 : spdk_delay_us(6 * spdk_get_ticks_hz());
2152 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2153 : 4 : set_thread(0);
2154 : 4 : stub_complete_io(g_bdev.io_target, 1);
2155 : 4 : spdk_put_io_channel(ch[0]);
2156 : 4 : poll_thread(0);
2157 : 4 : CU_ASSERT(g_desc->refs == 1)
2158 : 4 : CU_ASSERT(cb_arg.type == 0);
2159 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
2160 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 0);
2161 : :
2162 : : /* In thread 1 timeout poller runs then we destroy the io channel
2163 : : * Timeout callback is called on thread 1.
2164 : : */
2165 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2166 : 4 : set_thread(1);
2167 : 4 : poll_thread(1);
2168 : 4 : stub_complete_io(g_bdev.io_target, 1);
2169 : 4 : spdk_put_io_channel(ch[1]);
2170 : 4 : poll_thread(1);
2171 : 4 : CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
2172 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x2000);
2173 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 2 * g_bdev.bdev.blocklen);
2174 : :
2175 : : /* Close the desc.
2176 : : * Unregister the timeout poller first.
2177 : : * Then decrement desc->refs but it's not zero yet so desc is not freed.
2178 : : */
2179 : 4 : set_thread(0);
2180 : 4 : spdk_bdev_close(g_desc);
2181 : 4 : CU_ASSERT(g_desc->refs == 1);
2182 : 4 : CU_ASSERT(g_desc->io_timeout_poller == NULL);
2183 : :
2184 : : /* Timeout poller runs on thread 2 then we destroy the io channel.
2185 : : * Desc is closed so we would exit the timeout poller directly.
2186 : : * timeout callback is not called on thread 2.
2187 : : */
2188 [ - + ]: 4 : memset(&cb_arg, 0, sizeof(cb_arg));
2189 : 4 : set_thread(2);
2190 : 4 : poll_thread(2);
2191 : 4 : stub_complete_io(g_bdev.io_target, 1);
2192 : 4 : spdk_put_io_channel(ch[2]);
2193 : 4 : poll_thread(2);
2194 : 4 : CU_ASSERT(cb_arg.type == 0);
2195 : 4 : CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
2196 : 4 : CU_ASSERT(cb_arg.iov.iov_len == 0);
2197 : :
2198 : 4 : set_thread(0);
2199 : 4 : poll_thread(0);
2200 : 4 : g_teardown_done = false;
2201 : 4 : unregister_bdev(&g_bdev);
2202 : 4 : spdk_io_device_unregister(&g_io_device, NULL);
2203 : 4 : spdk_bdev_finish(finish_cb, NULL);
2204 : 4 : spdk_iobuf_finish(finish_cb, NULL);
2205 : 4 : poll_threads();
2206 [ - + ]: 4 : memset(&g_bdev, 0, sizeof(g_bdev));
2207 [ - + ]: 4 : CU_ASSERT(g_teardown_done == true);
2208 : 4 : g_teardown_done = false;
2209 : 4 : free_threads();
2210 : 4 : free_cores();
2211 : 4 : }
2212 : :
2213 : : static bool g_io_done2;
2214 : : static bool g_lock_lba_range_done;
2215 : : static bool g_unlock_lba_range_done;
2216 : :
2217 : : static void
2218 : 4 : io_done2(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
2219 : : {
2220 : 4 : g_io_done2 = true;
2221 : 4 : spdk_bdev_free_io(bdev_io);
2222 : 4 : }
2223 : :
2224 : : static void
2225 : 4 : lock_lba_range_done(struct lba_range *range, void *ctx, int status)
2226 : : {
2227 : 4 : g_lock_lba_range_done = true;
2228 : 4 : }
2229 : :
2230 : : static void
2231 : 4 : unlock_lba_range_done(struct lba_range *range, void *ctx, int status)
2232 : : {
2233 : 4 : g_unlock_lba_range_done = true;
2234 : 4 : }
2235 : :
2236 : : static uint32_t
2237 : 24 : stub_channel_outstanding_cnt(void *io_target)
2238 : : {
2239 : 24 : struct spdk_io_channel *_ch = spdk_get_io_channel(io_target);
2240 : 24 : struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch);
2241 : : uint32_t outstanding_cnt;
2242 : :
2243 : 24 : outstanding_cnt = ch->outstanding_cnt;
2244 : :
2245 : 24 : spdk_put_io_channel(_ch);
2246 : 24 : return outstanding_cnt;
2247 : : }
2248 : :
2249 : : static void
2250 : 4 : lock_lba_range_then_submit_io(void)
2251 : : {
2252 : 4 : struct spdk_bdev_desc *desc = NULL;
2253 : : void *io_target;
2254 : : struct spdk_io_channel *io_ch[3];
2255 : : struct spdk_bdev_channel *bdev_ch[3];
2256 : : struct lba_range *range;
2257 : 3 : char buf[4096];
2258 : 3 : int ctx0, ctx1, ctx2;
2259 : : int rc;
2260 : :
2261 : 4 : setup_test();
2262 : :
2263 : 4 : io_target = g_bdev.io_target;
2264 : 4 : desc = g_desc;
2265 : :
2266 : 4 : set_thread(0);
2267 : 4 : io_ch[0] = spdk_bdev_get_io_channel(desc);
2268 : 4 : bdev_ch[0] = spdk_io_channel_get_ctx(io_ch[0]);
2269 : 4 : CU_ASSERT(io_ch[0] != NULL);
2270 : :
2271 : 4 : set_thread(1);
2272 : 4 : io_ch[1] = spdk_bdev_get_io_channel(desc);
2273 : 4 : bdev_ch[1] = spdk_io_channel_get_ctx(io_ch[1]);
2274 : 4 : CU_ASSERT(io_ch[1] != NULL);
2275 : :
2276 : 4 : set_thread(0);
2277 : 4 : g_lock_lba_range_done = false;
2278 : 4 : rc = bdev_lock_lba_range(desc, io_ch[0], 20, 10, lock_lba_range_done, &ctx0);
2279 : 4 : CU_ASSERT(rc == 0);
2280 : 4 : poll_threads();
2281 : :
2282 : : /* The lock should immediately become valid, since there are no outstanding
2283 : : * write I/O.
2284 : : */
2285 [ - + ]: 4 : CU_ASSERT(g_lock_lba_range_done == true);
2286 : 4 : range = TAILQ_FIRST(&bdev_ch[0]->locked_ranges);
2287 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(range != NULL);
2288 : 4 : CU_ASSERT(range->offset == 20);
2289 : 4 : CU_ASSERT(range->length == 10);
2290 : 4 : CU_ASSERT(range->owner_ch == bdev_ch[0]);
2291 : :
2292 : 4 : g_io_done = false;
2293 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[0]->io_locked));
2294 : 4 : rc = spdk_bdev_read_blocks(desc, io_ch[0], buf, 20, 1, io_done, &ctx0);
2295 : 4 : CU_ASSERT(rc == 0);
2296 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 1);
2297 : :
2298 : 4 : stub_complete_io(io_target, 1);
2299 : 4 : poll_threads();
2300 [ - + ]: 4 : CU_ASSERT(g_io_done == true);
2301 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[0]->io_locked));
2302 : :
2303 : : /* Try a write I/O. This should actually be allowed to execute, since the channel
2304 : : * holding the lock is submitting the write I/O.
2305 : : */
2306 : 4 : g_io_done = false;
2307 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[0]->io_locked));
2308 : 4 : rc = spdk_bdev_write_blocks(desc, io_ch[0], buf, 20, 1, io_done, &ctx0);
2309 : 4 : CU_ASSERT(rc == 0);
2310 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 1);
2311 : :
2312 : 4 : stub_complete_io(io_target, 1);
2313 : 4 : poll_threads();
2314 [ - + ]: 4 : CU_ASSERT(g_io_done == true);
2315 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[0]->io_locked));
2316 : :
2317 : : /* Try a write I/O. This should get queued in the io_locked tailq. */
2318 : 4 : set_thread(1);
2319 : 4 : g_io_done = false;
2320 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[1]->io_locked));
2321 : 4 : rc = spdk_bdev_write_blocks(desc, io_ch[1], buf, 20, 1, io_done, &ctx1);
2322 : 4 : CU_ASSERT(rc == 0);
2323 : 4 : poll_threads();
2324 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 0);
2325 : 4 : CU_ASSERT(!TAILQ_EMPTY(&bdev_ch[1]->io_locked));
2326 [ - + ]: 4 : CU_ASSERT(g_io_done == false);
2327 : :
2328 : : /* Try to unlock the lba range using thread 1's io_ch. This should fail. */
2329 : 4 : rc = bdev_unlock_lba_range(desc, io_ch[1], 20, 10, unlock_lba_range_done, &ctx1);
2330 : 4 : CU_ASSERT(rc == -EINVAL);
2331 : :
2332 : : /* Now create a new channel and submit a write I/O with it. This should also be queued.
2333 : : * The new channel should inherit the active locks from the bdev's internal list.
2334 : : */
2335 : 4 : set_thread(2);
2336 : 4 : io_ch[2] = spdk_bdev_get_io_channel(desc);
2337 : 4 : bdev_ch[2] = spdk_io_channel_get_ctx(io_ch[2]);
2338 : 4 : CU_ASSERT(io_ch[2] != NULL);
2339 : :
2340 : 4 : g_io_done2 = false;
2341 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[2]->io_locked));
2342 : 4 : rc = spdk_bdev_write_blocks(desc, io_ch[2], buf, 22, 2, io_done2, &ctx2);
2343 : 4 : CU_ASSERT(rc == 0);
2344 : 4 : poll_threads();
2345 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 0);
2346 : 4 : CU_ASSERT(!TAILQ_EMPTY(&bdev_ch[2]->io_locked));
2347 [ - + ]: 4 : CU_ASSERT(g_io_done2 == false);
2348 : :
2349 : 4 : set_thread(0);
2350 : 4 : rc = bdev_unlock_lba_range(desc, io_ch[0], 20, 10, unlock_lba_range_done, &ctx0);
2351 : 4 : CU_ASSERT(rc == 0);
2352 : 4 : poll_threads();
2353 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[0]->locked_ranges));
2354 : :
2355 : : /* The LBA range is unlocked, so the write IOs should now have started execution. */
2356 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[1]->io_locked));
2357 : 4 : CU_ASSERT(TAILQ_EMPTY(&bdev_ch[2]->io_locked));
2358 : :
2359 : 4 : set_thread(1);
2360 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 1);
2361 : 4 : stub_complete_io(io_target, 1);
2362 : 4 : set_thread(2);
2363 : 4 : CU_ASSERT(stub_channel_outstanding_cnt(io_target) == 1);
2364 : 4 : stub_complete_io(io_target, 1);
2365 : :
2366 : 4 : poll_threads();
2367 [ - + ]: 4 : CU_ASSERT(g_io_done == true);
2368 [ - + ]: 4 : CU_ASSERT(g_io_done2 == true);
2369 : :
2370 : : /* Tear down the channels */
2371 : 4 : set_thread(0);
2372 : 4 : spdk_put_io_channel(io_ch[0]);
2373 : 4 : set_thread(1);
2374 : 4 : spdk_put_io_channel(io_ch[1]);
2375 : 4 : set_thread(2);
2376 : 4 : spdk_put_io_channel(io_ch[2]);
2377 : 4 : poll_threads();
2378 : 4 : set_thread(0);
2379 : 4 : teardown_test();
2380 : 4 : }
2381 : :
2382 : : /* spdk_bdev_reset() freezes and unfreezes I/O channels by using spdk_for_each_channel().
2383 : : * spdk_bdev_unregister() calls spdk_io_device_unregister() in the end. However
2384 : : * spdk_io_device_unregister() fails if it is called while executing spdk_for_each_channel().
2385 : : * Hence, in this case, spdk_io_device_unregister() is deferred until spdk_bdev_reset()
2386 : : * completes. Test this behavior.
2387 : : */
2388 : : static void
2389 : 4 : unregister_during_reset(void)
2390 : : {
2391 : : struct spdk_io_channel *io_ch[2];
2392 : 4 : bool done_reset = false, done_unregister = false;
2393 : : int rc;
2394 : :
2395 : 4 : setup_test();
2396 : 4 : set_thread(0);
2397 : :
2398 : 4 : io_ch[0] = spdk_bdev_get_io_channel(g_desc);
2399 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(io_ch[0] != NULL);
2400 : :
2401 : 4 : set_thread(1);
2402 : :
2403 : 4 : io_ch[1] = spdk_bdev_get_io_channel(g_desc);
2404 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(io_ch[1] != NULL);
2405 : :
2406 : 4 : set_thread(0);
2407 : :
2408 : 4 : CU_ASSERT(g_bdev.bdev.internal.reset_in_progress == NULL);
2409 : :
2410 : 4 : rc = spdk_bdev_reset(g_desc, io_ch[0], reset_done, &done_reset);
2411 : 4 : CU_ASSERT(rc == 0);
2412 : :
2413 : 4 : set_thread(0);
2414 : :
2415 : 4 : poll_thread_times(0, 1);
2416 : :
2417 : 4 : spdk_bdev_close(g_desc);
2418 : 4 : spdk_bdev_unregister(&g_bdev.bdev, _bdev_unregistered, &done_unregister);
2419 : :
2420 [ - + ]: 4 : CU_ASSERT(done_reset == false);
2421 [ - + ]: 4 : CU_ASSERT(done_unregister == false);
2422 : :
2423 : 4 : poll_threads();
2424 : :
2425 : 4 : stub_complete_io(g_bdev.io_target, 0);
2426 : :
2427 : 4 : poll_threads();
2428 : :
2429 [ - + ]: 4 : CU_ASSERT(done_reset == true);
2430 [ - + ]: 4 : CU_ASSERT(done_unregister == false);
2431 : :
2432 : 4 : spdk_put_io_channel(io_ch[0]);
2433 : :
2434 : 4 : set_thread(1);
2435 : :
2436 : 4 : spdk_put_io_channel(io_ch[1]);
2437 : :
2438 : 4 : poll_threads();
2439 : :
2440 [ - + ]: 4 : CU_ASSERT(done_unregister == true);
2441 : :
2442 : : /* Restore the original g_bdev so that we can use teardown_test(). */
2443 : 4 : set_thread(0);
2444 : 4 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
2445 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
2446 : 4 : teardown_test();
2447 : 4 : }
2448 : :
2449 : : static void
2450 : 4 : bdev_init_wt_cb(void *done, int rc)
2451 : : {
2452 : 4 : }
2453 : :
2454 : : static int
2455 : 4 : wrong_thread_setup(void)
2456 : : {
2457 : 4 : allocate_cores(1);
2458 : 4 : allocate_threads(2);
2459 : 4 : set_thread(0);
2460 : :
2461 : 4 : spdk_io_device_register(&g_accel_io_device, ut_accel_ch_create_cb,
2462 : : ut_accel_ch_destroy_cb, 0, NULL);
2463 : 4 : spdk_bdev_initialize(bdev_init_wt_cb, NULL);
2464 : 4 : spdk_io_device_register(&g_io_device, stub_create_ch, stub_destroy_ch,
2465 : : sizeof(struct ut_bdev_channel), NULL);
2466 : :
2467 : 4 : set_thread(1);
2468 : :
2469 : 4 : return 0;
2470 : : }
2471 : :
2472 : : static int
2473 : 4 : wrong_thread_teardown(void)
2474 : : {
2475 : 4 : int rc = 0;
2476 : :
2477 : 4 : set_thread(0);
2478 : :
2479 : 4 : g_teardown_done = false;
2480 : 4 : spdk_io_device_unregister(&g_io_device, NULL);
2481 : 4 : spdk_bdev_finish(finish_cb, NULL);
2482 : 4 : poll_threads();
2483 [ - + ]: 4 : memset(&g_bdev, 0, sizeof(g_bdev));
2484 [ + + - + ]: 4 : if (!g_teardown_done) {
2485 [ # # # # ]: 0 : fprintf(stderr, "%s:%d %s: teardown not done\n", __FILE__, __LINE__, __func__);
2486 : 0 : rc = -1;
2487 : 0 : }
2488 : 4 : g_teardown_done = false;
2489 : :
2490 : 4 : spdk_io_device_unregister(&g_accel_io_device, NULL);
2491 : 4 : free_threads();
2492 : 4 : free_cores();
2493 : :
2494 : 4 : return rc;
2495 : : }
2496 : :
2497 : : static void
2498 : 8 : _bdev_unregistered_wt(void *ctx, int rc)
2499 : : {
2500 : 8 : struct spdk_thread **threadp = ctx;
2501 : :
2502 : 8 : *threadp = spdk_get_thread();
2503 : 8 : }
2504 : :
2505 : : static void
2506 : 4 : spdk_bdev_register_wt(void)
2507 : : {
2508 : 4 : struct spdk_bdev bdev = { 0 };
2509 : : int rc;
2510 : 3 : struct spdk_thread *unreg_thread;
2511 : :
2512 : 4 : bdev.name = "wt_bdev";
2513 : 4 : bdev.fn_table = &fn_table;
2514 : 4 : bdev.module = &bdev_ut_if;
2515 : 4 : bdev.blocklen = 4096;
2516 : 4 : bdev.blockcnt = 1024;
2517 : :
2518 : : /* Can register only on app thread */
2519 : 4 : rc = spdk_bdev_register(&bdev);
2520 : 4 : CU_ASSERT(rc == -EINVAL);
2521 : :
2522 : : /* Can unregister on any thread */
2523 : 4 : set_thread(0);
2524 : 4 : rc = spdk_bdev_register(&bdev);
2525 : 4 : CU_ASSERT(rc == 0);
2526 : 4 : set_thread(1);
2527 : 4 : unreg_thread = NULL;
2528 : 4 : spdk_bdev_unregister(&bdev, _bdev_unregistered_wt, &unreg_thread);
2529 : 4 : poll_threads();
2530 : 4 : CU_ASSERT(unreg_thread == spdk_get_thread());
2531 : :
2532 : : /* Can unregister by name on any thread */
2533 : 4 : set_thread(0);
2534 : 4 : rc = spdk_bdev_register(&bdev);
2535 : 4 : CU_ASSERT(rc == 0);
2536 : 4 : set_thread(1);
2537 : 4 : unreg_thread = NULL;
2538 : 4 : rc = spdk_bdev_unregister_by_name(bdev.name, bdev.module, _bdev_unregistered_wt,
2539 : : &unreg_thread);
2540 : 4 : CU_ASSERT(rc == 0);
2541 : 4 : poll_threads();
2542 : 4 : CU_ASSERT(unreg_thread == spdk_get_thread());
2543 : 4 : }
2544 : :
2545 : : static void
2546 : 8 : wait_for_examine_cb(void *arg)
2547 : : {
2548 : 8 : struct spdk_thread **thread = arg;
2549 : :
2550 : 8 : *thread = spdk_get_thread();
2551 : 8 : }
2552 : :
2553 : : static void
2554 : 4 : spdk_bdev_examine_wt(void)
2555 : : {
2556 : : int rc;
2557 [ - + ]: 4 : bool save_auto_examine = g_bdev_opts.bdev_auto_examine;
2558 : 3 : struct spdk_thread *thread;
2559 : :
2560 : 4 : g_bdev_opts.bdev_auto_examine = false;
2561 : :
2562 : 4 : set_thread(0);
2563 : 4 : register_bdev(&g_bdev, "ut_bdev_wt", &g_io_device);
2564 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") != NULL);
2565 : 4 : set_thread(1);
2566 : :
2567 : : /* Can examine only on the app thread */
2568 : 4 : rc = spdk_bdev_examine("ut_bdev_wt");
2569 : 4 : CU_ASSERT(rc == -EINVAL);
2570 : 4 : unregister_bdev(&g_bdev);
2571 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") == NULL);
2572 : :
2573 : : /* Can wait for examine on app thread, callback called on app thread. */
2574 : 4 : set_thread(0);
2575 : 4 : register_bdev(&g_bdev, "ut_bdev_wt", &g_io_device);
2576 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") != NULL);
2577 : 4 : thread = NULL;
2578 : 4 : rc = spdk_bdev_wait_for_examine(wait_for_examine_cb, &thread);
2579 : 4 : CU_ASSERT(rc == 0);
2580 : 4 : poll_threads();
2581 : 4 : CU_ASSERT(thread == spdk_get_thread());
2582 : 4 : unregister_bdev(&g_bdev);
2583 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") == NULL);
2584 : :
2585 : : /* Can wait for examine on non-app thread, callback called on same thread. */
2586 : 4 : set_thread(0);
2587 : 4 : register_bdev(&g_bdev, "ut_bdev_wt", &g_io_device);
2588 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") != NULL);
2589 : 4 : thread = NULL;
2590 : 4 : rc = spdk_bdev_wait_for_examine(wait_for_examine_cb, &thread);
2591 : 4 : CU_ASSERT(rc == 0);
2592 : 4 : poll_threads();
2593 : 4 : CU_ASSERT(thread == spdk_get_thread());
2594 : 4 : unregister_bdev(&g_bdev);
2595 : 4 : CU_ASSERT(spdk_bdev_get_by_name("ut_bdev_wt") == NULL);
2596 : :
2597 : 4 : unregister_bdev(&g_bdev);
2598 : 4 : g_bdev_opts.bdev_auto_examine = save_auto_examine;
2599 : 4 : }
2600 : :
2601 : : static void
2602 : 4 : event_notify_and_close(void)
2603 : : {
2604 : 4 : int resize_notify_count = 0;
2605 : 4 : struct spdk_bdev_desc *desc = NULL;
2606 : : struct spdk_bdev *bdev;
2607 : : int rc;
2608 : :
2609 : 4 : setup_test();
2610 : 4 : set_thread(0);
2611 : :
2612 : : /* setup_test() automatically opens the bdev, but this test needs to do
2613 : : * that in a different way. */
2614 : 4 : spdk_bdev_close(g_desc);
2615 : 4 : poll_threads();
2616 : :
2617 : 4 : set_thread(1);
2618 : :
2619 : 4 : rc = spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, &resize_notify_count, &desc);
2620 : 4 : CU_ASSERT(rc == 0);
2621 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(desc != NULL);
2622 : :
2623 : 4 : bdev = spdk_bdev_desc_get_bdev(desc);
2624 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev != NULL);
2625 : :
2626 : : /* Test a normal case that a resize event is notified. */
2627 : 4 : set_thread(0);
2628 : :
2629 : 4 : rc = spdk_bdev_notify_blockcnt_change(bdev, 1024 * 2);
2630 : 4 : CU_ASSERT(rc == 0);
2631 : 4 : CU_ASSERT(bdev->blockcnt == 1024 * 2);
2632 : 4 : CU_ASSERT(desc->refs == 1);
2633 : 4 : CU_ASSERT(resize_notify_count == 0);
2634 : :
2635 : 4 : poll_threads();
2636 : :
2637 : 4 : CU_ASSERT(desc->refs == 0);
2638 : 4 : CU_ASSERT(resize_notify_count == 1);
2639 : :
2640 : : /* Test a complex case if the bdev is closed after two event_notify messages are sent,
2641 : : * then both event_notify messages are discarded and the desc is freed.
2642 : : */
2643 : 4 : rc = spdk_bdev_notify_blockcnt_change(bdev, 1024 * 3);
2644 : 4 : CU_ASSERT(rc == 0);
2645 : 4 : CU_ASSERT(bdev->blockcnt == 1024 * 3);
2646 : 4 : CU_ASSERT(desc->refs == 1);
2647 : 4 : CU_ASSERT(resize_notify_count == 1);
2648 : :
2649 : 4 : rc = spdk_bdev_notify_blockcnt_change(bdev, 1024 * 4);
2650 : 4 : CU_ASSERT(rc == 0);
2651 : 4 : CU_ASSERT(bdev->blockcnt == 1024 * 4);
2652 : 4 : CU_ASSERT(desc->refs == 2);
2653 : 4 : CU_ASSERT(resize_notify_count == 1);
2654 : :
2655 : 4 : set_thread(1);
2656 : :
2657 : 4 : spdk_bdev_close(desc);
2658 [ - + ]: 4 : CU_ASSERT(desc->closed == true);
2659 : 4 : CU_ASSERT(desc->refs == 2);
2660 : 4 : CU_ASSERT(resize_notify_count == 1);
2661 : :
2662 : 4 : poll_threads();
2663 : :
2664 : 4 : CU_ASSERT(resize_notify_count == 1);
2665 : :
2666 : 4 : set_thread(0);
2667 : :
2668 : : /* Restore g_desc. Then, we can execute teardown_test(). */
2669 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
2670 : 4 : teardown_test();
2671 : 4 : }
2672 : :
2673 : : /* There was a bug that bdev_channel_poll_qos() called spdk_for_each_channel()
2674 : : * after spdk_io_device_unregister() is called for a bdev.
2675 : : *
2676 : : * This occurred in the following sequence.
2677 : : * - There was a bdev and a channel for it.
2678 : : * - QoS was enabled and started.
2679 : : * - spdk_bdev_unregister() was called. However, there was a open descriptor.
2680 : : * Hence, remove notification was sent and unregistration was pending.
2681 : : * - Receiving a event notification, spdk_put_io_channel() and spdk_bdev_close() were
2682 : : * called. In spdk_bdev_close(), the existing QoS was unbound and a message was sent
2683 : : * to it, and then the pending spdk_io_device_unregister() was finally executed.
2684 : : * - If bdev_channel_poll_qos() was executed before the message was processed,
2685 : : * bdev_channel_poll_qos() called spdk_bdev_for_each_channel() and hit assert().
2686 : : *
2687 : : * The fix was in this case bdev_channel_poll_qos() returned immediately because QoS
2688 : : * was not enabled. bdev_qos_destroy() created a new disabled QoS and swapped it with
2689 : : * the existing QoS.
2690 : : *
2691 : : * This test case was added to avoid degradation in future.
2692 : : */
2693 : : static void
2694 : 4 : unregister_and_qos_poller(void)
2695 : : {
2696 : : struct spdk_io_channel *io_ch;
2697 : : struct spdk_bdev_channel *bdev_ch;
2698 : 4 : struct spdk_bdev_desc *desc = NULL;
2699 : : struct spdk_bdev_qos *old_qos;
2700 : 4 : uint64_t limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES] = {};
2701 : 4 : bool remove_notify = false, done_unregister = false;
2702 : 4 : int status = -1, rc;
2703 : :
2704 : 4 : setup_test();
2705 : 4 : set_thread(0);
2706 : :
2707 : 4 : MOCK_SET(spdk_get_ticks, 10);
2708 : :
2709 : : /* setup_test() automatically opens the bdev, but this test needs to do
2710 : : * that in a different way.
2711 : : */
2712 : 4 : spdk_bdev_close(g_desc);
2713 : 4 : poll_threads();
2714 : :
2715 : : /* We want to get remove event notification to check if unregistration
2716 : : * is deferred.
2717 : : */
2718 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, &remove_notify, &desc);
2719 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(desc != NULL);
2720 [ - + ]: 4 : CU_ASSERT(remove_notify == false);
2721 : :
2722 : 4 : io_ch = spdk_bdev_get_io_channel(desc);
2723 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(io_ch != NULL);
2724 : 4 : bdev_ch = spdk_io_channel_get_ctx(io_ch);
2725 : :
2726 : 4 : limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT] = 10000;
2727 : 4 : limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT] = 0;
2728 : 4 : limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT] = 0;
2729 : 4 : limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT] = 0;
2730 : 4 : spdk_bdev_set_qos_rate_limits(&g_bdev.bdev, limits, qos_dynamic_enable_done, &status);
2731 : 4 : poll_threads();
2732 : 4 : CU_ASSERT(status == 0);
2733 : 4 : CU_ASSERT((bdev_ch->flags & BDEV_CH_QOS_ENABLED) != 0);
2734 : :
2735 : 4 : old_qos = g_bdev.bdev.internal.qos;
2736 : 4 : CU_ASSERT(old_qos != NULL);
2737 : :
2738 : 4 : spdk_bdev_unregister(&g_bdev.bdev, _bdev_unregistered, &done_unregister);
2739 [ - + ]: 4 : CU_ASSERT(done_unregister == false);
2740 [ - + ]: 4 : CU_ASSERT(remove_notify == false);
2741 : :
2742 : 4 : poll_threads();
2743 [ - + ]: 4 : CU_ASSERT(done_unregister == false);
2744 [ - + ]: 4 : CU_ASSERT(remove_notify == true);
2745 : :
2746 : 4 : spdk_put_io_channel(io_ch);
2747 : 4 : spdk_bdev_close(desc);
2748 : :
2749 : 4 : CU_ASSERT(g_bdev.bdev.internal.qos != NULL);
2750 : 4 : CU_ASSERT(g_bdev.bdev.internal.qos->thread == NULL);
2751 : 4 : CU_ASSERT(old_qos != g_bdev.bdev.internal.qos);
2752 : :
2753 : : /* bdev_channel_poll_qos() has a chance to be executed in this small window. */
2754 : 4 : spdk_delay_us(SPDK_BDEV_QOS_TIMESLICE_IN_USEC);
2755 : :
2756 : 4 : rc = bdev_channel_poll_qos(&g_bdev.bdev);
2757 : 4 : CU_ASSERT(rc == SPDK_POLLER_IDLE);
2758 : :
2759 : 4 : poll_threads();
2760 : :
2761 [ - + ]: 4 : CU_ASSERT(done_unregister == true);
2762 : :
2763 : : /* Restore the original g_bdev so that we can use teardown_test(). */
2764 : 4 : set_thread(0);
2765 : 4 : register_bdev(&g_bdev, "ut_bdev", &g_io_device);
2766 : 4 : spdk_bdev_open_ext("ut_bdev", true, _bdev_event_cb, NULL, &g_desc);
2767 : 4 : teardown_test();
2768 : 4 : }
2769 : :
2770 : : int
2771 : 4 : main(int argc, char **argv)
2772 : : {
2773 : 4 : CU_pSuite suite = NULL;
2774 : 4 : CU_pSuite suite_wt = NULL;
2775 : : unsigned int num_failures;
2776 : :
2777 : 4 : CU_initialize_registry();
2778 : :
2779 : 4 : suite = CU_add_suite("bdev", NULL, NULL);
2780 : 4 : suite_wt = CU_add_suite("bdev_wrong_thread", wrong_thread_setup, wrong_thread_teardown);
2781 : :
2782 : 4 : CU_ADD_TEST(suite, basic);
2783 : 4 : CU_ADD_TEST(suite, unregister_and_close);
2784 : 4 : CU_ADD_TEST(suite, unregister_and_close_different_threads);
2785 : 4 : CU_ADD_TEST(suite, basic_qos);
2786 : 4 : CU_ADD_TEST(suite, put_channel_during_reset);
2787 : 4 : CU_ADD_TEST(suite, aborted_reset);
2788 : 4 : CU_ADD_TEST(suite, aborted_reset_no_outstanding_io);
2789 : 4 : CU_ADD_TEST(suite, io_during_reset);
2790 : 4 : CU_ADD_TEST(suite, reset_completions);
2791 : 4 : CU_ADD_TEST(suite, io_during_qos_queue);
2792 : 4 : CU_ADD_TEST(suite, io_during_qos_reset);
2793 : 4 : CU_ADD_TEST(suite, enomem);
2794 : 4 : CU_ADD_TEST(suite, enomem_multi_bdev);
2795 : 4 : CU_ADD_TEST(suite, enomem_multi_bdev_unregister);
2796 : 4 : CU_ADD_TEST(suite, enomem_multi_io_target);
2797 : 4 : CU_ADD_TEST(suite, qos_dynamic_enable);
2798 : 4 : CU_ADD_TEST(suite, bdev_histograms_mt);
2799 : 4 : CU_ADD_TEST(suite, bdev_set_io_timeout_mt);
2800 : 4 : CU_ADD_TEST(suite, lock_lba_range_then_submit_io);
2801 : 4 : CU_ADD_TEST(suite, unregister_during_reset);
2802 : 4 : CU_ADD_TEST(suite_wt, spdk_bdev_register_wt);
2803 : 4 : CU_ADD_TEST(suite_wt, spdk_bdev_examine_wt);
2804 : 4 : CU_ADD_TEST(suite, event_notify_and_close);
2805 : 4 : CU_ADD_TEST(suite, unregister_and_qos_poller);
2806 : :
2807 : 4 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
2808 : 4 : CU_cleanup_registry();
2809 : 4 : return num_failures;
2810 : : }
|