#include #include #include #include #include #include #include #include #include #include "gc.h" #include "map.h" int ftl_read(struct ftl_journal *j, void *data, size_t len, uint32_t va) { int ret; uint32_t page; if ((ret = trace_path(j, NULL, &page, va)) < 0) { memset(data, 0, len); return ret; } if (!data) return 0; return flash_read(j->dev, page << j->log2_page_size, data, min(j->log2_page_size, len)); } int ftl_write(struct ftl_journal *j, uint32_t va, const uint8_t *data) { struct ftl_page_desc page_desc; int ret; if (va >= ftl_get_capacity(j) && !is_aligned(va, 1 << j->log2_page_size)) 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 write_upage(j, data, &page_desc); } int ftl_trim(struct ftl_journal *j, uint32_t va) { struct ftl_page_desc page_desc, alt_page_desc; size_t level, i; uint32_t alt_va, page; int ret; if ((ret = trace_path(j, &page_desc, &page, va)) < 0) { if (ret == -ERR_NOT_FOUND) return 0; return ret; } --j->nused_pages; for (i = 0; i < 32; ++i) { level = 32 - i - 1; if ((alt_va = page_desc.subtrees[level]) != UINT32_MAX) break; } if (i == 32) { j->root = UINT32_MAX; memset(&page_desc, 0xff, sizeof page_desc); page_desc.nused_pages = 0; return write_upage(j, NULL, &page_desc); } if (read_page_desc(j, &alt_page_desc, alt_va) < 0) 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) { page_desc.subtrees[i] = alt_page_desc.subtrees[i]; } if (flash_copy(j->dev, j->head << j->log2_page_size, page << j->log2_page_size, 1 << j->log2_page_size) < 0) return -1; return 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. */ uint32_t ftl_get_capacity(const struct ftl_journal *j) { return ((j->nblocks - 1) << j->log2_block_size) - ((j->nblocks - 1) << j->log2_page_size); }