diff --git a/include/ftl.h b/include/ftl.h index 5c8ca7a..a3b9dd7 100644 --- a/include/ftl.h +++ b/include/ftl.h @@ -19,6 +19,7 @@ struct ftl_map { unsigned flags; uint32_t last_va; uint32_t last_pa; + uint32_t offset; uint32_t head, tail; uint32_t root; uint32_t nused_pages; @@ -33,6 +34,7 @@ struct ftl_map { #define FTL_CACHED_VA BIT(0) #define FTL_UNMAPPED BIT(1) +#define FTL_DIRTY BIT(2) #define FTL_MAX_ATTEMPTS 8 @@ -42,6 +44,7 @@ int ftl_is_mapped(struct ftl_map *map, uint32_t va); size_t ftl_write(struct ftl_map *map, uint32_t addr, const void *data, size_t len); size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va); +int ftl_sync(struct ftl_map *map); int ftl_trim(struct ftl_map *map, uint32_t va); uint32_t ftl_get_size(const struct ftl_map *map); uint32_t ftl_get_capacity(const struct ftl_map *map); diff --git a/source/ftl/dev.c b/source/ftl/dev.c index b5b9a59..f7a8dfe 100644 --- a/source/ftl/dev.c +++ b/source/ftl/dev.c @@ -53,7 +53,10 @@ static size_t ftl_flash_write(struct flash_dev *dev, uint32_t addr, { struct ftl_map *map = dev->priv; - return ftl_write(map, addr, data, len); + len = ftl_write(map, addr, data, len); + ftl_sync(map); + + return len; } static int ftl_flash_erase(struct flash_dev *dev, uint32_t addr) diff --git a/source/ftl/ftl.c b/source/ftl/ftl.c index db9be27..3f7bb54 100644 --- a/source/ftl/ftl.c +++ b/source/ftl/ftl.c @@ -41,61 +41,108 @@ size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va) len); } -size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata, - size_t len) +static int ftl_seek(struct ftl_map *map, uint32_t va) { - struct ftl_page_desc page_desc; - size_t nbytes; + size_t len; int ret; uint32_t offset, page, dst, src; if (va >= ftl_get_capacity(map)) - return 0; + return -1; offset = va & ((1 << map->log2_page_size) - 1); va >>= map->log2_page_size; - if ((ret = trace_path(map, &page_desc, &page, va)) < 0 && - ret != -ERR_NOT_FOUND) - return 0; + if ((map->flags & FTL_CACHED_VA) && map->last_va != va && + ftl_sync(map) < 0) + return -1; - if (ret == -ERR_NOT_FOUND) - ++map->nused_pages; + if ((ret = trace_path(map, NULL, &page, va)) < 0 && + ret != -ERR_NOT_FOUND) + return -1; - page_desc.nused_pages = map->nused_pages; + if (offset < map->offset) + return -1; - if (prepare_head(map) < 0) + if (offset == map->offset) return 0; + if (map->offset == 0) { + if (prepare_head(map) < 0) + return -1; + + if (ret == -ERR_NOT_FOUND) + ++map->nused_pages; + } + dst = map->head << map->log2_page_size; src = page << map->log2_page_size; - len = min(len, (1 << map->log2_page_size) - offset); + len = offset - map->offset; if (ret == -ERR_NOT_FOUND) - flash_write0(map->dev, dst, offset); + flash_write0(map->dev, dst, len); else - flash_copy(map->dev, dst, src, offset); + flash_copy(map->dev, dst, src, len); - src += offset; - dst += offset; + map->offset += len; - flash_write(map->dev, dst, udata, len); + return 0; +} - src += len; - dst += len; - nbytes = (1 << map->log2_page_size) - len - offset; +size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata, + size_t len) +{ + uint32_t dst; - if (ret == -ERR_NOT_FOUND) - flash_write0(map->dev, dst, nbytes); - else - flash_copy(map->dev, dst, src, nbytes); + if (ftl_seek(map, va) < 0) + return 0; - if (write_page_desc(map, &page_desc) < 0) + dst = (map->head << map->log2_page_size) + map->offset; + len = min(len, (1 << map->log2_page_size) - map->offset); + + if ((len = flash_write(map->dev, dst, udata, len)) == 0) return 0; + map->offset += len; + map->flags |= FTL_DIRTY; + return len; } +int ftl_sync(struct ftl_map *map) +{ + struct ftl_page_desc page_desc; + size_t len; + int ret; + uint32_t page, dst, src; + + if (!(map->flags & FTL_DIRTY)) + return 0; + + if ((ret = trace_path(map, &page_desc, &page, map->last_va)) < 0 && + ret != -ERR_NOT_FOUND) + return -1; + + dst = (map->head << map->log2_page_size) + map->offset; + src = (page << map->log2_page_size) + map->offset; + len = (1 << map->log2_page_size) - map->offset; + + if (map->flags & FTL_UNMAPPED) + flash_write0(map->dev, dst, len); + else + flash_copy(map->dev, dst, src, len); + + page_desc.nused_pages = map->nused_pages; + + if (write_page_desc(map, &page_desc) < 0) + return -1; + + map->offset = 0; + map->flags &= ~FTL_DIRTY; + + return 0; +} + int ftl_trim(struct ftl_map *map, uint32_t va) { struct ftl_page_desc page_desc, alt_page_desc;