4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/stdinc.h"
36 #include "spdk_cunit.h"
37 #include "common/lib/test_env.c"
39 #include "ftl/ftl_reloc.c"
40 #include "../common/utils.c"
42 #define MAX_ACTIVE_RELOCS 5
43 #define MAX_RELOC_QDEPTH 31
45 static struct spdk_ocssd_geometry_data g_geo
= {
54 static struct spdk_ftl_punit_range g_range
= {
59 DEFINE_STUB(ftl_dev_tail_md_disk_size
, size_t, (const struct spdk_ftl_dev
*dev
), 1);
60 DEFINE_STUB_V(ftl_band_set_state
, (struct ftl_band
*band
, enum ftl_band_state state
));
61 DEFINE_STUB_V(ftl_trace_lba_io_init
, (struct spdk_ftl_dev
*dev
, const struct ftl_io
*io
));
62 DEFINE_STUB_V(ftl_free_io
, (struct ftl_io
*io
));
65 ftl_band_alloc_lba_map(struct ftl_band
*band
)
67 struct spdk_ftl_dev
*dev
= band
->dev
;
69 ftl_band_acquire_lba_map(band
);
70 band
->lba_map
.map
= spdk_mempool_get(dev
->lba_pool
);
76 ftl_band_release_lba_map(struct ftl_band
*band
)
78 struct spdk_ftl_dev
*dev
= band
->dev
;
80 band
->lba_map
.ref_cnt
--;
81 spdk_mempool_put(dev
->lba_pool
, band
->lba_map
.map
);
82 band
->lba_map
.map
= NULL
;
86 ftl_band_acquire_lba_map(struct ftl_band
*band
)
88 band
->lba_map
.ref_cnt
++;
92 ftl_lba_map_num_lbks(const struct spdk_ftl_dev
*dev
)
94 return spdk_divide_round_up(ftl_num_band_lbks(dev
) * sizeof(uint64_t), FTL_BLOCK_SIZE
);
98 ftl_band_read_lba_map(struct ftl_band
*band
, size_t offset
,
99 size_t lbk_cnt
, ftl_io_fn fn
, void *ctx
)
106 ftl_band_lbkoff_from_ppa(struct ftl_band
*band
, struct ftl_ppa ppa
)
108 return test_offset_from_ppa(ppa
, band
);
112 ftl_band_ppa_from_lbkoff(struct ftl_band
*band
, uint64_t lbkoff
)
114 struct ftl_ppa ppa
= { .ppa
= 0 };
115 struct spdk_ftl_dev
*dev
= band
->dev
;
118 punit
= lbkoff
/ ftl_dev_lbks_in_chunk(dev
) + dev
->range
.begin
;
120 ppa
.lbk
= lbkoff
% ftl_dev_lbks_in_chunk(dev
);
122 ppa
.pu
= punit
/ dev
->geo
.num_grp
;
123 ppa
.grp
= punit
% dev
->geo
.num_grp
;
129 ftl_io_read(struct ftl_io
*io
)
131 io
->cb_fn(io
, io
->cb_ctx
, 0);
136 ftl_io_write(struct ftl_io
*io
)
138 io
->cb_fn(io
, io
->cb_ctx
, 0);
139 free(io
->lba
.vector
);
144 ftl_io_init_internal(const struct ftl_io_init_opts
*opts
)
146 struct ftl_io
*io
= opts
->io
;
149 io
= calloc(1, opts
->size
);
152 SPDK_CU_ASSERT_FATAL(io
!= NULL
);
155 io
->band
= opts
->band
;
156 io
->flags
= opts
->flags
;
157 io
->cb_fn
= opts
->cb_fn
;
159 io
->lbk_cnt
= opts
->lbk_cnt
;
160 io
->iov
[0].iov_base
= opts
->data
;
162 if (opts
->flags
& FTL_IO_VECTOR_LBA
) {
163 io
->lba
.vector
= calloc(io
->lbk_cnt
, sizeof(uint64_t));
164 SPDK_CU_ASSERT_FATAL(io
->lba
.vector
!= NULL
);
171 ftl_io_alloc(struct spdk_io_channel
*ch
)
173 size_t io_size
= sizeof(struct ftl_md_io
);
175 return malloc(io_size
);
179 ftl_io_reinit(struct ftl_io
*io
, ftl_io_fn fn
, void *ctx
, int flags
, int type
)
187 single_reloc_move(struct ftl_band_reloc
*breloc
)
190 ftl_process_reloc(breloc
);
191 /* Process lba map read */
192 ftl_process_reloc(breloc
);
194 ftl_process_reloc(breloc
);
198 setup_reloc(struct spdk_ftl_dev
**_dev
, struct ftl_reloc
**_reloc
,
199 const struct spdk_ocssd_geometry_data
*geo
, const struct spdk_ftl_punit_range
*range
)
202 struct spdk_ftl_dev
*dev
;
203 struct ftl_reloc
*reloc
;
205 dev
= test_init_ftl_dev(geo
, range
);
206 dev
->conf
.max_active_relocs
= MAX_ACTIVE_RELOCS
;
207 dev
->conf
.max_reloc_qdepth
= MAX_RELOC_QDEPTH
;
209 SPDK_CU_ASSERT_FATAL(ftl_dev_num_bands(dev
) > 0);
211 for (i
= 0; i
< ftl_dev_num_bands(dev
); ++i
) {
212 test_init_ftl_band(dev
, i
);
215 reloc
= ftl_reloc_init(dev
);
217 CU_ASSERT_PTR_NOT_NULL_FATAL(reloc
);
218 ftl_reloc_resume(reloc
);
225 cleanup_reloc(struct spdk_ftl_dev
*dev
, struct ftl_reloc
*reloc
)
229 for (i
= 0; i
< ftl_dev_num_bands(reloc
->dev
); ++i
) {
230 SPDK_CU_ASSERT_FATAL(reloc
->brelocs
[i
].active
== false);
233 ftl_reloc_free(reloc
);
235 for (i
= 0; i
< ftl_dev_num_bands(dev
); ++i
) {
236 test_free_ftl_band(&dev
->bands
[i
]);
238 test_free_ftl_dev(dev
);
242 set_band_valid_map(struct ftl_band
*band
, size_t offset
, size_t num_lbks
)
244 struct ftl_lba_map
*lba_map
= &band
->lba_map
;
247 SPDK_CU_ASSERT_FATAL(lba_map
!= NULL
);
248 for (i
= offset
; i
< offset
+ num_lbks
; ++i
) {
249 spdk_bit_array_set(lba_map
->vld
, i
);
255 test_reloc_iter_full(void)
257 size_t num_lbks
, num_iters
, reminder
, i
;
258 struct spdk_ftl_dev
*dev
;
259 struct ftl_reloc
*reloc
;
260 struct ftl_band_reloc
*breloc
;
261 struct ftl_band
*band
;
264 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
267 breloc
= &reloc
->brelocs
[0];
270 set_band_valid_map(band
, 0, ftl_num_band_lbks(dev
));
272 ftl_reloc_add(reloc
, band
, 0, ftl_num_band_lbks(dev
), 0);
274 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
276 num_iters
= ftl_dev_num_punits(dev
) *
277 (ftl_dev_lbks_in_chunk(dev
) / reloc
->xfer_size
);
279 for (i
= 0; i
< num_iters
; i
++) {
280 num_lbks
= ftl_reloc_next_lbks(breloc
, &ppa
);
281 CU_ASSERT_EQUAL(num_lbks
, reloc
->xfer_size
);
284 num_iters
= ftl_dev_num_punits(dev
);
286 /* ftl_reloc_next_lbks is searching for maximum xfer_size */
287 /* contiguous valid logic blocks in chunk, so we can end up */
288 /* with some reminder if number of logical blocks in chunk */
289 /* is not divisible by xfer_size */
290 reminder
= ftl_dev_lbks_in_chunk(dev
) % reloc
->xfer_size
;
291 for (i
= 0; i
< num_iters
; i
++) {
292 num_lbks
= ftl_reloc_next_lbks(breloc
, &ppa
);
293 CU_ASSERT_EQUAL(reminder
, num_lbks
);
296 /* num_lbks should remain intact since all the blocks are valid */
297 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
299 cleanup_reloc(dev
, reloc
);
303 test_reloc_iter_empty(void)
305 struct spdk_ftl_dev
*dev
;
306 struct ftl_reloc
*reloc
;
307 struct ftl_band_reloc
*breloc
;
308 struct ftl_band
*band
;
311 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
313 breloc
= &reloc
->brelocs
[0];
316 ftl_reloc_add(reloc
, band
, 0, ftl_num_band_lbks(dev
), 0);
318 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
319 CU_ASSERT_EQUAL(0, ftl_reloc_next_lbks(breloc
, &ppa
));
320 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
322 cleanup_reloc(dev
, reloc
);
326 test_reloc_full_band(void)
328 struct spdk_ftl_dev
*dev
;
329 struct ftl_reloc
*reloc
;
330 struct ftl_band_reloc
*breloc
;
331 struct ftl_band
*band
;
332 size_t num_moves
, num_iters
, num_lbk
, i
;
334 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
336 breloc
= &reloc
->brelocs
[0];
338 num_moves
= MAX_RELOC_QDEPTH
* reloc
->xfer_size
;
339 num_iters
= ftl_num_band_lbks(dev
) / num_moves
;
341 set_band_valid_map(band
, 0, ftl_num_band_lbks(dev
));
343 ftl_reloc_add(reloc
, band
, 0, ftl_num_band_lbks(dev
), 0);
345 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
347 ftl_reloc_add_active_queue(breloc
);
349 for (i
= 1; i
<= num_iters
; ++i
) {
350 single_reloc_move(breloc
);
351 num_lbk
= ftl_num_band_lbks(dev
) - (i
* num_moves
);
352 CU_ASSERT_EQUAL(breloc
->num_lbks
, num_lbk
);
356 /* Process reminder lbks */
357 single_reloc_move(breloc
);
358 /* Drain move queue */
359 ftl_reloc_process_moves(breloc
);
361 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
362 CU_ASSERT_TRUE(ftl_reloc_done(breloc
));
363 ftl_reloc_release(breloc
);
365 cleanup_reloc(dev
, reloc
);
369 test_reloc_scatter_band(void)
371 struct spdk_ftl_dev
*dev
;
372 struct ftl_reloc
*reloc
;
373 struct ftl_band_reloc
*breloc
;
374 struct ftl_band
*band
;
377 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
379 breloc
= &reloc
->brelocs
[0];
381 num_iters
= ftl_num_band_lbks(dev
) / MAX_RELOC_QDEPTH
;
383 for (i
= 0; i
< ftl_num_band_lbks(dev
); ++i
) {
385 set_band_valid_map(band
, i
, 1);
389 ftl_reloc_add(reloc
, band
, 0, ftl_num_band_lbks(dev
), 0);
390 ftl_reloc_add_active_queue(breloc
);
392 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
394 for (i
= 0; i
< num_iters
; ++i
) {
395 single_reloc_move(breloc
);
398 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
399 CU_ASSERT_TRUE(ftl_reloc_done(breloc
));
400 ftl_reloc_release(breloc
);
402 cleanup_reloc(dev
, reloc
);
406 test_reloc_chunk(void)
408 struct spdk_ftl_dev
*dev
;
409 struct ftl_reloc
*reloc
;
410 struct ftl_band_reloc
*breloc
;
411 struct ftl_band
*band
;
412 size_t num_io
, num_iters
, num_lbk
, i
;
414 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
416 breloc
= &reloc
->brelocs
[0];
418 num_io
= MAX_RELOC_QDEPTH
* reloc
->xfer_size
;
419 num_iters
= ftl_dev_lbks_in_chunk(dev
) / num_io
;
421 set_band_valid_map(band
, 0, ftl_num_band_lbks(dev
));
423 ftl_reloc_add(reloc
, band
, ftl_dev_lbks_in_chunk(dev
) * 3,
424 ftl_dev_lbks_in_chunk(dev
), 1);
425 ftl_reloc_add_active_queue(breloc
);
427 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_dev_lbks_in_chunk(dev
));
429 for (i
= 1; i
<= num_iters
; ++i
) {
430 single_reloc_move(breloc
);
431 num_lbk
= ftl_dev_lbks_in_chunk(dev
) - (i
* num_io
);
433 CU_ASSERT_EQUAL(breloc
->num_lbks
, num_lbk
);
436 /* In case num_lbks_in_chunk % num_io != 0 one extra iteration is needed */
437 single_reloc_move(breloc
);
438 /* Drain move queue */
439 ftl_reloc_process_moves(breloc
);
441 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
442 CU_ASSERT_TRUE(ftl_reloc_done(breloc
));
443 ftl_reloc_release(breloc
);
445 cleanup_reloc(dev
, reloc
);
449 test_reloc_single_lbk(void)
451 struct spdk_ftl_dev
*dev
;
452 struct ftl_reloc
*reloc
;
453 struct ftl_band_reloc
*breloc
;
454 struct ftl_band
*band
;
455 #define TEST_RELOC_OFFSET 6
457 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
459 breloc
= &reloc
->brelocs
[0];
462 set_band_valid_map(band
, TEST_RELOC_OFFSET
, 1);
464 ftl_reloc_add(reloc
, band
, TEST_RELOC_OFFSET
, 1, 0);
465 ftl_reloc_add_active_queue(breloc
);
467 CU_ASSERT_EQUAL(breloc
->num_lbks
, 1);
469 single_reloc_move(breloc
);
470 /* Drain move queue */
471 ftl_reloc_process_moves(breloc
);
473 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
474 CU_ASSERT_TRUE(ftl_reloc_done(breloc
));
475 ftl_reloc_release(breloc
);
477 cleanup_reloc(dev
, reloc
);
481 test_reloc_empty_band(void)
483 struct spdk_ftl_dev
*dev
;
484 struct ftl_reloc
*reloc
;
485 struct ftl_band_reloc
*breloc
;
486 struct ftl_band
*band
;
488 setup_reloc(&dev
, &reloc
, &g_geo
, &g_range
);
490 breloc
= &reloc
->brelocs
[0];
493 ftl_reloc_add(reloc
, band
, 0, ftl_num_band_lbks(dev
), 0);
495 CU_ASSERT_EQUAL(breloc
->num_lbks
, ftl_num_band_lbks(dev
));
499 CU_ASSERT_EQUAL(breloc
->num_lbks
, 0);
500 SPDK_CU_ASSERT_FATAL(breloc
->moves
!= NULL
);
502 cleanup_reloc(dev
, reloc
);
506 main(int argc
, char **argv
)
508 CU_pSuite suite
= NULL
;
509 unsigned int num_failures
;
511 if (CU_initialize_registry() != CUE_SUCCESS
) {
512 return CU_get_error();
515 suite
= CU_add_suite("ftl_band_suite", NULL
, NULL
);
517 CU_cleanup_registry();
518 return CU_get_error();
522 CU_add_test(suite
, "test_reloc_iter_full",
523 test_reloc_iter_full
) == NULL
524 || CU_add_test(suite
, "test_reloc_iter_empty",
525 test_reloc_iter_empty
) == NULL
526 || CU_add_test(suite
, "test_reloc_empty_band",
527 test_reloc_empty_band
) == NULL
528 || CU_add_test(suite
, "test_reloc_full_band",
529 test_reloc_full_band
) == NULL
530 || CU_add_test(suite
, "test_reloc_scatter_band",
531 test_reloc_scatter_band
) == NULL
532 || CU_add_test(suite
, "test_reloc_chunk",
533 test_reloc_chunk
) == NULL
534 || CU_add_test(suite
, "test_reloc_single_lbk",
535 test_reloc_single_lbk
) == NULL
537 CU_cleanup_registry();
538 return CU_get_error();
541 CU_basic_set_mode(CU_BRM_VERBOSE
);
542 CU_basic_run_tests();
543 num_failures
= CU_get_number_of_failures();
544 CU_cleanup_registry();