ftl: implement transactions to perform partial writes
This commit is contained in:
parent
15d2f6dc4b
commit
018b0043a3
3 changed files with 81 additions and 28 deletions
|
@ -19,6 +19,7 @@ struct ftl_map {
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
uint32_t last_va;
|
uint32_t last_va;
|
||||||
uint32_t last_pa;
|
uint32_t last_pa;
|
||||||
|
uint32_t offset;
|
||||||
uint32_t head, tail;
|
uint32_t head, tail;
|
||||||
uint32_t root;
|
uint32_t root;
|
||||||
uint32_t nused_pages;
|
uint32_t nused_pages;
|
||||||
|
@ -33,6 +34,7 @@ struct ftl_map {
|
||||||
|
|
||||||
#define FTL_CACHED_VA BIT(0)
|
#define FTL_CACHED_VA BIT(0)
|
||||||
#define FTL_UNMAPPED BIT(1)
|
#define FTL_UNMAPPED BIT(1)
|
||||||
|
#define FTL_DIRTY BIT(2)
|
||||||
|
|
||||||
#define FTL_MAX_ATTEMPTS 8
|
#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 ftl_write(struct ftl_map *map, uint32_t addr, const void *data,
|
||||||
size_t len);
|
size_t len);
|
||||||
size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va);
|
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);
|
int ftl_trim(struct ftl_map *map, uint32_t va);
|
||||||
uint32_t ftl_get_size(const struct ftl_map *map);
|
uint32_t ftl_get_size(const struct ftl_map *map);
|
||||||
uint32_t ftl_get_capacity(const struct ftl_map *map);
|
uint32_t ftl_get_capacity(const struct ftl_map *map);
|
||||||
|
|
|
@ -53,7 +53,10 @@ static size_t ftl_flash_write(struct flash_dev *dev, uint32_t addr,
|
||||||
{
|
{
|
||||||
struct ftl_map *map = dev->priv;
|
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)
|
static int ftl_flash_erase(struct flash_dev *dev, uint32_t addr)
|
||||||
|
|
|
@ -41,61 +41,108 @@ size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va)
|
||||||
len);
|
len);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata,
|
static int ftl_seek(struct ftl_map *map, uint32_t va)
|
||||||
size_t len)
|
|
||||||
{
|
{
|
||||||
struct ftl_page_desc page_desc;
|
size_t len;
|
||||||
size_t nbytes;
|
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t offset, page, dst, src;
|
uint32_t offset, page, dst, src;
|
||||||
|
|
||||||
if (va >= ftl_get_capacity(map))
|
if (va >= ftl_get_capacity(map))
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
offset = va & ((1 << map->log2_page_size) - 1);
|
offset = va & ((1 << map->log2_page_size) - 1);
|
||||||
va >>= map->log2_page_size;
|
va >>= map->log2_page_size;
|
||||||
|
|
||||||
if ((ret = trace_path(map, &page_desc, &page, va)) < 0 &&
|
if ((map->flags & FTL_CACHED_VA) && map->last_va != va &&
|
||||||
|
ftl_sync(map) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ret = trace_path(map, NULL, &page, va)) < 0 &&
|
||||||
ret != -ERR_NOT_FOUND)
|
ret != -ERR_NOT_FOUND)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (offset < map->offset)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (offset == map->offset)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (map->offset == 0) {
|
||||||
|
if (prepare_head(map) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (ret == -ERR_NOT_FOUND)
|
if (ret == -ERR_NOT_FOUND)
|
||||||
++map->nused_pages;
|
++map->nused_pages;
|
||||||
|
}
|
||||||
page_desc.nused_pages = map->nused_pages;
|
|
||||||
|
|
||||||
if (prepare_head(map) < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dst = map->head << map->log2_page_size;
|
dst = map->head << map->log2_page_size;
|
||||||
src = page << 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)
|
if (ret == -ERR_NOT_FOUND)
|
||||||
flash_write0(map->dev, dst, offset);
|
flash_write0(map->dev, dst, len);
|
||||||
else
|
else
|
||||||
flash_copy(map->dev, dst, src, offset);
|
flash_copy(map->dev, dst, src, len);
|
||||||
|
|
||||||
src += offset;
|
map->offset += len;
|
||||||
dst += offset;
|
|
||||||
|
|
||||||
flash_write(map->dev, dst, udata, len);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
src += len;
|
size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata,
|
||||||
dst += len;
|
size_t len)
|
||||||
nbytes = (1 << map->log2_page_size) - len - offset;
|
{
|
||||||
|
uint32_t dst;
|
||||||
|
|
||||||
if (ret == -ERR_NOT_FOUND)
|
if (ftl_seek(map, va) < 0)
|
||||||
flash_write0(map->dev, dst, nbytes);
|
|
||||||
else
|
|
||||||
flash_copy(map->dev, dst, src, nbytes);
|
|
||||||
|
|
||||||
if (write_page_desc(map, &page_desc) < 0)
|
|
||||||
return 0;
|
return 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;
|
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)
|
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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue