ftl: split up code

This commit is contained in:
S.J.R. van Schaik 2017-05-19 15:52:40 +02:00
parent a899f35562
commit 770860d621
5 changed files with 606 additions and 575 deletions

130
source/ftl/gc.c Normal file
View file

@ -0,0 +1,130 @@
#include <flash.h>
#include <ftl.h>
#include <macros.h>
#include "gc.h"
int read_page_desc(struct ftl_journal *j,
struct ftl_page_desc *page_desc, uint32_t upage);
int trace_path(struct ftl_journal *j,
struct ftl_page_desc *new_page_desc, uint32_t *loc, uint32_t va);
int write_upage(struct ftl_journal *j, const uint8_t *page,
const struct ftl_page_desc *page_desc);
/* For a given user page, attempt to claim more free space by checking if no
* recent mapping has obsoleted the older mapping. If a more recent mapping
* exists, the page can be safely ignored and erased. Otherwise, we preserve
* the page by copying the page to create a new mapping such that the old page
* can be ignored and erased.
*/
static int free_page(struct ftl_journal *j, uint32_t upage)
{
struct ftl_page_desc page_desc;
uint32_t found_upage, va;
if (read_page_desc(j, &page_desc, upage) < 0)
return -1;
va = page_desc.va;
if (trace_path(j, &page_desc, &found_upage, va) < 0)
return -1;
if (upage != found_upage)
return 0;
page_desc.nused_pages = j->nused_pages;
if (flash_copy(j->dev, j->head << j->log2_page_size,
upage << j->log2_page_size, 1 << j->log2_page_size) < 0)
return -1;
return write_upage(j, NULL, &page_desc);
}
/* Claim more free space by checking which user pages in a page group are
* mapped and for which the mappings have been obsoleted by a more recent
* mapping. The mapped user pages are preserved by copying.
*/
static int free_group(struct ftl_journal *j, uint32_t group)
{
uint32_t npages = UINT32_C(1) << j->log2_pages_per_group;
uint32_t page = group << j->log2_pages_per_group;
uint32_t i;
for (i = 0; i < npages; ++i) {
if (free_page(j, page + i) < 0)
return -1;
}
return 0;
}
/* Claim more free space by checking which user pages in a block are mapped and
* for which the mappings have been obsoleted by a more recent mapping. The
* mapped user pages are preserved by copying.
*/
static int free_block(struct ftl_journal *j, uint32_t block)
{
uint32_t ngroups = UINT32_C(1) << j->log2_groups_per_block;
uint32_t group = block << j->log2_groups_per_block;
uint32_t i;
for (i = 0; i < ngroups; ++i) {
if (free_group(j, group + i) < 0)
return -1;
}
return 0;
}
/* Checks if there are sufficient pages available for writing. Otherwise this
* function attempts to claim more free space from unmapped pages for which
* newer pages have obsoleted the mapping. Further, we move the user pages that
* are still mapped as these should be preserved.
*/
static int free_tail(struct ftl_journal *j)
{
size_t log2_pages_per_block = j->log2_pages_per_group +
j->log2_groups_per_block;
size_t npages = j->nblocks << log2_pages_per_block;
size_t dist;
if (j->head < j->tail)
dist = j->tail - j->head;
else
dist = npages - j->head + j->tail;
if (dist > (UINT32_C(1) << log2_pages_per_block))
return 0;
if (free_block(j, j->tail >> log2_pages_per_block) < 0)
return -1;
j->tail += 1 << log2_pages_per_block;
if (j->tail >= npages)
j->tail -= npages;
return 0;
}
/* Prepare the head for writing. If the user page to be written to is not
* aligned on a block boundary, the block must already be erased and there is
* nothing to be done. Otherwise, we free the tail if necessary and erase the
* block for writing.
*/
int prepare_head(struct ftl_journal *j)
{
size_t log2_pages_per_block = j->log2_pages_per_group +
j->log2_groups_per_block;
if (!is_aligned(j->head, log2_pages_per_block))
return 0;
if (free_tail(j) < 0)
return -1;
return flash_erase(j->dev, j->head >> log2_pages_per_block,
j->log2_block_size);
}