ftl: split up code
This commit is contained in:
parent
a899f35562
commit
770860d621
5 changed files with 606 additions and 575 deletions
130
source/ftl/gc.c
Normal file
130
source/ftl/gc.c
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue