|
|
|
@ -12,7 +12,12 @@ |
|
|
|
|
/* Given the group number, this function checks if a page group is erased by
|
|
|
|
|
* checking if the pages that compose the page group are erased. |
|
|
|
|
*/ |
|
|
|
|
static int is_group_erased(struct ftl_map *map, uint32_t group) |
|
|
|
|
#ifdef is_group_erased |
|
|
|
|
#undef is_group_erased |
|
|
|
|
#define is_group_erased __real_is_group_erased |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int is_group_erased(struct ftl_map *map, uint32_t group) |
|
|
|
|
{ |
|
|
|
|
uint8_t data[32]; |
|
|
|
|
struct flash_dev *dev = map->dev; |
|
|
|
@ -37,6 +42,13 @@ static int is_group_erased(struct ftl_map *map, uint32_t group) |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef is_group_erased |
|
|
|
|
#undef is_group_erased |
|
|
|
|
#define is_group_erased __wrap_is_group_erased |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int __wrap_is_group_erased(struct ftl_map *map, uint32_t group); |
|
|
|
|
|
|
|
|
|
/* Given the current user page, this function computes the page number of the
|
|
|
|
|
* next user page by incrementing the page number. However, if incrementing the |
|
|
|
|
* page number results in the page number of a page containing page |
|
|
|
@ -215,7 +227,12 @@ int find_block_div(struct ftl_map *map) |
|
|
|
|
* use, as a block can only be erased as a whole. Therefore, if the first page |
|
|
|
|
* group is not in use, neither will the other page groups in a block. |
|
|
|
|
*/ |
|
|
|
|
static int find_block(struct ftl_map *map, struct ftl_page_group *group, |
|
|
|
|
#ifdef find_block |
|
|
|
|
#undef find_block |
|
|
|
|
#define find_block __real_find_block |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int find_block(struct ftl_map *map, struct ftl_page_group *group, |
|
|
|
|
uint32_t *where, uint32_t block) |
|
|
|
|
{ |
|
|
|
|
uint32_t page; |
|
|
|
@ -240,43 +257,46 @@ static int find_block(struct ftl_map *map, struct ftl_page_group *group, |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef find_block |
|
|
|
|
#undef find_block |
|
|
|
|
#define find_block __wrap_find_block |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int find_block(struct ftl_map *map, struct ftl_page_group *group, |
|
|
|
|
uint32_t *where, uint32_t block); |
|
|
|
|
|
|
|
|
|
/* Given the block number of the first block, attempts to use binary search to
|
|
|
|
|
* find the last block that is in use. |
|
|
|
|
*/ |
|
|
|
|
static uint32_t find_last_block(struct ftl_map *map, uint32_t first) |
|
|
|
|
uint32_t find_last_block(struct ftl_map *map, uint32_t first) |
|
|
|
|
{ |
|
|
|
|
struct ftl_page_group group; |
|
|
|
|
uint32_t mid, low = first, high = map->nblocks - 1; |
|
|
|
|
uint32_t found, next; |
|
|
|
|
|
|
|
|
|
while (low <= high) { |
|
|
|
|
while (low < high) { |
|
|
|
|
mid = (low + high) / 2; |
|
|
|
|
|
|
|
|
|
if (find_block(map, &group, &found, mid) < 0 || |
|
|
|
|
group.epoch != map->epoch) { |
|
|
|
|
if (!mid) |
|
|
|
|
return first; |
|
|
|
|
|
|
|
|
|
high = mid - 1; |
|
|
|
|
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (((found + 1) > map->nblocks) || |
|
|
|
|
find_block(map, &group, &next, found + 1) < 0 || |
|
|
|
|
if (find_block(map, &group, &next, found + 1) < 0 || |
|
|
|
|
group.epoch != map->epoch) |
|
|
|
|
return found; |
|
|
|
|
|
|
|
|
|
low = next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return first; |
|
|
|
|
return low; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Attempts to find the last page group that is in use within a block by
|
|
|
|
|
* performing a binary search on the page groups. |
|
|
|
|
*/ |
|
|
|
|
static uint32_t find_last_group(struct ftl_map *map, uint32_t block) |
|
|
|
|
uint32_t find_last_group(struct ftl_map *map, uint32_t block) |
|
|
|
|
{ |
|
|
|
|
uint32_t ngroups = UINT32_C(1) << map->log2_groups_per_block; |
|
|
|
|
uint32_t mid, low = 0, high = ngroups - 1; |
|
|
|
@ -284,7 +304,7 @@ static uint32_t find_last_group(struct ftl_map *map, uint32_t block) |
|
|
|
|
low += block << map->log2_groups_per_block; |
|
|
|
|
high += block << map->log2_groups_per_block; |
|
|
|
|
|
|
|
|
|
while (low <= high) { |
|
|
|
|
while (low < high) { |
|
|
|
|
mid = (low + high) / 2; |
|
|
|
|
|
|
|
|
|
if (is_group_erased(map, mid)) { |
|
|
|
@ -298,7 +318,7 @@ static uint32_t find_last_group(struct ftl_map *map, uint32_t block) |
|
|
|
|
low = mid + 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return block << map->log2_groups_per_block; |
|
|
|
|
return low; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int find_root(struct ftl_map *map, uint32_t group) |
|
|
|
|