diff --git a/Makefile b/Makefile index f8b046c..ca9ab4d 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ obj-y += source/core/flash.o obj-y += source/fs/mufs/block.o obj-y += source/fs/mufs/super.o +obj-y += source/fs/mufs/tree.o obj-y += source/ftl/dev.o obj-y += source/ftl/ftl.o diff --git a/source/fs/mufs/tree.c b/source/fs/mufs/tree.c new file mode 100644 index 0000000..5213a86 --- /dev/null +++ b/source/fs/mufs/tree.c @@ -0,0 +1,97 @@ +#include + +#include +#include + +#include + +#include "block.h" +#include "tree.h" + +static int mufs_do_lookup(struct mufs *fs, uint32_t *page, + uint32_t base, uint8_t depth, uint32_t va, unsigned alloc) +{ + char data[1 << fs->dev->log2_block_size]; + uint32_t *table = (uint32_t *)data; + size_t index; + uint8_t log2_nentries = fs->dev->log2_block_size - ilog2(sizeof(uint32_t)); + + if (!base) + return -1; + + if (!depth) { + *page = base; + return 0; + } + + if (flash_read(fs->dev, base << fs->dev->log2_block_size, data, + sizeof data) == 0) + return -1; + + index = va & ((1 << (log2_nentries * (depth - 1))) - 1); + + if (!table[index]) { + if (!alloc || mufs_alloc_block(fs, &table[index]) < 0) + return -1; + } + + return mufs_do_lookup(fs, page, table[index], depth - 1, va, alloc); +} + +int mufs_lookup_page(struct mufs *fs, struct mufs_tree *tree, uint32_t *page, + uint32_t va) +{ + return mufs_do_lookup(fs, page, tree->base, tree->depth, va, 0); +} + +int mufs_alloc_page(struct mufs *fs, struct mufs_tree *tree, uint32_t *page, + uint32_t va) +{ + return mufs_do_lookup(fs, page, tree->base, tree->depth, va, 1); +} + +static int mufs_do_free_page(struct mufs *fs, uint32_t base, + uint8_t depth, uint32_t va) +{ + char data[1 << fs->dev->log2_block_size]; + uint32_t *table = (uint32_t *)data; + size_t index; + uint8_t log2_nentries = fs->dev->log2_block_size - ilog2(sizeof(uint32_t)); + + if (!base) + return -1; + + if (!depth) { + mufs_free_block(fs, base); + return 0; + } + + if (flash_read(fs->dev, base << fs->dev->log2_block_size, data, + sizeof data) == 0) + return -1; + + index = va & ((1 << (log2_nentries * (depth - 1))) - 1); + + if (mufs_do_free_page(fs, table[index], depth - 1, va) < 0) + return -1; + + table[index] = 0; + + for (index = 0; index < (UINT32_C(1) << log2_nentries); ++index) { + if (!table[index]) + continue; + + if (flash_write(fs->dev, base << fs->dev->log2_block_size, data, + sizeof data) == 0) + return -1; + + return 0; + } + + return mufs_free_block(fs, base); +} + +void mufs_free_page(struct mufs *fs, struct mufs_tree *tree, uint32_t va) +{ + mufs_do_free_page(fs, tree->base, tree->depth, va); +} diff --git a/source/fs/mufs/tree.h b/source/fs/mufs/tree.h new file mode 100644 index 0000000..7a90ed7 --- /dev/null +++ b/source/fs/mufs/tree.h @@ -0,0 +1,12 @@ +#pragma once + +struct mufs_tree { + uint32_t base; + uint8_t depth; +}; + +int mufs_lookup_page(struct mufs *fs, struct mufs_tree *tree, uint32_t *page, + uint32_t va); +int mufs_alloc_page(struct mufs *fs, struct mufs_tree *tree, uint32_t *page, + uint32_t va); +void mufs_free_page(struct mufs *fs, struct mufs_tree *tree, uint32_t va);