From ca5866f52472fb11e8305ada8aa45f68e18d846b Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Mon, 14 Sep 2020 18:49:41 +0200 Subject: [PATCH] Made the base of the file-system allocation engine --- include/gp/array.hpp | 8 ++ include/gp/tagfs/tagfs.hpp | 210 +++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 include/gp/tagfs/tagfs.hpp diff --git a/include/gp/array.hpp b/include/gp/array.hpp index 1c93cbd..b86d801 100644 --- a/include/gp/array.hpp +++ b/include/gp/array.hpp @@ -28,6 +28,14 @@ namespace gp{ } } + template + array(fn& func) + { + for(auto& elem : ary) { + elem = fn(); + } + } + template array(U&& ...values) : ary{gp::move((T&&)values)...} diff --git a/include/gp/tagfs/tagfs.hpp b/include/gp/tagfs/tagfs.hpp new file mode 100644 index 0000000..bf80b23 --- /dev/null +++ b/include/gp/tagfs/tagfs.hpp @@ -0,0 +1,210 @@ +#pragma once + +#include "gp/array.hpp" +#include "gp/algorithm/min_max.hpp" +#include "gp/algorithm/repeat.hpp" +#include "gp/bitops.hpp" +#include "gp/buffer.hpp" +#include "gp/pointers.hpp" + +#include + +#include + +template +class memory_vdisk { + static_assert(sz%128 == 0, "in memory disk expects 128 bytes page alignment"); + alignas(128) gp::array data; + + gp::buffer read(gp::buffer buffer, uint64_t offset) { + auto it = data.begin()+offset; + auto ret = buffer; + for(auto& c : buffer) { + c = *(it++); + if(it == data.end()) { + ret = buffer.slice_start(it - (data.begin() + offset)); + break; + } + } + return ret; + } + + gp::buffer write(gp::buffer buffer, uint64_t offset) { + auto it = data.begin()+offset; + auto ret = buffer; + for(auto& c : buffer) { + *(it++) = c; + if(it == data.end()) { + ret = buffer.slice_start(it - (data.begin() + offset)); + break; + } + } + return ret; + } + + constexpr uint64_t size() const noexcept { + return sz; + } + + static constexpr size_t page_size() noexcept { + return 128; + } + + constexpr uint64_t page_count() const noexcept { + return size() / page_size(); + } +}; + +template +class tagfs { + vdisk_ptr disk; + const gp::array empty_page; + + struct disk_root { + gp::endian_wrapper magic; + gp::endian_wrapper first_allocator_page; + gp::endian_wrapper allocator_shuttle; + gp::endian_wrapper allocator_page_count; + gp::endian_wrapper tag_list_node; + gp::endian_wrapper page_count; + }; + + struct file_description { + gp::endian_wrapper reference_counter; + }; + + tagfs(vdisk_ptr&& _disk) + : disk(gp::forward(disk)) + , empty_page{[](){return 0;}} + {} + + disk_root get_disk_root() { + gp::array vret; + return *disk->read(vret.as_buffer().template cast(), 0).template cast().begin(); + } + + void set_disk_root(disk_root& root) { + gp::array vpar{root}; + disk->write(vpar.as_buffer().template cast(), 0); + } + + gp::optional try_set_bit(gp::buffer page) { + uint64_t idx = 0; + for(auto& elem : page) { + if(elem != 0xff) { + uint8_t copy = elem; + uint8_t setter = 1; + gp::repeat(8, [&](){ + bool value = copy & 1; + if(!value) { + return; + } + copy >>= 1; + setter <<= 1; + ++idx; + }); + elem |= setter; + return idx; + } + idx += 8; + } + return gp::nullopt; + } + + uint64_t next_shuttle_page(disk_root root, uint64_t shuttle) { + return + shuttle + 1 == root.first_allocator_page + root.allocator_page_count ? + root.first_allocator_page + : shuttle + 1; + } + + bool try_unset_bit(gp::buffer page, uint64_t idx) { + uint8_t& target_byte = *(page.begin()+(idx/8)); + uint8_t flipper = 1 << (idx%8); + if(target_byte & flipper) { + target_byte ^= flipper; + return true; + } + return false; + } + + uint64_t allocate_page() { + disk_root root = get_disk_root(); + uint64_t begin_page = root.first_allocator_page; + uint64_t shuttle_page = root.allocator_shuttle; + uint64_t end_page = root.first_allocator_page + root.allocator_page_count; + gp::array page_contents; + + gp::optional page; + do + { + auto allocator_page = disk->read(page_contents.as_buffer(), shuttle_page*decltype(*disk)::page_size()); + if(shuttle_page == end_page - 1) { + uint64_t existing_pages = root.page_count - end_page; + uint64_t allocable_pages = root.allocator_page_count*8*decltype(*disk)::page_size(); + if(existing_pages < allocable_pages) { + uint64_t extra = allocable_pages - existing_pages; + extra /= 8; + allocator_page = allocator_page.slice_start(decltype(*disk)::page_size() - extra); + } + } + page = try_set_bit(allocator_page); + if(!page.has_value()) { + root.allocator_shuttle = (shuttle_page = next_shuttle_page(shuttle_page)); + } else { + disk->write(page_contents.as_buffer(), shuttle_page*decltype(*disk)::page_size()); + page.value += decltype(*disk)::page_size()*8*(shuttle_page-begin_page); + } + } + while(!page.has_value()); + set_disk_root(root); + return page.value() + end_page; + } + + bool deallocate_page(uint64_t page) { + disk_root root = get_disk_root(); + page -= root.first_allocator_page + root.allocator_page_count; + uint64_t discriminant = decltype(*disk)::page_size()*8; + uint64_t allocator_page = page/discriminant; + uint64_t pos_page = page%discriminant; + gp::array store; + disk->read(store.as_buffer(), decltype(*disk)::page_size()*allocator_page); + bool ret = try_unset_bit(store.as_buffer(), pos_page); + disk->write(store.as_buffer(), decltype(*disk)::page_size()*allocator_page); + return ret; + } + + void clear_page(uint64_t page) { + disk->write(empty_page.as_buffer(), page*decltype(*disk)::page_size()); + } + + void format() { + auto sz = disk->size(); + auto page_sz = disk->page_size(); + auto page_count = sz /page_sz; + auto remaining_pages = page_count; + + disk_root root; + // tagmebro + root.magic = 0x7461676D6562726F; + root.page_count = page_count; + root.first_allocator_page = 1; + root.allocator_shuttle = 1; + + // Removing the root page + remaining_pages -= 1; + + // calculating datapages + auto datapage_count = (8*remaining_pages*page_sz)/(1+8*page_sz); + auto allocator_pages = remaining_pages - datapage_count; + + root.allocator_page_count = allocator_pages; + + for(uint64_t offset = 0; offset < allocator_pages; ++offset) { + clear_page(root.first_allocator_page); + } + + root.tag_list_node = 0; + set_disk_root(root); + } +}; \ No newline at end of file