ftl: rename journal to map

tags/0.1.0
S.J.R. van Schaik 7 years ago
parent 770860d621
commit 6f7fec2965
  1. 16
      include/ftl.h
  2. 52
      source/ftl/ftl.c
  3. 72
      source/ftl/gc.c
  4. 2
      source/ftl/gc.h
  5. 224
      source/ftl/map.c
  6. 8
      source/ftl/map.h

@ -12,7 +12,7 @@ struct ftl_page_desc {
uint32_t subtrees[32]; uint32_t subtrees[32];
} __attribute__((packed)); } __attribute__((packed));
struct ftl_journal { struct ftl_map {
struct flash_dev *dev; struct flash_dev *dev;
uint32_t head, tail; uint32_t head, tail;
uint32_t root; uint32_t root;
@ -28,10 +28,10 @@ struct ftl_journal {
#define FTL_MAX_ATTEMPTS 8 #define FTL_MAX_ATTEMPTS 8
int ftl_init_journal(struct ftl_journal *j, struct flash_dev *dev); int ftl_init_map(struct ftl_map *map, struct flash_dev *dev);
int ftl_resume_journal(struct ftl_journal *j); int ftl_resume_map(struct ftl_map *map);
int ftl_write(struct ftl_journal *j, uint32_t addr, const uint8_t *data); int ftl_write(struct ftl_map *map, uint32_t addr, const uint8_t *data);
int ftl_read(struct ftl_journal *j, void *data, size_t len, uint32_t va); int ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va);
int ftl_trim(struct ftl_journal *j, uint32_t va); int ftl_trim(struct ftl_map *map, uint32_t va);
uint32_t ftl_get_size(const struct ftl_journal *j); uint32_t ftl_get_size(const struct ftl_map *map);
uint32_t ftl_get_capacity(const struct ftl_journal *j); uint32_t ftl_get_capacity(const struct ftl_map *map);

@ -12,12 +12,12 @@
#include "gc.h" #include "gc.h"
#include "map.h" #include "map.h"
int ftl_read(struct ftl_journal *j, void *data, size_t len, uint32_t va) int ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va)
{ {
int ret; int ret;
uint32_t page; uint32_t page;
if ((ret = trace_path(j, NULL, &page, va)) < 0) { if ((ret = trace_path(map, NULL, &page, va)) < 0) {
memset(data, 0, len); memset(data, 0, len);
return ret; return ret;
} }
@ -25,46 +25,46 @@ int ftl_read(struct ftl_journal *j, void *data, size_t len, uint32_t va)
if (!data) if (!data)
return 0; return 0;
return flash_read(j->dev, page << j->log2_page_size, data, return flash_read(map->dev, page << map->log2_page_size, data,
min(j->log2_page_size, len)); min(map->log2_page_size, len));
} }
int ftl_write(struct ftl_journal *j, uint32_t va, const uint8_t *data) int ftl_write(struct ftl_map *map, uint32_t va, const uint8_t *data)
{ {
struct ftl_page_desc page_desc; struct ftl_page_desc page_desc;
int ret; int ret;
if (va >= ftl_get_capacity(j) && if (va >= ftl_get_capacity(map) &&
!is_aligned(va, 1 << j->log2_page_size)) !is_aligned(va, 1 << map->log2_page_size))
return -1; return -1;
if ((ret = trace_path(j, &page_desc, NULL, va)) < 0 && if ((ret = trace_path(map, &page_desc, NULL, va)) < 0 &&
ret != -ERR_NOT_FOUND) ret != -ERR_NOT_FOUND)
return -1; return -1;
if (ret == -ERR_NOT_FOUND) if (ret == -ERR_NOT_FOUND)
++j->nused_pages; ++map->nused_pages;
page_desc.nused_pages = j->nused_pages; page_desc.nused_pages = map->nused_pages;
return write_upage(j, data, &page_desc); return write_upage(map, data, &page_desc);
} }
int ftl_trim(struct ftl_journal *j, uint32_t va) int ftl_trim(struct ftl_map *map, uint32_t va)
{ {
struct ftl_page_desc page_desc, alt_page_desc; struct ftl_page_desc page_desc, alt_page_desc;
size_t level, i; size_t level, i;
uint32_t alt_va, page; uint32_t alt_va, page;
int ret; int ret;
if ((ret = trace_path(j, &page_desc, &page, va)) < 0) { if ((ret = trace_path(map, &page_desc, &page, va)) < 0) {
if (ret == -ERR_NOT_FOUND) if (ret == -ERR_NOT_FOUND)
return 0; return 0;
return ret; return ret;
} }
--j->nused_pages; --map->nused_pages;
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
level = 32 - i - 1; level = 32 - i - 1;
@ -74,45 +74,45 @@ int ftl_trim(struct ftl_journal *j, uint32_t va)
} }
if (i == 32) { if (i == 32) {
j->root = UINT32_MAX; map->root = UINT32_MAX;
memset(&page_desc, 0xff, sizeof page_desc); memset(&page_desc, 0xff, sizeof page_desc);
page_desc.nused_pages = 0; page_desc.nused_pages = 0;
return write_upage(j, NULL, &page_desc); return write_upage(map, NULL, &page_desc);
} }
if (read_page_desc(j, &alt_page_desc, alt_va) < 0) if (read_page_desc(map, &alt_page_desc, alt_va) < 0)
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.nused_pages = map->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) {
page_desc.subtrees[i] = alt_page_desc.subtrees[i]; page_desc.subtrees[i] = alt_page_desc.subtrees[i];
} }
if (flash_copy(j->dev, j->head << j->log2_page_size, if (flash_copy(map->dev, map->head << map->log2_page_size,
page << j->log2_page_size, 1 << j->log2_page_size) < 0) page << map->log2_page_size, 1 << map->log2_page_size) < 0)
return -1; return -1;
return write_upage(j, NULL, &page_desc); return write_upage(map, NULL, &page_desc);
} }
/* Returns the amount of used pages with a unique virtual address multiplied by /* 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. * the page size as the size of used space on the device.
*/ */
uint32_t ftl_get_size(const struct ftl_journal *j) uint32_t ftl_get_size(const struct ftl_map *map)
{ {
return j->nused_pages << j->log2_page_size; return map->nused_pages << map->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.
*/ */
uint32_t ftl_get_capacity(const struct ftl_journal *j) uint32_t ftl_get_capacity(const struct ftl_map *map)
{ {
return ((j->nblocks - 1) << j->log2_block_size) - return ((map->nblocks - 1) << map->log2_block_size) -
((j->nblocks - 1) << j->log2_page_size); ((map->nblocks - 1) << map->log2_page_size);
} }

@ -4,11 +4,11 @@
#include "gc.h" #include "gc.h"
int read_page_desc(struct ftl_journal *j, int read_page_desc(struct ftl_map *map,
struct ftl_page_desc *page_desc, uint32_t upage); struct ftl_page_desc *page_desc, uint32_t upage);
int trace_path(struct ftl_journal *j, int trace_path(struct ftl_map *map,
struct ftl_page_desc *new_page_desc, uint32_t *loc, uint32_t va); struct ftl_page_desc *new_page_desc, uint32_t *loc, uint32_t va);
int write_upage(struct ftl_journal *j, const uint8_t *page, int write_upage(struct ftl_map *map, const uint8_t *page,
const struct ftl_page_desc *page_desc); const struct ftl_page_desc *page_desc);
/* For a given user page, attempt to claim more free space by checking if no /* For a given user page, attempt to claim more free space by checking if no
@ -17,43 +17,43 @@ int write_upage(struct ftl_journal *j, const uint8_t *page,
* the page by copying the page to create a new mapping such that the old page * the page by copying the page to create a new mapping such that the old page
* can be ignored and erased. * can be ignored and erased.
*/ */
static int free_page(struct ftl_journal *j, uint32_t upage) static int free_page(struct ftl_map *map, uint32_t upage)
{ {
struct ftl_page_desc page_desc; struct ftl_page_desc page_desc;
uint32_t found_upage, va; uint32_t found_upage, va;
if (read_page_desc(j, &page_desc, upage) < 0) if (read_page_desc(map, &page_desc, upage) < 0)
return -1; return -1;
va = page_desc.va; va = page_desc.va;
if (trace_path(j, &page_desc, &found_upage, va) < 0) if (trace_path(map, &page_desc, &found_upage, va) < 0)
return -1; return -1;
if (upage != found_upage) if (upage != found_upage)
return 0; return 0;
page_desc.nused_pages = j->nused_pages; page_desc.nused_pages = map->nused_pages;
if (flash_copy(j->dev, j->head << j->log2_page_size, if (flash_copy(map->dev, map->head << map->log2_page_size,
upage << j->log2_page_size, 1 << j->log2_page_size) < 0) upage << map->log2_page_size, 1 << map->log2_page_size) < 0)
return -1; return -1;
return write_upage(j, NULL, &page_desc); return write_upage(map, NULL, &page_desc);
} }
/* Claim more free space by checking which user pages in a page group are /* 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 * mapped and for which the mappings have been obsoleted by a more recent
* mapping. The mapped user pages are preserved by copying. * mapping. The mapped user pages are preserved by copying.
*/ */
static int free_group(struct ftl_journal *j, uint32_t group) static int free_group(struct ftl_map *map, uint32_t group)
{ {
uint32_t npages = UINT32_C(1) << j->log2_pages_per_group; uint32_t npages = UINT32_C(1) << map->log2_pages_per_group;
uint32_t page = group << j->log2_pages_per_group; uint32_t page = group << map->log2_pages_per_group;
uint32_t i; uint32_t i;
for (i = 0; i < npages; ++i) { for (i = 0; i < npages; ++i) {
if (free_page(j, page + i) < 0) if (free_page(map, page + i) < 0)
return -1; return -1;
} }
@ -64,14 +64,14 @@ static int free_group(struct ftl_journal *j, uint32_t group)
* for which the mappings have been obsoleted by a more recent mapping. The * for which the mappings have been obsoleted by a more recent mapping. The
* mapped user pages are preserved by copying. * mapped user pages are preserved by copying.
*/ */
static int free_block(struct ftl_journal *j, uint32_t block) static int free_block(struct ftl_map *map, uint32_t block)
{ {
uint32_t ngroups = UINT32_C(1) << j->log2_groups_per_block; uint32_t ngroups = UINT32_C(1) << map->log2_groups_per_block;
uint32_t group = block << j->log2_groups_per_block; uint32_t group = block << map->log2_groups_per_block;
uint32_t i; uint32_t i;
for (i = 0; i < ngroups; ++i) { for (i = 0; i < ngroups; ++i) {
if (free_group(j, group + i) < 0) if (free_group(map, group + i) < 0)
return -1; return -1;
} }
@ -83,28 +83,28 @@ static int free_block(struct ftl_journal *j, uint32_t block)
* newer pages have obsoleted the mapping. Further, we move the user pages that * newer pages have obsoleted the mapping. Further, we move the user pages that
* are still mapped as these should be preserved. * are still mapped as these should be preserved.
*/ */
static int free_tail(struct ftl_journal *j) static int free_tail(struct ftl_map *map)
{ {
size_t log2_pages_per_block = j->log2_pages_per_group + size_t log2_pages_per_block = map->log2_pages_per_group +
j->log2_groups_per_block; map->log2_groups_per_block;
size_t npages = j->nblocks << log2_pages_per_block; size_t npages = map->nblocks << log2_pages_per_block;
size_t dist; size_t dist;
if (j->head < j->tail) if (map->head < map->tail)
dist = j->tail - j->head; dist = map->tail - map->head;
else else
dist = npages - j->head + j->tail; dist = npages - map->head + map->tail;
if (dist > (UINT32_C(1) << log2_pages_per_block)) if (dist > (UINT32_C(1) << log2_pages_per_block))
return 0; return 0;
if (free_block(j, j->tail >> log2_pages_per_block) < 0) if (free_block(map, map->tail >> log2_pages_per_block) < 0)
return -1; return -1;
j->tail += 1 << log2_pages_per_block; map->tail += 1 << log2_pages_per_block;
if (j->tail >= npages) if (map->tail >= npages)
j->tail -= npages; map->tail -= npages;
return 0; return 0;
} }
@ -114,17 +114,17 @@ static int free_tail(struct ftl_journal *j)
* nothing to be done. Otherwise, we free the tail if necessary and erase the * nothing to be done. Otherwise, we free the tail if necessary and erase the
* block for writing. * block for writing.
*/ */
int prepare_head(struct ftl_journal *j) int prepare_head(struct ftl_map *map)
{ {
size_t log2_pages_per_block = j->log2_pages_per_group + size_t log2_pages_per_block = map->log2_pages_per_group +
j->log2_groups_per_block; map->log2_groups_per_block;
if (!is_aligned(j->head, log2_pages_per_block)) if (!is_aligned(map->head, log2_pages_per_block))
return 0; return 0;
if (free_tail(j) < 0) if (free_tail(map) < 0)
return -1; return -1;
return flash_erase(j->dev, j->head >> log2_pages_per_block, return flash_erase(map->dev, map->head >> log2_pages_per_block,
j->log2_block_size); map->log2_block_size);
} }

@ -1,3 +1,3 @@
#pragma once #pragma once
int prepare_head(struct ftl_journal *j); int prepare_head(struct ftl_map *map);

@ -12,16 +12,16 @@
/* Given a page number, this function checks whether the page is fully erased /* Given a page number, this function checks whether the page is fully erased
* by checking if all bits are set to ones. * by checking if all bits are set to ones.
*/ */
static int is_page_erased(struct ftl_journal *j, uint32_t page) static int is_page_erased(struct ftl_map *map, uint32_t page)
{ {
uint8_t data[64]; uint8_t data[64];
size_t i, nbytes, len = j->log2_page_size; size_t i, nbytes, len = map->log2_page_size;
uint32_t addr = page << j->log2_page_size; uint32_t addr = page << map->log2_page_size;
while (len) { while (len) {
nbytes = min(sizeof data, len); nbytes = min(sizeof data, len);
if (flash_read(j->dev, addr, data, nbytes) < 0) if (flash_read(map->dev, addr, data, nbytes) < 0)
return 0; return 0;
for (i = 0; i < nbytes; ++i) { for (i = 0; i < nbytes; ++i) {
@ -39,14 +39,14 @@ static int is_page_erased(struct ftl_journal *j, uint32_t page)
/* Given the group number, this function checks if a page group is erased by /* Given the group number, this function checks if a page group is erased by
* checking if the pages that compose the page group are erased. * checking if the pages that compose the page group are erased.
*/ */
static int is_group_erased(struct ftl_journal *j, uint32_t group) static int is_group_erased(struct ftl_map *map, uint32_t group)
{ {
uint32_t npages = UINT32_C(1) << j->log2_pages_per_group; uint32_t npages = UINT32_C(1) << map->log2_pages_per_group;
uint32_t page = group << j->log2_pages_per_group; uint32_t page = group << map->log2_pages_per_group;
uint32_t i; uint32_t i;
for (i = 0; i < npages; ++i) { for (i = 0; i < npages; ++i) {
if (!is_page_erased(j, page + i)) if (!is_page_erased(map, page + i))
return 0; return 0;
} }
@ -62,17 +62,17 @@ static int is_group_erased(struct ftl_journal *j, uint32_t group)
* possible pages on the devices, the page number of the very first user page * possible pages on the devices, the page number of the very first user page
* is returned instead. * is returned instead.
*/ */
static uint32_t next_upage(struct ftl_journal *j, uint32_t p) static uint32_t next_upage(struct ftl_map *map, uint32_t p)
{ {
size_t log2_pages_per_block = j->log2_pages_per_group + size_t log2_pages_per_block = map->log2_pages_per_group +
j->log2_groups_per_block; map->log2_groups_per_block;
++p; ++p;
if (is_aligned(p + 1, j->log2_pages_per_group)) if (is_aligned(p + 1, map->log2_pages_per_group))
++p; ++p;
if (p >= (j->nblocks << log2_pages_per_block)) if (p >= (map->nblocks << log2_pages_per_block))
p = 0; p = 0;
return p; return p;
@ -80,71 +80,71 @@ static uint32_t next_upage(struct ftl_journal *j, uint32_t p)
/* Reads the header of the given page group. /* Reads the header of the given page group.
*/ */
int read_page_group(struct ftl_journal *j, int read_page_group(struct ftl_map *map,
struct ftl_page_group *group, uint32_t group_no) struct ftl_page_group *group, uint32_t group_no)
{ {
uint32_t page, addr; uint32_t page, addr;
page = ((group_no + 1) << j->log2_pages_per_group) - 1; page = ((group_no + 1) << map->log2_pages_per_group) - 1;
addr = page << j->log2_page_size; addr = page << map->log2_page_size;
return flash_read(j->dev, addr, group, sizeof *group); return flash_read(map->dev, addr, group, sizeof *group);
} }
/* Given the page number of a user page, reads the page descriptor associated /* Given the page number of a user page, reads the page descriptor associated
* with the user page by locating the footer and more specifically the page * with the user page by locating the footer and more specifically the page
* descriptor within the page group. * descriptor within the page group.
*/ */
int read_page_desc(struct ftl_journal *j, int read_page_desc(struct ftl_map *map,
struct ftl_page_desc *page_desc, uint32_t upage) struct ftl_page_desc *page_desc, uint32_t upage)
{ {
uint32_t group_no, page, addr, offset; uint32_t group_no, page, addr, offset;
group_no = upage >> j->log2_pages_per_group; group_no = upage >> map->log2_pages_per_group;
page = ((group_no + 1) << j->log2_pages_per_group) - 1; page = ((group_no + 1) << map->log2_pages_per_group) - 1;
addr = page << j->log2_page_size; addr = page << map->log2_page_size;
offset = sizeof(struct ftl_page_group) + offset = sizeof(struct ftl_page_group) +
(upage & ((1 << j->log2_pages_per_group) - 1)) * sizeof *page_desc; (upage & ((1 << map->log2_pages_per_group) - 1)) * sizeof *page_desc;
return flash_read(j->dev, addr + offset, page_desc, sizeof *page_desc); return flash_read(map->dev, addr + offset, page_desc, sizeof *page_desc);
} }
/* Writes the page descriptor to the footer of the current page group and /* Writes the page descriptor to the footer of the current page group and
* increments the head to point to the next free user page. * increments the head to point to the next free user page.
*/ */
static int write_page_desc(struct ftl_journal *j, static int write_page_desc(struct ftl_map *map,
const struct ftl_page_desc *page_desc) const struct ftl_page_desc *page_desc)
{ {
struct ftl_page_group group; struct ftl_page_group group;
uint32_t group_no, page, addr, offset, head; uint32_t group_no, page, addr, offset, head;
group_no = j->head >> j->log2_pages_per_group; group_no = map->head >> map->log2_pages_per_group;
page = ((group_no + 1) << j->log2_pages_per_group) - 1; page = ((group_no + 1) << map->log2_pages_per_group) - 1;
addr = page << j->log2_page_size; addr = page << map->log2_page_size;
/* Write the page group header. */ /* Write the page group header. */
if (is_page_erased(j, page)) { if (is_page_erased(map, page)) {
memcpy(&group.magic, "FTL", sizeof group.magic); memcpy(&group.magic, "FTL", sizeof group.magic);
group.epoch = j->epoch; group.epoch = map->epoch;
group.tail = j->tail; group.tail = map->tail;
if (flash_write(j->dev, addr, &group, sizeof group) < 0) if (flash_write(map->dev, addr, &group, sizeof group) < 0)
return -1; return -1;
} }
offset = sizeof group + (j->head & ((1 << j->log2_pages_per_group) - 1)) * offset = sizeof group + (map->head & ((1 << map->log2_pages_per_group) - 1)) *
sizeof *page_desc; sizeof *page_desc;
if (flash_write(j->dev, addr + offset, page_desc, sizeof *page_desc) < 0) if (flash_write(map->dev, addr + offset, page_desc, sizeof *page_desc) < 0)
return -1; return -1;
j->root = j->head; map->root = map->head;
head = j->head; head = map->head;
j->head = next_upage(j, j->head); map->head = next_upage(map, map->head);
if (j->head < head) if (map->head < head)
++j->epoch; ++map->epoch;
return 0; return 0;
} }
@ -154,17 +154,17 @@ static int write_page_desc(struct ftl_journal *j,
* group, whereupon the head is incremented to point to the next available user * group, whereupon the head is incremented to point to the next available user
* page. * page.
*/ */
int write_upage(struct ftl_journal *j, const uint8_t *page, int write_upage(struct ftl_map *map, const uint8_t *page,
const struct ftl_page_desc *page_desc) const struct ftl_page_desc *page_desc)
{ {
if (prepare_head(j) < 0) if (prepare_head(map) < 0)
return -1; return -1;
if (page && flash_write(j->dev, j->head << j->log2_page_size, page, if (page && flash_write(map->dev, map->head << map->log2_page_size, page,
j->log2_page_size) < 0) map->log2_page_size) < 0)
return -1; return -1;
return write_page_desc(j, page_desc); return write_page_desc(map, page_desc);
} }
/* Determines the amount of user pages to store in a page group by determining /* Determines the amount of user pages to store in a page group by determining
@ -175,25 +175,25 @@ int write_upage(struct ftl_journal *j, const uint8_t *page,
* can also be determined, as a single page group may not cover a whole erase * can also be determined, as a single page group may not cover a whole erase
* block. * block.
*/ */
static int find_block_div(struct ftl_journal *j) static int find_block_div(struct ftl_map *map)
{ {
size_t log2_pages_per_block = j->log2_block_size - j->log2_page_size; size_t log2_pages_per_block = map->log2_block_size - map->log2_page_size;
size_t nbytes_avail = (1 << j->log2_page_size) - size_t nbytes_avail = (1 << map->log2_page_size) -
sizeof(struct ftl_page_group); sizeof(struct ftl_page_group);
size_t nbytes = sizeof(struct ftl_page_desc); size_t nbytes = sizeof(struct ftl_page_desc);
j->log2_pages_per_group = 1; map->log2_pages_per_group = 1;
while (j->log2_pages_per_group < log2_pages_per_block) { while (map->log2_pages_per_group < log2_pages_per_block) {
nbytes = 2 * nbytes + sizeof(struct ftl_page_desc); nbytes = 2 * nbytes + sizeof(struct ftl_page_desc);
if (nbytes > nbytes_avail) if (nbytes > nbytes_avail)
break; break;
++j->log2_pages_per_group; ++map->log2_pages_per_group;
} }
j->log2_groups_per_block = log2_pages_per_block - j->log2_pages_per_group; map->log2_groups_per_block = log2_pages_per_block - map->log2_pages_per_group;
return 0; return 0;
} }
@ -203,18 +203,18 @@ static int find_block_div(struct ftl_journal *j)
* use, as a block can only be erased as a whole. Therefore, if the first page * use, as a block can only be erased as a whole. Therefore, if the first page
* group is not in use, neither will the other page groups in a block. * group is not in use, neither will the other page groups in a block.
*/ */
static int find_block(struct ftl_journal *j, struct ftl_page_group *group, static int find_block(struct ftl_map *map, struct ftl_page_group *group,
uint32_t *where, uint32_t block) uint32_t *where, uint32_t block)
{ {
uint32_t page; uint32_t page;
unsigned attempt; unsigned attempt;
for (attempt = 0; block < j->nblocks && attempt < FTL_MAX_ATTEMPTS; for (attempt = 0; block < map->nblocks && attempt < FTL_MAX_ATTEMPTS;
++attempt, ++block) { ++attempt, ++block) {
page = block << j->log2_block_size; page = block << map->log2_block_size;
page |= ((UINT32_C(1) << j->log2_pages_per_group) - 1) << j->log2_page_size; page |= ((UINT32_C(1) << map->log2_pages_per_group) - 1) << map->log2_page_size;
if (flash_read(j->dev, page, group, sizeof *group) < 0) if (flash_read(map->dev, page, group, sizeof *group) < 0)
continue; continue;
if (memcmp(group->magic, "FTL", sizeof group->magic) != 0) if (memcmp(group->magic, "FTL", sizeof group->magic) != 0)
@ -231,17 +231,17 @@ static int find_block(struct ftl_journal *j, struct ftl_page_group *group,
/* Given the block number of the first block, attempts to use binary search to /* Given the block number of the first block, attempts to use binary search to
* find the last block that is in use. * find the last block that is in use.
*/ */
static uint32_t find_last_block(struct ftl_journal *j, uint32_t first) static uint32_t find_last_block(struct ftl_map *map, uint32_t first)
{ {
struct ftl_page_group group; struct ftl_page_group group;
uint32_t mid, low = first, high = j->nblocks - 1; uint32_t mid, low = first, high = map->nblocks - 1;
uint32_t found, next; uint32_t found, next;
while (low <= high) { while (low <= high) {
mid = (low + high) / 2; mid = (low + high) / 2;
if (find_block(j, &group, &found, mid) < 0 || if (find_block(map, &group, &found, mid) < 0 ||
group.epoch != j->epoch) { group.epoch != map->epoch) {
if (!mid) if (!mid)
return first; return first;
@ -250,9 +250,9 @@ static uint32_t find_last_block(struct ftl_journal *j, uint32_t first)
continue; continue;
} }
if (((found + 1) > j->nblocks) || if (((found + 1) > map->nblocks) ||
find_block(j, &group, &next, found + 1) < 0 || find_block(map, &group, &next, found + 1) < 0 ||
group.epoch != j->epoch) group.epoch != map->epoch)
return found; return found;
low = next; low = next;
@ -264,41 +264,41 @@ static uint32_t find_last_block(struct ftl_journal *j, uint32_t first)
/* Attempts to find the last page group that is in use within a block by /* Attempts to find the last page group that is in use within a block by
* performing a binary search on the page groups. * performing a binary search on the page groups.
*/ */
static uint32_t find_last_group(struct ftl_journal *j, uint32_t block) static uint32_t find_last_group(struct ftl_map *map, uint32_t block)
{ {
uint32_t ngroups = UINT32_C(1) << j->log2_groups_per_block; uint32_t ngroups = UINT32_C(1) << map->log2_groups_per_block;
uint32_t mid, low = 0, high = ngroups - 1; uint32_t mid, low = 0, high = ngroups - 1;
while (low <= high) { while (low <= high) {
mid = (low + high) / 2; mid = (low + high) / 2;
if (is_group_erased(j, mid)) { if (is_group_erased(map, mid)) {
high = mid - 1; high = mid - 1;
continue; continue;
} }
if (((mid + 1) >= ngroups) || if (((mid + 1) >= ngroups) ||
is_group_erased(j, mid + 1)) is_group_erased(map, mid + 1))
return (block << j->log2_groups_per_block) + mid; return (block << map->log2_groups_per_block) + mid;
low = mid + 1; low = mid + 1;
} }
return block << j->log2_groups_per_block; return block << map->log2_groups_per_block;
} }
static int find_root(struct ftl_journal *j, uint32_t group) static int find_root(struct ftl_map *map, uint32_t group)
{ {
struct ftl_page_desc page_desc; struct ftl_page_desc page_desc;
uint32_t upage; uint32_t upage;
upage = group << j->log2_pages_per_group; upage = group << map->log2_pages_per_group;
do { do {
j->root = upage; map->root = upage;
upage = next_upage(j, upage); upage = next_upage(map, upage);
if (read_page_desc(j, &page_desc, upage) < 0) if (read_page_desc(map, &page_desc, upage) < 0)
return -1; return -1;
} while (page_desc.va != UINT32_MAX || } while (page_desc.va != UINT32_MAX ||
page_desc.nused_pages == 0); page_desc.nused_pages == 0);
@ -311,86 +311,86 @@ static int find_root(struct ftl_journal *j, uint32_t group)
* within the page group, the first user page of the next page group should be * within the page group, the first user page of the next page group should be
* used as that page group should not be in use. * used as that page group should not be in use.
*/ */
static int find_head(struct ftl_journal *j) static int find_head(struct ftl_map *map)
{ {
size_t log2_pages_per_block = j->log2_pages_per_group + size_t log2_pages_per_block = map->log2_pages_per_group +
j->log2_groups_per_block; map->log2_groups_per_block;
j->head = j->root; map->head = map->root;
do { do {
j->head = next_upage(j, j->head); map->head = next_upage(map, map->head);
if (is_aligned(j->head, log2_pages_per_block)) if (is_aligned(map->head, log2_pages_per_block))
return 0; return 0;
} while (!is_page_erased(j, j->head)); } while (!is_page_erased(map, map->head));
return 0; return 0;
} }
static void reset_journal(struct ftl_journal *j) static void reset_map(struct ftl_map *map)
{ {
j->log2_erase_size = ilog2(4 * KIB); map->log2_erase_size = ilog2(4 * KIB);
j->log2_page_size = ilog2(4 * KIB); map->log2_page_size = ilog2(4 * KIB);
j->log2_block_size = ilog2(64 * KIB); map->log2_block_size = ilog2(64 * KIB);
find_block_div(j); find_block_div(map);
j->nblocks = flash_get_size(j->dev) >> j->log2_block_size; map->nblocks = flash_get_size(map->dev) >> map->log2_block_size;
j->head = 0; map->head = 0;
j->tail = 0; map->tail = 0;
j->root = UINT32_MAX; map->root = UINT32_MAX;
j->nused_pages = 0; map->nused_pages = 0;
j->epoch = 0; map->epoch = 0;
} }
int ftl_init_journal(struct ftl_journal *j, struct flash_dev *dev) int ftl_init_map(struct ftl_map *map, struct flash_dev *dev)
{ {
j->dev = dev; map->dev = dev;
reset_journal(j); reset_map(map);
return 0; return 0;
} }
/* Resumes the journal by finding the first block that is in use, the last /* Resumes the map 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.
*/ */
int ftl_resume_journal(struct ftl_journal *j) int ftl_resume_map(struct ftl_map *map)
{ {
struct ftl_page_group group; struct ftl_page_group group;
struct ftl_page_desc page_desc; struct ftl_page_desc page_desc;
uint32_t first, last, group_no; uint32_t first, last, group_no;
if (!j) if (!map)
return -1; return -1;
if (find_block(j, &group, &first, 0) < 0) { if (find_block(map, &group, &first, 0) < 0) {
reset_journal(j); reset_map(map);
return -1; return -1;
} }
j->epoch = group.epoch; map->epoch = group.epoch;
last = find_last_block(j, first); last = find_last_block(map, first);
group_no = find_last_group(j, last); group_no = find_last_group(map, last);
if (find_root(j, group_no) < 0) if (find_root(map, group_no) < 0)
return -1; return -1;
if (find_head(j) < 0) if (find_head(map) < 0)
return -1; return -1;
if (read_page_group(j, &group, j->root >> j->log2_pages_per_group) < 0) if (read_page_group(map, &group, map->root >> map->log2_pages_per_group) < 0)
return -1; return -1;
if (read_page_desc(j, &page_desc, j->root) < 0) if (read_page_desc(map, &page_desc, map->root) < 0)
return -1; return -1;
j->tail = group.tail; map->tail = group.tail;
j->nused_pages = page_desc.nused_pages; map->nused_pages = page_desc.nused_pages;
return 0; return 0;
} }
@ -401,12 +401,12 @@ int ftl_resume_journal(struct ftl_journal *j)
* depth until we have either found that there is no further subtree to * depth until we have either found that there is no further subtree to
* traverse or until we have found the actual user page. * traverse or until we have found the actual user page.
*/ */
int trace_path(struct ftl_journal *j, struct ftl_page_desc *new_page_desc, int trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
uint32_t *page, uint32_t va) uint32_t *page, uint32_t va)
{ {
struct ftl_page_desc page_desc; struct ftl_page_desc page_desc;
uint8_t depth = 0; uint8_t depth = 0;
uint32_t upage = j->root; uint32_t upage = map->root;
if (new_page_desc) if (new_page_desc)
new_page_desc->va = va; new_page_desc->va = va;
@ -414,7 +414,7 @@ int trace_path(struct ftl_journal *j, struct ftl_page_desc *new_page_desc,
if (upage == UINT32_MAX) if (upage == UINT32_MAX)
goto err_not_found; goto err_not_found;
if (read_page_desc(j, &page_desc, upage) < 0) if (read_page_desc(map, &page_desc, upage) < 0)
return -1; return -1;
for (; depth < 32; ++depth) { for (; depth < 32; ++depth) {
@ -436,7 +436,7 @@ int trace_path(struct ftl_journal *j, struct ftl_page_desc *new_page_desc,
goto err_not_found; goto err_not_found;
} }
if (read_page_desc(j, &page_desc, upage) < 0) if (read_page_desc(map, &page_desc, upage) < 0)
return -1; return -1;
} }

@ -2,11 +2,11 @@
#define ERR_NOT_FOUND 2 #define ERR_NOT_FOUND 2
int read_page_group(struct ftl_journal *j, int read_page_group(struct ftl_map *map,
struct ftl_page_group *group, uint32_t group_no); struct ftl_page_group *group, uint32_t group_no);
int read_page_desc(struct ftl_journal *j, int read_page_desc(struct ftl_map *map,
struct ftl_page_desc *page_desc, uint32_t upage); struct ftl_page_desc *page_desc, uint32_t upage);
int write_upage(struct ftl_journal *j, const uint8_t *page, int write_upage(struct ftl_map *map, const uint8_t *page,
const struct ftl_page_desc *page_desc); const struct ftl_page_desc *page_desc);
int trace_path(struct ftl_journal *j, struct ftl_page_desc *new_page_desc, int trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
uint32_t *page, uint32_t va); uint32_t *page, uint32_t va);

Loading…
Cancel
Save