ftl: add ftl_get_size(), allow trimming final sector, recover tail and size

tags/0.1.0
S.J.R. van Schaik 7 years ago
parent da30898794
commit 4b651b19f1
  1. 3
      include/ftl.h
  2. 54
      source/ftl/ftl.c

@ -8,6 +8,7 @@ struct ftl_page_group {
struct ftl_page_desc {
uint32_t va;
uint32_t nused_pages;
uint32_t subtrees[32];
} __attribute__((packed));
@ -15,6 +16,7 @@ struct ftl_journal {
struct flash_dev *dev;
uint32_t head, tail;
uint32_t root;
uint32_t nused_pages;
uint32_t nblocks;
uint8_t log2_groups_per_block;
uint8_t log2_pages_per_group;
@ -32,4 +34,5 @@ int ftl_find(struct ftl_journal *j, uint32_t *loc, uint32_t va);
int ftl_write(struct ftl_journal *j, uint32_t addr, const uint8_t *data);
int ftl_read(struct ftl_journal *j, uint8_t *data, uint32_t va);
int ftl_trim(struct ftl_journal *j, uint32_t va);
uint32_t ftl_get_size(const struct ftl_journal *j);
uint32_t ftl_get_capacity(const struct ftl_journal *j);

@ -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…
Cancel
Save