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_core.c" 40 #include "ftl/ftl_band.c" 41 #include "../common/utils.c" 42 43 #define TEST_BAND_IDX 68 44 #define TEST_LBA 0x68676564 45 46 struct base_bdev_geometry g_geo = { 47 .write_unit_size = 16, 48 .optimal_open_zones = 9, 49 .zone_size = 100, 50 .blockcnt = 1500 * 100 * 8, 51 }; 52 53 static struct spdk_ftl_dev *g_dev; 54 static struct ftl_band *g_band; 55 56 #if defined(DEBUG) 57 DEFINE_STUB(ftl_band_validate_md, bool, (struct ftl_band *band), true); 58 DEFINE_STUB_V(ftl_trace_limits, (struct spdk_ftl_dev *dev, int limit, size_t num_free)); 59 DEFINE_STUB_V(ftl_trace_completion, (struct spdk_ftl_dev *dev, const struct ftl_io *io, 60 enum ftl_trace_completion completion)); 61 DEFINE_STUB_V(ftl_trace_defrag_band, (struct spdk_ftl_dev *dev, const struct ftl_band *band)); 62 DEFINE_STUB_V(ftl_trace_wbuf_fill, (struct spdk_ftl_dev *dev, const struct ftl_io *io)); 63 DEFINE_STUB_V(ftl_trace_wbuf_pop, (struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry)); 64 DEFINE_STUB_V(ftl_trace_write_band, (struct spdk_ftl_dev *dev, const struct ftl_band *band)); 65 DEFINE_STUB_V(ftl_trace_submission, (struct spdk_ftl_dev *dev, const struct ftl_io *io, 66 struct ftl_addr addr, size_t addr_cnt)); 67 #endif 68 DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *bdev_io)); 69 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 512); 70 DEFINE_STUB(spdk_bdev_get_name, const char *, (const struct spdk_bdev *bdev), "test"); 71 DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 0); 72 DEFINE_STUB(spdk_bdev_get_media_events, size_t, 73 (struct spdk_bdev_desc *bdev_desc, struct spdk_bdev_media_event *events, 74 size_t max_events), 0); 75 DEFINE_STUB(spdk_bdev_get_md_size, uint32_t, (const struct spdk_bdev *bdev), 8); 76 DEFINE_STUB(spdk_bdev_io_get_append_location, uint64_t, (struct spdk_bdev_io *bdev_io), 0); 77 DEFINE_STUB(spdk_bdev_write_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, 78 void *buf, uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb, 79 void *cb_arg), 0); 80 DEFINE_STUB(spdk_bdev_write_blocks_with_md, int, (struct spdk_bdev_desc *desc, 81 struct spdk_io_channel *ch, void *buf, void *md, uint64_t offset_blocks, 82 uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 83 DEFINE_STUB(spdk_bdev_read_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, 84 void *buf, uint64_t offset_blocks, uint64_t num_blocks, 85 spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 86 DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int, 87 (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, 88 uint64_t offset_blocks, uint64_t num_blocks, 89 spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 90 DEFINE_STUB(spdk_bdev_writev_blocks, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, 91 struct iovec *iov, int iovcnt, uint64_t offset_blocks, uint64_t num_blocks, 92 spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 93 DEFINE_STUB(spdk_bdev_zone_appendv, int, (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, 94 struct iovec *iov, int iovcnt, uint64_t zone_id, uint64_t num_blocks, 95 spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 96 DEFINE_STUB(spdk_bdev_zone_management, int, (struct spdk_bdev_desc *desc, 97 struct spdk_io_channel *ch, 98 uint64_t zone_id, enum spdk_bdev_zone_action action, 99 spdk_bdev_io_completion_cb cb, void *cb_arg), 0); 100 101 DEFINE_STUB_V(ftl_io_advance, (struct ftl_io *io, size_t num_blocks)); 102 DEFINE_STUB_V(ftl_io_call_foreach_child, 103 (struct ftl_io *io, int (*callback)(struct ftl_io *))); 104 DEFINE_STUB(ftl_io_channel_get_ctx, struct ftl_io_channel *, 105 (struct spdk_io_channel *ioch), NULL); 106 DEFINE_STUB_V(ftl_io_complete, (struct ftl_io *io)); 107 DEFINE_STUB(ftl_io_current_lba, uint64_t, (const struct ftl_io *io), 0); 108 DEFINE_STUB_V(ftl_io_dec_req, (struct ftl_io *io)); 109 DEFINE_STUB(ftl_io_erase_init, struct ftl_io *, 110 (struct ftl_band *band, size_t num_blocks, ftl_io_fn cb), NULL); 111 DEFINE_STUB_V(ftl_io_fail, (struct ftl_io *io, int status)); 112 DEFINE_STUB_V(ftl_io_free, (struct ftl_io *io)); 113 DEFINE_STUB(ftl_io_get_lba, uint64_t, 114 (const struct ftl_io *io, size_t offset), 0); 115 DEFINE_STUB_V(ftl_io_inc_req, (struct ftl_io *io)); 116 DEFINE_STUB(ftl_io_init_internal, struct ftl_io *, 117 (const struct ftl_io_init_opts *opts), NULL); 118 DEFINE_STUB_V(ftl_io_reset, (struct ftl_io *io)); 119 DEFINE_STUB(ftl_io_iovec_addr, void *, (struct ftl_io *io), NULL); 120 DEFINE_STUB(ftl_io_iovec_len_left, size_t, (struct ftl_io *io), 0); 121 DEFINE_STUB_V(ftl_io_shrink_iovec, (struct ftl_io *io, size_t num_blocks)); 122 DEFINE_STUB(ftl_io_wbuf_init, struct ftl_io *, 123 (struct spdk_ftl_dev *dev, struct ftl_addr addr, 124 struct ftl_band *band, struct ftl_batch *batch, ftl_io_fn cb), NULL); 125 DEFINE_STUB(ftl_io_user_init, struct ftl_io *, 126 (struct spdk_io_channel *ioch, uint64_t lba, size_t num_blocks, 127 struct iovec *iov, size_t iov_cnt, spdk_ftl_fn cb_fn, 128 void *cb_arg, int type), NULL); 129 130 DEFINE_STUB(ftl_iovec_num_blocks, size_t, 131 (struct iovec *iov, size_t iov_cnt), 0); 132 DEFINE_STUB(ftl_reloc, bool, (struct ftl_reloc *reloc), false); 133 DEFINE_STUB_V(ftl_reloc_add, (struct ftl_reloc *reloc, struct ftl_band *band, size_t offset, 134 size_t num_blocks, int prio, bool defrag)); 135 DEFINE_STUB(ftl_reloc_is_defrag_active, bool, (const struct ftl_reloc *reloc), false); 136 DEFINE_STUB(ftl_reloc_is_halted, bool, (const struct ftl_reloc *reloc), false); 137 138 #ifdef SPDK_CONFIG_PMDK 139 DEFINE_STUB_V(pmem_persist, (const void *addr, size_t len)); 140 #endif 141 142 static void 143 setup_band(void) 144 { 145 int rc; 146 147 g_dev = test_init_ftl_dev(&g_geo); 148 g_band = test_init_ftl_band(g_dev, TEST_BAND_IDX, g_geo.zone_size); 149 rc = ftl_band_alloc_lba_map(g_band); 150 CU_ASSERT_EQUAL_FATAL(rc, 0); 151 } 152 153 static void 154 cleanup_band(void) 155 { 156 test_free_ftl_band(g_band); 157 test_free_ftl_dev(g_dev); 158 } 159 160 static struct ftl_addr 161 addr_from_punit(uint64_t punit) 162 { 163 struct ftl_addr addr = {}; 164 165 addr.offset = punit * g_geo.zone_size; 166 return addr; 167 } 168 169 static void 170 test_band_block_offset_from_addr_base(void) 171 { 172 struct ftl_addr addr; 173 uint64_t offset, i, flat_lun = 0; 174 175 setup_band(); 176 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 177 addr = addr_from_punit(i); 178 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 179 180 offset = ftl_band_block_offset_from_addr(g_band, addr); 181 CU_ASSERT_EQUAL(offset, flat_lun * ftl_get_num_blocks_in_zone(g_dev)); 182 flat_lun++; 183 } 184 cleanup_band(); 185 } 186 187 static void 188 test_band_block_offset_from_addr_offset(void) 189 { 190 struct ftl_addr addr; 191 uint64_t offset, expect, i, j; 192 193 setup_band(); 194 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 195 for (j = 0; j < g_geo.zone_size; ++j) { 196 addr = addr_from_punit(i); 197 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + j; 198 199 offset = ftl_band_block_offset_from_addr(g_band, addr); 200 201 expect = test_offset_from_addr(addr, g_band); 202 CU_ASSERT_EQUAL(offset, expect); 203 } 204 } 205 cleanup_band(); 206 } 207 208 static void 209 test_band_addr_from_block_offset(void) 210 { 211 struct ftl_addr addr, expect; 212 uint64_t offset, i, j; 213 214 setup_band(); 215 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 216 for (j = 0; j < g_geo.zone_size; ++j) { 217 expect = addr_from_punit(i); 218 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + j; 219 220 offset = ftl_band_block_offset_from_addr(g_band, expect); 221 addr = ftl_band_addr_from_block_offset(g_band, offset); 222 223 CU_ASSERT_EQUAL(addr.offset, expect.offset); 224 } 225 } 226 cleanup_band(); 227 } 228 229 static void 230 test_band_set_addr(void) 231 { 232 struct ftl_lba_map *lba_map; 233 struct ftl_addr addr; 234 uint64_t offset = 0; 235 236 setup_band(); 237 lba_map = &g_band->lba_map; 238 addr = addr_from_punit(0); 239 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 240 241 CU_ASSERT_EQUAL(lba_map->num_vld, 0); 242 243 offset = test_offset_from_addr(addr, g_band); 244 245 ftl_band_set_addr(g_band, TEST_LBA, addr); 246 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 247 CU_ASSERT_EQUAL(lba_map->map[offset], TEST_LBA); 248 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 249 250 addr.offset += g_geo.zone_size; 251 offset = test_offset_from_addr(addr, g_band); 252 ftl_band_set_addr(g_band, TEST_LBA + 1, addr); 253 CU_ASSERT_EQUAL(lba_map->num_vld, 2); 254 CU_ASSERT_EQUAL(lba_map->map[offset], TEST_LBA + 1); 255 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 256 addr.offset -= g_geo.zone_size; 257 offset = test_offset_from_addr(addr, g_band); 258 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 259 cleanup_band(); 260 } 261 262 static void 263 test_invalidate_addr(void) 264 { 265 struct ftl_lba_map *lba_map; 266 struct ftl_addr addr; 267 uint64_t offset[2]; 268 269 setup_band(); 270 lba_map = &g_band->lba_map; 271 addr = addr_from_punit(0); 272 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 273 offset[0] = test_offset_from_addr(addr, g_band); 274 275 ftl_band_set_addr(g_band, TEST_LBA, addr); 276 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 277 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 278 ftl_invalidate_addr(g_band->dev, addr); 279 CU_ASSERT_EQUAL(lba_map->num_vld, 0); 280 CU_ASSERT_FALSE(spdk_bit_array_get(lba_map->vld, offset[0])); 281 282 offset[0] = test_offset_from_addr(addr, g_band); 283 ftl_band_set_addr(g_band, TEST_LBA, addr); 284 addr.offset += g_geo.zone_size; 285 offset[1] = test_offset_from_addr(addr, g_band); 286 ftl_band_set_addr(g_band, TEST_LBA + 1, addr); 287 CU_ASSERT_EQUAL(lba_map->num_vld, 2); 288 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 289 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[1])); 290 ftl_invalidate_addr(g_band->dev, addr); 291 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 292 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 293 CU_ASSERT_FALSE(spdk_bit_array_get(lba_map->vld, offset[1])); 294 cleanup_band(); 295 } 296 297 static void 298 test_next_xfer_addr(void) 299 { 300 struct ftl_addr addr, result, expect; 301 302 setup_band(); 303 /* Verify simple one block incremention */ 304 addr = addr_from_punit(0); 305 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 306 expect = addr; 307 expect.offset += 1; 308 309 result = ftl_band_next_xfer_addr(g_band, addr, 1); 310 CU_ASSERT_EQUAL(result.offset, expect.offset); 311 312 /* Verify jumping between zones */ 313 expect = addr_from_punit(1); 314 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 315 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size); 316 CU_ASSERT_EQUAL(result.offset, expect.offset); 317 318 /* Verify jumping works with unaligned offsets */ 319 expect = addr_from_punit(1); 320 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + 3; 321 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size + 3); 322 CU_ASSERT_EQUAL(result.offset, expect.offset); 323 324 /* Verify jumping from last zone to the first one */ 325 expect = addr_from_punit(0); 326 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + g_dev->xfer_size; 327 addr = addr_from_punit(ftl_get_num_punits(g_dev) - 1); 328 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 329 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size); 330 CU_ASSERT_EQUAL(result.offset, expect.offset); 331 332 /* Verify jumping from last zone to the first one with unaligned offset */ 333 expect = addr_from_punit(0); 334 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 335 expect.offset += g_dev->xfer_size + 2; 336 addr = addr_from_punit(ftl_get_num_punits(g_dev) - 1); 337 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 338 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size + 2); 339 CU_ASSERT_EQUAL(result.offset, expect.offset); 340 341 /* Verify large offset spanning across the whole band multiple times */ 342 expect = addr_from_punit(0); 343 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 344 expect.offset += g_dev->xfer_size * 5 + 4; 345 addr = addr_from_punit(0); 346 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 347 addr.offset += g_dev->xfer_size * 2 + 1; 348 result = ftl_band_next_xfer_addr(g_band, addr, 3 * g_dev->xfer_size * 349 ftl_get_num_punits(g_dev) + 3); 350 CU_ASSERT_EQUAL(result.offset, expect.offset); 351 352 /* Remove one zone and verify it's skipped properly */ 353 g_band->zone_buf[1].info.state = SPDK_BDEV_ZONE_STATE_OFFLINE; 354 CIRCLEQ_REMOVE(&g_band->zones, &g_band->zone_buf[1], circleq); 355 g_band->num_zones--; 356 expect = addr_from_punit(2); 357 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 358 expect.offset += g_dev->xfer_size * 5 + 4; 359 addr = addr_from_punit(0); 360 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 361 addr.offset += g_dev->xfer_size * 2 + 1; 362 result = ftl_band_next_xfer_addr(g_band, addr, 3 * g_dev->xfer_size * 363 (ftl_get_num_punits(g_dev) - 1) + g_dev->xfer_size + 3); 364 CU_ASSERT_EQUAL(result.offset, expect.offset); 365 cleanup_band(); 366 } 367 368 int 369 main(int argc, char **argv) 370 { 371 CU_pSuite suite = NULL; 372 unsigned int num_failures; 373 374 CU_set_error_action(CUEA_ABORT); 375 CU_initialize_registry(); 376 377 suite = CU_add_suite("ftl_band_suite", NULL, NULL); 378 379 380 CU_ADD_TEST(suite, test_band_block_offset_from_addr_base); 381 CU_ADD_TEST(suite, test_band_block_offset_from_addr_offset); 382 CU_ADD_TEST(suite, test_band_addr_from_block_offset); 383 CU_ADD_TEST(suite, test_band_set_addr); 384 CU_ADD_TEST(suite, test_invalidate_addr); 385 CU_ADD_TEST(suite, test_next_xfer_addr); 386 387 CU_basic_set_mode(CU_BRM_VERBOSE); 388 CU_basic_run_tests(); 389 num_failures = CU_get_number_of_failures(); 390 CU_cleanup_registry(); 391 392 return num_failures; 393 } 394