]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / unit / lib / ftl / ftl_reloc.c / ftl_reloc_ut.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
16 * distribution.
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.
20 *
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.
32 */
33
34 #include "spdk/stdinc.h"
35
36 #include "spdk_cunit.h"
37 #include "common/lib/test_env.c"
38
39 #include "ftl/ftl_reloc.c"
40 #include "../common/utils.c"
41
42 #define MAX_ACTIVE_RELOCS 5
43 #define MAX_RELOC_QDEPTH 31
44
45 static struct spdk_ocssd_geometry_data g_geo = {
46 .num_grp = 4,
47 .num_pu = 3,
48 .num_chk = 500,
49 .clba = 100,
50 .ws_opt = 16,
51 .ws_min = 4,
52 };
53
54 static struct spdk_ftl_punit_range g_range = {
55 .begin = 2,
56 .end = 9,
57 };
58
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));
63
64 int
65 ftl_band_alloc_lba_map(struct ftl_band *band)
66 {
67 struct spdk_ftl_dev *dev = band->dev;
68
69 ftl_band_acquire_lba_map(band);
70 band->lba_map.map = spdk_mempool_get(dev->lba_pool);
71
72 return 0;
73 }
74
75 void
76 ftl_band_release_lba_map(struct ftl_band *band)
77 {
78 struct spdk_ftl_dev *dev = band->dev;
79
80 band->lba_map.ref_cnt--;
81 spdk_mempool_put(dev->lba_pool, band->lba_map.map);
82 band->lba_map.map = NULL;
83 }
84
85 void
86 ftl_band_acquire_lba_map(struct ftl_band *band)
87 {
88 band->lba_map.ref_cnt++;
89 }
90
91 size_t
92 ftl_lba_map_num_lbks(const struct spdk_ftl_dev *dev)
93 {
94 return spdk_divide_round_up(ftl_num_band_lbks(dev) * sizeof(uint64_t), FTL_BLOCK_SIZE);
95 }
96
97 int
98 ftl_band_read_lba_map(struct ftl_band *band, size_t offset,
99 size_t lbk_cnt, ftl_io_fn fn, void *ctx)
100 {
101 fn(ctx, ctx, 0);
102 return 0;
103 }
104
105 uint64_t
106 ftl_band_lbkoff_from_ppa(struct ftl_band *band, struct ftl_ppa ppa)
107 {
108 return test_offset_from_ppa(ppa, band);
109 }
110
111 struct ftl_ppa
112 ftl_band_ppa_from_lbkoff(struct ftl_band *band, uint64_t lbkoff)
113 {
114 struct ftl_ppa ppa = { .ppa = 0 };
115 struct spdk_ftl_dev *dev = band->dev;
116 uint64_t punit;
117
118 punit = lbkoff / ftl_dev_lbks_in_chunk(dev) + dev->range.begin;
119
120 ppa.lbk = lbkoff % ftl_dev_lbks_in_chunk(dev);
121 ppa.chk = band->id;
122 ppa.pu = punit / dev->geo.num_grp;
123 ppa.grp = punit % dev->geo.num_grp;
124
125 return ppa;
126 }
127
128 void
129 ftl_io_read(struct ftl_io *io)
130 {
131 io->cb_fn(io, io->cb_ctx, 0);
132 free(io);
133 }
134
135 void
136 ftl_io_write(struct ftl_io *io)
137 {
138 io->cb_fn(io, io->cb_ctx, 0);
139 free(io->lba.vector);
140 free(io);
141 }
142
143 struct ftl_io *
144 ftl_io_init_internal(const struct ftl_io_init_opts *opts)
145 {
146 struct ftl_io *io = opts->io;
147
148 if (!io) {
149 io = calloc(1, opts->size);
150 }
151
152 SPDK_CU_ASSERT_FATAL(io != NULL);
153
154 io->dev = opts->dev;
155 io->band = opts->band;
156 io->flags = opts->flags;
157 io->cb_fn = opts->cb_fn;
158 io->cb_ctx = io;
159 io->lbk_cnt = opts->lbk_cnt;
160 io->iov[0].iov_base = opts->data;
161
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);
165 }
166
167 return io;
168 }
169
170 struct ftl_io *
171 ftl_io_alloc(struct spdk_io_channel *ch)
172 {
173 size_t io_size = sizeof(struct ftl_md_io);
174
175 return malloc(io_size);
176 }
177
178 void
179 ftl_io_reinit(struct ftl_io *io, ftl_io_fn fn, void *ctx, int flags, int type)
180 {
181 io->cb_fn = fn;
182 io->cb_ctx = ctx;
183 io->type = type;
184 }
185
186 static void
187 single_reloc_move(struct ftl_band_reloc *breloc)
188 {
189 /* Process read */
190 ftl_process_reloc(breloc);
191 /* Process lba map read */
192 ftl_process_reloc(breloc);
193 /* Process write */
194 ftl_process_reloc(breloc);
195 }
196
197 static void
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)
200 {
201 size_t i;
202 struct spdk_ftl_dev *dev;
203 struct ftl_reloc *reloc;
204
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;
208
209 SPDK_CU_ASSERT_FATAL(ftl_dev_num_bands(dev) > 0);
210
211 for (i = 0; i < ftl_dev_num_bands(dev); ++i) {
212 test_init_ftl_band(dev, i);
213 }
214
215 reloc = ftl_reloc_init(dev);
216 dev->reloc = reloc;
217 CU_ASSERT_PTR_NOT_NULL_FATAL(reloc);
218 ftl_reloc_resume(reloc);
219
220 *_dev = dev;
221 *_reloc = reloc;
222 }
223
224 static void
225 cleanup_reloc(struct spdk_ftl_dev *dev, struct ftl_reloc *reloc)
226 {
227 size_t i;
228
229 for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) {
230 SPDK_CU_ASSERT_FATAL(reloc->brelocs[i].active == false);
231 }
232
233 ftl_reloc_free(reloc);
234
235 for (i = 0; i < ftl_dev_num_bands(dev); ++i) {
236 test_free_ftl_band(&dev->bands[i]);
237 }
238 test_free_ftl_dev(dev);
239 }
240
241 static void
242 set_band_valid_map(struct ftl_band *band, size_t offset, size_t num_lbks)
243 {
244 struct ftl_lba_map *lba_map = &band->lba_map;
245 size_t i;
246
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);
250 lba_map->num_vld++;
251 }
252 }
253
254 static void
255 test_reloc_iter_full(void)
256 {
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;
262 struct ftl_ppa ppa;
263
264 setup_reloc(&dev, &reloc, &g_geo, &g_range);
265
266 dev->geo.clba = 100;
267 breloc = &reloc->brelocs[0];
268 band = breloc->band;
269
270 set_band_valid_map(band, 0, ftl_num_band_lbks(dev));
271
272 ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
273
274 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
275
276 num_iters = ftl_dev_num_punits(dev) *
277 (ftl_dev_lbks_in_chunk(dev) / reloc->xfer_size);
278
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);
282 }
283
284 num_iters = ftl_dev_num_punits(dev);
285
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);
294 }
295
296 /* num_lbks should remain intact since all the blocks are valid */
297 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
298
299 cleanup_reloc(dev, reloc);
300 }
301
302 static void
303 test_reloc_iter_empty(void)
304 {
305 struct spdk_ftl_dev *dev;
306 struct ftl_reloc *reloc;
307 struct ftl_band_reloc *breloc;
308 struct ftl_band *band;
309 struct ftl_ppa ppa;
310
311 setup_reloc(&dev, &reloc, &g_geo, &g_range);
312
313 breloc = &reloc->brelocs[0];
314 band = breloc->band;
315
316 ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
317
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);
321
322 cleanup_reloc(dev, reloc);
323 }
324
325 static void
326 test_reloc_full_band(void)
327 {
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;
333
334 setup_reloc(&dev, &reloc, &g_geo, &g_range);
335
336 breloc = &reloc->brelocs[0];
337 band = breloc->band;
338 num_moves = MAX_RELOC_QDEPTH * reloc->xfer_size;
339 num_iters = ftl_num_band_lbks(dev) / num_moves;
340
341 set_band_valid_map(band, 0, ftl_num_band_lbks(dev));
342
343 ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
344
345 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
346
347 ftl_reloc_add_active_queue(breloc);
348
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);
353
354 }
355
356 /* Process reminder lbks */
357 single_reloc_move(breloc);
358 /* Drain move queue */
359 ftl_reloc_process_moves(breloc);
360
361 CU_ASSERT_EQUAL(breloc->num_lbks, 0);
362 CU_ASSERT_TRUE(ftl_reloc_done(breloc));
363 ftl_reloc_release(breloc);
364
365 cleanup_reloc(dev, reloc);
366 }
367
368 static void
369 test_reloc_scatter_band(void)
370 {
371 struct spdk_ftl_dev *dev;
372 struct ftl_reloc *reloc;
373 struct ftl_band_reloc *breloc;
374 struct ftl_band *band;
375 size_t num_iters, i;
376
377 setup_reloc(&dev, &reloc, &g_geo, &g_range);
378
379 breloc = &reloc->brelocs[0];
380 band = breloc->band;
381 num_iters = ftl_num_band_lbks(dev) / MAX_RELOC_QDEPTH;
382
383 for (i = 0; i < ftl_num_band_lbks(dev); ++i) {
384 if (i % 2) {
385 set_band_valid_map(band, i, 1);
386 }
387 }
388
389 ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
390 ftl_reloc_add_active_queue(breloc);
391
392 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
393
394 for (i = 0; i < num_iters ; ++i) {
395 single_reloc_move(breloc);
396 }
397
398 CU_ASSERT_EQUAL(breloc->num_lbks, 0);
399 CU_ASSERT_TRUE(ftl_reloc_done(breloc));
400 ftl_reloc_release(breloc);
401
402 cleanup_reloc(dev, reloc);
403 }
404
405 static void
406 test_reloc_chunk(void)
407 {
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;
413
414 setup_reloc(&dev, &reloc, &g_geo, &g_range);
415
416 breloc = &reloc->brelocs[0];
417 band = breloc->band;
418 num_io = MAX_RELOC_QDEPTH * reloc->xfer_size;
419 num_iters = ftl_dev_lbks_in_chunk(dev) / num_io;
420
421 set_band_valid_map(band, 0, ftl_num_band_lbks(dev));
422
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);
426
427 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_dev_lbks_in_chunk(dev));
428
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);
432
433 CU_ASSERT_EQUAL(breloc->num_lbks, num_lbk);
434 }
435
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);
440
441 CU_ASSERT_EQUAL(breloc->num_lbks, 0);
442 CU_ASSERT_TRUE(ftl_reloc_done(breloc));
443 ftl_reloc_release(breloc);
444
445 cleanup_reloc(dev, reloc);
446 }
447
448 static void
449 test_reloc_single_lbk(void)
450 {
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
456
457 setup_reloc(&dev, &reloc, &g_geo, &g_range);
458
459 breloc = &reloc->brelocs[0];
460 band = breloc->band;
461
462 set_band_valid_map(band, TEST_RELOC_OFFSET, 1);
463
464 ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0);
465 ftl_reloc_add_active_queue(breloc);
466
467 CU_ASSERT_EQUAL(breloc->num_lbks, 1);
468
469 single_reloc_move(breloc);
470 /* Drain move queue */
471 ftl_reloc_process_moves(breloc);
472
473 CU_ASSERT_EQUAL(breloc->num_lbks, 0);
474 CU_ASSERT_TRUE(ftl_reloc_done(breloc));
475 ftl_reloc_release(breloc);
476
477 cleanup_reloc(dev, reloc);
478 }
479
480 static void
481 test_reloc_empty_band(void)
482 {
483 struct spdk_ftl_dev *dev;
484 struct ftl_reloc *reloc;
485 struct ftl_band_reloc *breloc;
486 struct ftl_band *band;
487
488 setup_reloc(&dev, &reloc, &g_geo, &g_range);
489
490 breloc = &reloc->brelocs[0];
491 band = breloc->band;
492
493 ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
494
495 CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
496
497 ftl_reloc(reloc);
498
499 CU_ASSERT_EQUAL(breloc->num_lbks, 0);
500 SPDK_CU_ASSERT_FATAL(breloc->moves != NULL);
501
502 cleanup_reloc(dev, reloc);
503 }
504
505 int
506 main(int argc, char **argv)
507 {
508 CU_pSuite suite = NULL;
509 unsigned int num_failures;
510
511 if (CU_initialize_registry() != CUE_SUCCESS) {
512 return CU_get_error();
513 }
514
515 suite = CU_add_suite("ftl_band_suite", NULL, NULL);
516 if (!suite) {
517 CU_cleanup_registry();
518 return CU_get_error();
519 }
520
521 if (
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
536 ) {
537 CU_cleanup_registry();
538 return CU_get_error();
539 }
540
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();
545
546 return num_failures;
547 }