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