ftl: add ftl_get_size(), allow trimming final sector, recover tail and size
This commit is contained in:
parent
da30898794
commit
4b651b19f1
2 changed files with 51 additions and 6 deletions
|
@ -98,6 +98,7 @@ static void reset_journal(struct ftl_journal *j)
|
|||
j->head = 0;
|
||||
j->tail = 0;
|
||||
j->root = UINT32_MAX;
|
||||
j->nused_pages = 0;
|
||||
j->epoch = 0;
|
||||
}
|
||||
|
||||
|
@ -259,8 +260,8 @@ static int find_root(struct ftl_journal *j, uint32_t group)
|
|||
|
||||
if (read_page_desc(j, &page_desc, upage) < 0)
|
||||
return -1;
|
||||
/* TODO: better condition? */
|
||||
} while (page_desc.va != UINT32_MAX);
|
||||
} while (page_desc.va != UINT32_MAX ||
|
||||
page_desc.nused_pages == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -287,6 +288,9 @@ static int find_head(struct ftl_journal *j)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int read_page_group(struct ftl_journal *j,
|
||||
struct ftl_page_group *group, uint32_t group_no);
|
||||
|
||||
/* Resumes the journal by finding the first block that is in use, the last
|
||||
* block that is in use, the last page group that is in use, and setting the
|
||||
* head to the first free user page.
|
||||
|
@ -294,6 +298,7 @@ static int find_head(struct ftl_journal *j)
|
|||
int ftl_resume_journal(struct ftl_journal *j)
|
||||
{
|
||||
struct ftl_page_group group;
|
||||
struct ftl_page_desc page_desc;
|
||||
uint32_t first, last, group_no;
|
||||
|
||||
if (!j)
|
||||
|
@ -315,6 +320,15 @@ int ftl_resume_journal(struct ftl_journal *j)
|
|||
if (find_head(j) < 0)
|
||||
return -1;
|
||||
|
||||
if (read_page_group(j, &group, j->root >> j->log2_pages_per_group) < 0)
|
||||
return -1;
|
||||
|
||||
if (read_page_desc(j, &page_desc, j->root) < 0)
|
||||
return -1;
|
||||
|
||||
j->tail = group.tail;
|
||||
j->nused_pages = page_desc.nused_pages;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -376,6 +390,17 @@ int read_page_desc(struct ftl_journal *j,
|
|||
return flash_read(j->dev, addr + offset, page_desc, sizeof *page_desc);
|
||||
}
|
||||
|
||||
int read_page_group(struct ftl_journal *j,
|
||||
struct ftl_page_group *group, uint32_t group_no)
|
||||
{
|
||||
uint32_t page, addr;
|
||||
|
||||
page = ((group_no + 1) << j->log2_pages_per_group) - 1;
|
||||
addr = page << j->log2_page_size;
|
||||
|
||||
return flash_read(j->dev, addr, group, sizeof *group);
|
||||
}
|
||||
|
||||
/* Trace a path for a given virtual target address by comparing each of the
|
||||
* bits in the target address with the virtual address of our root. In case of
|
||||
* a mismatch, we proceed our traversal with the given subtree at the current
|
||||
|
@ -461,6 +486,8 @@ static int free_page(struct ftl_journal *j, uint32_t upage)
|
|||
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;
|
||||
|
@ -603,10 +630,14 @@ int ftl_write(struct ftl_journal *j, uint32_t va, const uint8_t *data)
|
|||
!is_aligned(va, 1 << j->log2_page_size))
|
||||
return -1;
|
||||
|
||||
if ((ret = trace_path(j, &page_desc, NULL, va)) < 0) {
|
||||
if (ret != -ERR_NOT_FOUND)
|
||||
return -1;
|
||||
}
|
||||
if ((ret = trace_path(j, &page_desc, NULL, va)) < 0 &&
|
||||
ret != -ERR_NOT_FOUND)
|
||||
return -1;
|
||||
|
||||
if (ret == -ERR_NOT_FOUND)
|
||||
++j->nused_pages;
|
||||
|
||||
page_desc.nused_pages = j->nused_pages;
|
||||
|
||||
return ftl_write_upage(j, data, &page_desc);
|
||||
}
|
||||
|
@ -625,6 +656,8 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
|
|||
return ret;
|
||||
}
|
||||
|
||||
--j->nused_pages;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
level = 32 - i - 1;
|
||||
|
||||
|
@ -643,6 +676,7 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
|
|||
return -1;
|
||||
|
||||
page_desc.va = alt_page_desc.va;
|
||||
page_desc.nused_pages = j->nused_pages;
|
||||
page_desc.subtrees[level] = UINT32_MAX;
|
||||
|
||||
for (i = level + 1; i < 32; ++i) {
|
||||
|
@ -656,6 +690,14 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
|
|||
return ftl_write_upage(j, NULL, &page_desc);
|
||||
}
|
||||
|
||||
/* Returns the amount of used pages with a unique virtual address multiplied by
|
||||
* the page size as the size of used space on the device.
|
||||
*/
|
||||
uint32_t ftl_get_size(const struct ftl_journal *j)
|
||||
{
|
||||
return j->nused_pages << j->log2_page_size;
|
||||
}
|
||||
|
||||
/* The capacity of the device is the total amount of user pages minus a block
|
||||
* worth of user pages for garbage collection.
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue