ftl: valid map

Adds P2L validity map tracking - a bitmap marking all physical LBAs
as containing valid (current) user data or not. A clear bit denotes
the location has no valid data and may be skipped during relocation
or compaction. A set bit means it may have valid data (it's still
necessary to do the necessary comparision against L2P).

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Change-Id: I6a831a97b3080eb7c880d9c4feab41b523467885
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13350
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Artur Paszkiewicz 2022-06-10 10:09:27 +02:00 committed by Jim Harris
parent 1e904e2b75
commit cea8dadecf
16 changed files with 178 additions and 5 deletions

View File

@ -184,6 +184,7 @@ ftl_band_set_addr(struct ftl_band *band, uint64_t lba, ftl_addr addr)
p2l_map->band_map[offset] = lba; p2l_map->band_map[offset] = lba;
p2l_map->num_valid++; p2l_map->num_valid++;
ftl_bitmap_set(band->dev->valid_map, addr);
} }
size_t size_t

View File

@ -202,6 +202,14 @@ ftl_band_qd(const struct ftl_band *band)
return band->queue_depth; return band->queue_depth;
} }
static inline bool
ftl_band_block_offset_valid(struct ftl_band *band, size_t block_off)
{
struct ftl_p2l_map *p2l_map = &band->p2l_map;
return ftl_bitmap_get(p2l_map->valid, block_off);
}
static inline void static inline void
ftl_band_iter_init(struct ftl_band *band) ftl_band_iter_init(struct ftl_band *band)
{ {

View File

@ -133,15 +133,20 @@ ftl_invalidate_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
struct ftl_p2l_map *p2l_map; struct ftl_p2l_map *p2l_map;
if (ftl_addr_in_nvc(dev, addr)) { if (ftl_addr_in_nvc(dev, addr)) {
ftl_bitmap_clear(dev->valid_map, addr);
return; return;
} }
band = ftl_band_from_addr(dev, addr); band = ftl_band_from_addr(dev, addr);
p2l_map = &band->p2l_map; p2l_map = &band->p2l_map;
/* TODO: fix case when the same address is invalidated from multiple sources */ /* The bit might be already cleared if two writes are scheduled to the */
assert(p2l_map->num_valid > 0); /* same LBA at the same time */
p2l_map->num_valid--; if (ftl_bitmap_get(dev->valid_map, addr)) {
assert(p2l_map->num_valid > 0);
ftl_bitmap_clear(dev->valid_map, addr);
p2l_map->num_valid--;
}
/* Invalidate open/full band p2l_map entry to keep p2l and l2p /* Invalidate open/full band p2l_map entry to keep p2l and l2p
* consistency when band is going to close state */ * consistency when band is going to close state */

View File

@ -22,6 +22,7 @@
#include "ftl_layout.h" #include "ftl_layout.h"
#include "ftl_sb.h" #include "ftl_sb.h"
#include "ftl_l2p.h" #include "ftl_l2p.h"
#include "utils/ftl_bitmap.h"
#include "utils/ftl_log.h" #include "utils/ftl_log.h"
/* /*
@ -115,6 +116,9 @@ struct spdk_ftl_dev {
/* Size of the l2p table */ /* Size of the l2p table */
uint64_t num_lbas; uint64_t num_lbas;
/* P2L valid map */
struct ftl_bitmap *valid_map;
/* Metadata size */ /* Metadata size */
uint64_t md_size; uint64_t md_size;

View File

@ -11,6 +11,8 @@
#include "spdk/util.h" #include "spdk/util.h"
#include "spdk/uuid.h" #include "spdk/uuid.h"
#include "utils/ftl_bitmap.h"
/* Marks address as invalid */ /* Marks address as invalid */
#define FTL_ADDR_INVALID ((ftl_addr)-1) #define FTL_ADDR_INVALID ((ftl_addr)-1)
/* Marks LBA as invalid */ /* Marks LBA as invalid */
@ -68,6 +70,9 @@ struct ftl_p2l_map {
/* P2L map's reference count, prevents premature release of resources during dirty shutdown recovery for open bands */ /* P2L map's reference count, prevents premature release of resources during dirty shutdown recovery for open bands */
size_t ref_cnt; size_t ref_cnt;
/* Bitmap of valid LBAs */
struct ftl_bitmap *valid;
/* P2L map (only valid for open/relocating bands) */ /* P2L map (only valid for open/relocating bands) */
union { union {
uint64_t *band_map; uint64_t *band_map;

View File

@ -306,6 +306,17 @@ setup_layout_base(struct spdk_ftl_dev *dev)
/* Move offset after base superblock */ /* Move offset after base superblock */
offset += layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.blocks; offset += layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.blocks;
/* Setup validity map */
region = &layout->region[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
region->type = FTL_LAYOUT_REGION_TYPE_VALID_MAP;
region->name = "vmap";
region->current.version = region->prev.version = 0;
region->current.offset = offset;
region->current.blocks = blocks_region(spdk_divide_round_up(
layout->base.total_blocks + layout->nvc.total_blocks, 8));
set_region_bdev_btm(region, dev);
offset += region->current.blocks;
/* Checking for underflow */ /* Checking for underflow */
left = layout->base.total_blocks - offset; left = layout->base.total_blocks - offset;
if (left > layout->base.total_blocks) { if (left > layout->base.total_blocks) {

View File

@ -28,6 +28,9 @@ enum ftl_layout_region_type {
/* Mirrored instance of bands state */ /* Mirrored instance of bands state */
FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR,
/* Map of valid physical addresses, used for more efficient garbage collection */
FTL_LAYOUT_REGION_TYPE_VALID_MAP,
/* State of chunks */ /* State of chunks */
FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_LAYOUT_REGION_TYPE_NVC_MD,
/* Mirrored instance of the state of chunks */ /* Mirrored instance of the state of chunks */
@ -44,7 +47,7 @@ enum ftl_layout_region_type {
/* last nvc/base region in terms of lba address space */ /* last nvc/base region in terms of lba address space */
#define FTL_LAYOUT_REGION_LAST_NVC FTL_LAYOUT_REGION_TYPE_DATA_NVC #define FTL_LAYOUT_REGION_LAST_NVC FTL_LAYOUT_REGION_TYPE_DATA_NVC
#define FTL_LAYOUT_REGION_LAST_BASE FTL_LAYOUT_REGION_TYPE_DATA_BASE #define FTL_LAYOUT_REGION_LAST_BASE FTL_LAYOUT_REGION_TYPE_VALID_MAP
#define FTL_LAYOUT_REGION_TYPE_FREE_BASE (UINT32_MAX - 2) #define FTL_LAYOUT_REGION_TYPE_FREE_BASE (UINT32_MAX - 2)
#define FTL_LAYOUT_REGION_TYPE_FREE_NVC (UINT32_MAX - 1) #define FTL_LAYOUT_REGION_TYPE_FREE_NVC (UINT32_MAX - 1)
#define FTL_LAYOUT_REGION_TYPE_INVALID (UINT32_MAX) #define FTL_LAYOUT_REGION_TYPE_INVALID (UINT32_MAX)

View File

@ -1170,6 +1170,7 @@ ftl_nv_cache_set_addr(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr)
assert(lba != FTL_LBA_INVALID); assert(lba != FTL_LBA_INVALID);
ftl_chunk_set_addr(chunk, lba, addr); ftl_chunk_set_addr(chunk, lba, addr);
ftl_bitmap_set(dev->valid_map, addr);
} }
static void ftl_chunk_open(struct ftl_nv_cache_chunk *chunk); static void ftl_chunk_open(struct ftl_nv_cache_chunk *chunk);

View File

@ -292,6 +292,7 @@ move_advance_rq(struct ftl_rq *rq)
offset = ftl_band_block_offset_from_addr(band, rq->io.addr); offset = ftl_band_block_offset_from_addr(band, rq->io.addr);
assert(offset < ftl_get_num_blocks_in_band(band->dev)); assert(offset < ftl_get_num_blocks_in_band(band->dev));
assert(ftl_band_block_offset_valid(band, offset));
entry->lba = band->p2l_map.band_map[offset]; entry->lba = band->p2l_map.band_map[offset];
entry->addr = rq->io.addr; entry->addr = rq->io.addr;

View File

@ -12,9 +12,25 @@ static int
ftl_band_init_md(struct ftl_band *band) ftl_band_init_md(struct ftl_band *band)
{ {
struct spdk_ftl_dev *dev = band->dev; struct spdk_ftl_dev *dev = band->dev;
struct ftl_p2l_map *p2l_map = &band->p2l_map;
struct ftl_md *band_info_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD]; struct ftl_md *band_info_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
struct ftl_md *valid_map_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
uint64_t band_num_blocks = ftl_get_num_blocks_in_band(band->dev);
size_t band_valid_map_bytes;
struct ftl_band_md *band_md = ftl_md_get_buffer(band_info_md); struct ftl_band_md *band_md = ftl_md_get_buffer(band_info_md);
if (band_num_blocks % (ftl_bitmap_buffer_alignment * 8)) {
FTL_ERRLOG(dev, "The number of blocks in band is not divisible by bitmap word bits\n");
return -EINVAL;
}
band_valid_map_bytes = band_num_blocks / 8;
p2l_map->valid = ftl_bitmap_create(ftl_md_get_buffer(valid_map_md) +
band_valid_map_bytes * band->id, band_valid_map_bytes);
if (!p2l_map->valid) {
return -ENOMEM;
}
band->md = &band_md[band->id]; band->md = &band_md[band->id];
if (!ftl_fast_startup(dev)) { if (!ftl_fast_startup(dev)) {
band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID; band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
@ -73,6 +89,22 @@ ftl_dev_deinit_bands(struct spdk_ftl_dev *dev)
free(dev->bands); free(dev->bands);
} }
static void
ftl_dev_deinit_bands_md(struct spdk_ftl_dev *dev)
{
if (dev->bands) {
uint64_t i;
for (i = 0; i < dev->num_bands; ++i) {
struct ftl_band *band = &dev->bands[i];
ftl_bitmap_destroy(band->p2l_map.valid);
band->p2l_map.valid = NULL;
band->md = NULL;
}
}
}
void void
ftl_mngt_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) ftl_mngt_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{ {
@ -100,6 +132,13 @@ ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
ftl_mngt_next_step(mngt); ftl_mngt_next_step(mngt);
} }
void
ftl_mngt_deinit_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
ftl_dev_deinit_bands_md(dev);
ftl_mngt_next_step(mngt);
}
/* /*
* For grouping multiple logical bands (1GiB) to make any IOs more sequential from the drive's * For grouping multiple logical bands (1GiB) to make any IOs more sequential from the drive's
* perspective. Improves WAF. * perspective. Improves WAF.

View File

@ -218,3 +218,30 @@ ftl_mngt_dump_stats(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
ftl_dev_dump_stats(dev); ftl_dev_dump_stats(dev);
ftl_mngt_next_step(mngt); ftl_mngt_next_step(mngt);
} }
void
ftl_mngt_init_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_md *valid_map_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
dev->valid_map = ftl_bitmap_create(ftl_md_get_buffer(valid_map_md),
ftl_md_get_buffer_size(valid_map_md));
if (!dev->valid_map) {
FTL_ERRLOG(dev, "Failed to create valid map\n");
ftl_mngt_fail_step(mngt);
return;
}
ftl_mngt_next_step(mngt);
}
void
ftl_mngt_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
if (dev->valid_map) {
ftl_bitmap_destroy(dev->valid_map);
dev->valid_map = NULL;
}
ftl_mngt_next_step(mngt);
}

View File

@ -92,9 +92,15 @@ static const struct ftl_mngt_process_desc desc_startup = {
.action = ftl_mngt_init_nv_cache, .action = ftl_mngt_init_nv_cache,
.cleanup = ftl_mngt_deinit_nv_cache .cleanup = ftl_mngt_deinit_nv_cache
}, },
{
.name = "Initialize valid map",
.action = ftl_mngt_init_vld_map,
.cleanup = ftl_mngt_deinit_vld_map
},
{ {
.name = "Initialize bands metadata", .name = "Initialize bands metadata",
.action = ftl_mngt_init_bands_md .action = ftl_mngt_init_bands_md,
.cleanup = ftl_mngt_deinit_bands_md
}, },
{ {
.name = "Initialize reloc", .name = "Initialize reloc",

View File

@ -42,6 +42,8 @@ void ftl_mngt_init_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *m
void ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_deinit_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_deinit_bands_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_init_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_init_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_deinit_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_deinit_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
@ -86,6 +88,10 @@ void ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process
void ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_init_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);

View File

@ -1125,6 +1125,11 @@ ftl_md_create_region_flags(struct spdk_ftl_dev *dev, int region_type)
flags |= FTL_MD_CREATE_SHM_NEW; flags |= FTL_MD_CREATE_SHM_NEW;
} }
break; break;
case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
if (!ftl_fast_startup(dev) && !ftl_fast_recovery(dev)) {
flags |= FTL_MD_CREATE_SHM_NEW;
}
break;
default: default:
return FTL_MD_CREATE_HEAP; return FTL_MD_CREATE_HEAP;
} }
@ -1138,6 +1143,7 @@ ftl_md_destroy_region_flags(struct spdk_ftl_dev *dev, int region_type)
switch (region_type) { switch (region_type) {
case FTL_LAYOUT_REGION_TYPE_SB: case FTL_LAYOUT_REGION_TYPE_SB:
case FTL_LAYOUT_REGION_TYPE_BAND_MD: case FTL_LAYOUT_REGION_TYPE_BAND_MD:
case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
case FTL_LAYOUT_REGION_TYPE_NVC_MD: case FTL_LAYOUT_REGION_TYPE_NVC_MD:
if (dev->conf.fast_shutdown) { if (dev->conf.fast_shutdown) {
return FTL_MD_DESTROY_SHM_KEEP; return FTL_MD_DESTROY_SHM_KEEP;

View File

@ -116,6 +116,9 @@ test_init_ftl_band(struct spdk_ftl_dev *dev, size_t id, size_t zone_size)
band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID; band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
TAILQ_INSERT_HEAD(&dev->shut_bands, band, queue_entry); TAILQ_INSERT_HEAD(&dev->shut_bands, band, queue_entry);
band->p2l_map.valid = (struct ftl_bitmap *)spdk_bit_array_create(ftl_get_num_blocks_in_band(dev));
SPDK_CU_ASSERT_FATAL(band->p2l_map.valid != NULL);
band->start_addr = zone_size * id; band->start_addr = zone_size * id;
return band; return band;
@ -149,6 +152,7 @@ void
test_free_ftl_band(struct ftl_band *band) test_free_ftl_band(struct ftl_band *band)
{ {
SPDK_CU_ASSERT_FATAL(band != NULL); SPDK_CU_ASSERT_FATAL(band != NULL);
spdk_bit_array_free((struct spdk_bit_array **)&band->p2l_map.valid);
spdk_dma_free(band->p2l_map.band_dma_md); spdk_dma_free(band->p2l_map.band_dma_md);
band->p2l_map.band_dma_md = NULL; band->p2l_map.band_dma_md = NULL;

View File

@ -120,6 +120,39 @@ DEFINE_STUB(ftl_writer_is_halted, bool, (struct ftl_writer *writer), true);
DEFINE_STUB(ftl_mempool_claim_df, void *, (struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id), DEFINE_STUB(ftl_mempool_claim_df, void *, (struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id),
NULL); NULL);
static void
adjust_bitmap(struct ftl_bitmap **bitmap, uint64_t *bit)
{
if (*bitmap == g_dev->valid_map) {
*bitmap = g_band->p2l_map.valid;
*bit = test_offset_from_addr(*bit, g_band);
}
}
bool
ftl_bitmap_get(const struct ftl_bitmap *bitmap, uint64_t bit)
{
adjust_bitmap((struct ftl_bitmap **)&bitmap, &bit);
return spdk_bit_array_get((struct spdk_bit_array *)bitmap, bit);
}
void
ftl_bitmap_set(struct ftl_bitmap *bitmap, uint64_t bit)
{
int ret;
adjust_bitmap(&bitmap, &bit);
ret = spdk_bit_array_set((struct spdk_bit_array *)bitmap, bit);
CU_ASSERT_EQUAL(ret, 0);
}
void
ftl_bitmap_clear(struct ftl_bitmap *bitmap, uint64_t bit)
{
adjust_bitmap(&bitmap, &bit);
spdk_bit_array_clear((struct spdk_bit_array *)bitmap, bit);
}
static void static void
setup_band(void) setup_band(void)
{ {
@ -220,14 +253,17 @@ test_band_set_addr(void)
ftl_band_set_addr(g_band, TEST_LBA, addr); ftl_band_set_addr(g_band, TEST_LBA, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 1); CU_ASSERT_EQUAL(p2l_map->num_valid, 1);
CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA); CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset));
addr += g_geo.zone_size / 2; addr += g_geo.zone_size / 2;
offset = test_offset_from_addr(addr, g_band); offset = test_offset_from_addr(addr, g_band);
ftl_band_set_addr(g_band, TEST_LBA + 1, addr); ftl_band_set_addr(g_band, TEST_LBA + 1, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 2); CU_ASSERT_EQUAL(p2l_map->num_valid, 2);
CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA + 1); CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA + 1);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset));
addr -= g_geo.zone_size / 2; addr -= g_geo.zone_size / 2;
offset = test_offset_from_addr(addr, g_band); offset = test_offset_from_addr(addr, g_band);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset));
cleanup_band(); cleanup_band();
} }
@ -236,23 +272,33 @@ test_invalidate_addr(void)
{ {
struct ftl_p2l_map *p2l_map; struct ftl_p2l_map *p2l_map;
ftl_addr addr; ftl_addr addr;
uint64_t offset[2];
setup_band(); setup_band();
p2l_map = &g_band->p2l_map; p2l_map = &g_band->p2l_map;
addr = addr_from_zone_id(0); addr = addr_from_zone_id(0);
addr += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); addr += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev);
offset[0] = test_offset_from_addr(addr, g_band);
ftl_band_set_addr(g_band, TEST_LBA, addr); ftl_band_set_addr(g_band, TEST_LBA, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 1); CU_ASSERT_EQUAL(p2l_map->num_valid, 1);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset[0]));
ftl_invalidate_addr(g_band->dev, addr); ftl_invalidate_addr(g_band->dev, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 0); CU_ASSERT_EQUAL(p2l_map->num_valid, 0);
CU_ASSERT_FALSE(ftl_bitmap_get(p2l_map->valid, offset[0]));
offset[0] = test_offset_from_addr(addr, g_band);
ftl_band_set_addr(g_band, TEST_LBA, addr); ftl_band_set_addr(g_band, TEST_LBA, addr);
addr += g_geo.zone_size / 2; addr += g_geo.zone_size / 2;
offset[1] = test_offset_from_addr(addr, g_band);
ftl_band_set_addr(g_band, TEST_LBA + 1, addr); ftl_band_set_addr(g_band, TEST_LBA + 1, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 2); CU_ASSERT_EQUAL(p2l_map->num_valid, 2);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset[0]));
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset[1]));
ftl_invalidate_addr(g_band->dev, addr); ftl_invalidate_addr(g_band->dev, addr);
CU_ASSERT_EQUAL(p2l_map->num_valid, 1); CU_ASSERT_EQUAL(p2l_map->num_valid, 1);
CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset[0]));
CU_ASSERT_FALSE(ftl_bitmap_get(p2l_map->valid, offset[1]));
cleanup_band(); cleanup_band();
} }