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

tags/0.1.0
S.J.R. van Schaik 8 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 { struct ftl_page_desc {
uint32_t va; uint32_t va;
uint32_t nused_pages;
uint32_t subtrees[32]; uint32_t subtrees[32];
} __attribute__((packed)); } __attribute__((packed));
@ -15,6 +16,7 @@ struct ftl_journal {
struct flash_dev *dev; struct flash_dev *dev;
uint32_t head, tail; uint32_t head, tail;
uint32_t root; uint32_t root;
uint32_t nused_pages;
uint32_t nblocks; uint32_t nblocks;
uint8_t log2_groups_per_block; uint8_t log2_groups_per_block;
uint8_t log2_pages_per_group; 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_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_read(struct ftl_journal *j, uint8_t *data, uint32_t va);
int ftl_trim(struct ftl_journal *j, 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); 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->head = 0;
j->tail = 0; j->tail = 0;
j->root = UINT32_MAX; j->root = UINT32_MAX;
j->nused_pages = 0;
j->epoch = 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) if (read_page_desc(j, &page_desc, upage) < 0)
return -1; return -1;
/* TODO: better condition? */ } while (page_desc.va != UINT32_MAX ||
} while (page_desc.va != UINT32_MAX); page_desc.nused_pages == 0);
return 0; return 0;
} }
@ -287,6 +288,9 @@ static int find_head(struct ftl_journal *j)
return 0; 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 /* 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 * block that is in use, the last page group that is in use, and setting the
* head to the first free user page. * 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) int ftl_resume_journal(struct ftl_journal *j)
{ {
struct ftl_page_group group; struct ftl_page_group group;
struct ftl_page_desc page_desc;
uint32_t first, last, group_no; uint32_t first, last, group_no;
if (!j) if (!j)
@ -315,6 +320,15 @@ int ftl_resume_journal(struct ftl_journal *j)
if (find_head(j) < 0) if (find_head(j) < 0)
return -1; 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; 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); 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 /* 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 * 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 * 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) if (upage != found_upage)
return 0; return 0;
page_desc.nused_pages = j->nused_pages;
if (flash_copy(j->dev, j->head << j->log2_page_size, if (flash_copy(j->dev, j->head << j->log2_page_size,
upage << j->log2_page_size, 1 << j->log2_page_size) < 0) upage << j->log2_page_size, 1 << j->log2_page_size) < 0)
return -1; 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)) !is_aligned(va, 1 << j->log2_page_size))
return -1; return -1;
if ((ret = trace_path(j, &page_desc, NULL, va)) < 0) { if ((ret = trace_path(j, &page_desc, NULL, va)) < 0 &&
if (ret != -ERR_NOT_FOUND) ret != -ERR_NOT_FOUND)
return -1; 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); return ftl_write_upage(j, data, &page_desc);
} }
@ -625,6 +656,8 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
return ret; return ret;
} }
--j->nused_pages;
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
level = 32 - i - 1; level = 32 - i - 1;
@ -643,6 +676,7 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
return -1; return -1;
page_desc.va = alt_page_desc.va; page_desc.va = alt_page_desc.va;
page_desc.nused_pages = j->nused_pages;
page_desc.subtrees[level] = UINT32_MAX; page_desc.subtrees[level] = UINT32_MAX;
for (i = level + 1; i < 32; ++i) { 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); 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 /* The capacity of the device is the total amount of user pages minus a block
* worth of user pages for garbage collection. * worth of user pages for garbage collection.
*/ */

Loading…
Cancel
Save