From 8c263f02b1f979d0c38bb1e364296ea030c1c7d7 Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 14 Nov 2023 22:24:00 -0800 Subject: [PATCH] temporary addition of inode/datablock allocation --- include/fs.hpp | 7 ++- include/fs/fs_data_types.hpp | 8 ++- include/fs/inode_allocator.hpp | 1 + lib/fs/datablock_allocator.cpp | 112 +++++++++++++++++++++++++-------- lib/fs/fs.cpp | 35 ++++++++--- lib/fs/fs_data_types.cpp | 39 +++++++++--- lib/fs/inode_allocator.cpp | 84 ++++++++++++++++++++++--- 7 files changed, 233 insertions(+), 53 deletions(-) diff --git a/include/fs.hpp b/include/fs.hpp index 5063c5c..36eeac2 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -24,10 +24,13 @@ public: DataBlock_Allocator datablock_allocator; int load_superblock(); - int store_superblock(); + int save_superblock(); + + int save_free_list_head(u_int64_t new_free_list_head); + int save_inode_list_head(u_int64_t new_inode_list_head); int load_inode(INode_Data *inode_data); - int store_inode(INode_Data *inode_data); + int save_inode(INode_Data *inode_data); }; #endif \ No newline at end of file diff --git a/include/fs/fs_data_types.hpp b/include/fs/fs_data_types.hpp index f3958ea..5fed834 100644 --- a/include/fs/fs_data_types.hpp +++ b/include/fs/fs_data_types.hpp @@ -9,6 +9,10 @@ size_t write_u64(u_int64_t num, char buf[]); size_t read_u64(u_int64_t *num, char buf[]); +size_t write_u32(u_int32_t num, char buf[]); + +size_t read_u32(u_int32_t *num, char buf[]); + class SuperBlock_Data { u_int64_t free_list_head; u_int64_t inode_list_head; @@ -20,13 +24,15 @@ class SuperBlock_Data { class INode_Data { u_int64_t inode_num; -#define NUMBER_OF_METADATA_BYTES (4 * sizeof(u_int64_t) + sizeof(u_int32_t)) +#define NUMBER_OF_METADATA_BYTES \ + (4 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t))) struct INode_MetaData { u_int64_t uid; u_int64_t gid; u_int64_t permissions; u_int64_t size; // not yet implemented u_int32_t reference_count; + u_int32_t flags; } metadata; size_t serialize_metadata(char buf[]); size_t deserialize_metadata(char buf[]); diff --git a/include/fs/inode_allocator.hpp b/include/fs/inode_allocator.hpp index fca64f0..1d856bb 100644 --- a/include/fs/inode_allocator.hpp +++ b/include/fs/inode_allocator.hpp @@ -25,6 +25,7 @@ public: protected: Fs *fs; u_int64_t block_segment_start, block_segment_end; + u_int64_t max_num_inodes; }; class INode_Allocator_Freelist : INode_Allocator { diff --git a/lib/fs/datablock_allocator.cpp b/lib/fs/datablock_allocator.cpp index da778a7..d8ea8a8 100644 --- a/lib/fs/datablock_allocator.cpp +++ b/lib/fs/datablock_allocator.cpp @@ -9,29 +9,35 @@ DataBlock_Allocator::DataBlock_Allocator(Fs *fs, u_int64_t block_segment_start, class BitmapBlock_Data { char buf[BLOCK_SIZE]; + u_int64_t datablocks_per_bitmap; + + BitmapBlock_Data(u_int64_t datablocks_per_bitmap_) + : datablocks_per_bitmap(datablocks_per_bitmap_) {} u_int64_t get_next_node() { u_int64_t block_num; - read_u64(&block_num, buf) return block_num; + read_u64(&block_num, buf); + return block_num; } void set_next_node(u_int64_t block_num) { write_u64(block_num, buf); } - u_int64_t claim_relative_block() { - // This type u_int64_t is important - u_int64_t *data = &buf[8]; - u_int64_t relative_block_num = 0; + u_int64_t find_unfilled() { + const char *data = &buf[8]; + u_int64_t i = 0; - for (size_t i = 0; i < (BLOCK_SIZE / 8) - 1; ++i) - if (data[i] != (~0)) - for (size_t j = 0; j < 64; ++j) - if (data[i] & (1 << j)) { - data[i] |= (1 << j); - return (i * 64) + j + 1; - } + for (; i < datablocks_per_bitmap; ++i) + if (data[i / 8] & (1 << (i % 8)) == 0) + return i + 1; - perror("Error claiming block from bitmap"); return 0; } + u_int64_t claim_relative_block() { + u_int64_t unfilled = find_unfilled(); + if (unfilled) + buf[((unfilled - 1) / 8) + 8] |= (1 << ((unfilled - 1) % 8)); + return unfilled; + } + void release_relative_block(u_int64_t relative_block_num) { relative_block_num -= 1; size_t index = (relative_block_num / 8) + 8; @@ -42,34 +48,90 @@ class BitmapBlock_Data { int DataBlock_Allocator_Bitmap::new_datablock(u_int64_t *block_num) { int err; - BitmapBlock_Data bitmap = BitmapBlock_Data(); + BitmapBlock_Data bitmap = BitmapBlock_Data(DATABLOCKS_PER_BITMAP_BLOCK); u_int64_t bitmap_block_num = fs->superblock.free_list_head; + const char zero_buf[BLOCK_SIZE] = {0}; + + if (bitmap_block_num < block_segment_start || + bitmap_block_num >= block_segment_end) + return -1; if ((err = disk->read_block(bitmap_block_num, bitmap.buf)) < 0) return err; u_int64_t relative_block_num = bitmap.claim_relative_block(); - if (relative_block_num == DATABLOCKS_PER_BITMAP_BLOCK) { - fs->superblock.free_list_head = bitmap.get_next_node(); - if ((err = fs->store_superblock()) < 0) - return err; - } + if (relative_block_num == 0) + return -1; - bitmap.set_next_node(0); + u_int64_t block_num = relative_block_num + bitmap_block; + + // NOTE: this could be removed for speed + if ((err = disk->write_block(block_num, zero_buf)) < 0) + return err; + + if (relative_block_num == DATABLOCKS_PER_BITMAP_BLOCK) { + if ((err = fs->save_free_list_head(bitmap.get_next_node())) < 0) + return err; + bitmap.set_next_node(0); + } if ((err = disk->write_block(bitmap_block_num, bitmap.buf)) < 0) return err; - (*block_num) = relative_block_num + bitmap_block_num; + (*block_num) = block_num; return 0; } int DataBlock_Allocator_Bitmap::free_datablock(u_int64_t block_num) { - return -1; + int err; + BitmapBlock_Data bitmap = BitmapBlock_Data(DATABLOCKS_PER_BITMAP_BLOCK); + const u_int64_t bitmap_region_size = DATABLOCKS_PER_BITMAP_BLOCK + 1; + bool update_freelist = false; - // sticing almost full bitmaps back at start of freelist os slow - // also potentially like 256 times slower + u_int64_t bitmap_block_num = + (((block_num - block_segment_start) / bitmap_region_size) * + bitmap_region_size) + + block_segment_start; + + if ((err = disk->read_block(bitmap_block_num, bitmap.buf)) < 0) + return err; + + bitmap.release_relative_block(block_num - bitmap_block_num); + + if (bitmap.find_unfilled() == 0) { + update_freelist = true; + bitmap.set_next_node(fs->superblock.free_list_head); + } + + if ((err = disk->write_block(bitmap_block_num, bitmap.buf)) < 0) + return err; + + if (update_freelist) { + if ((err = fs->save_free_list_head(bitmap_block_num)) < 0) + return err; + } + + return 0; + + // placing almost full bitmaps back at start of freelist is slow + // potentially like 256 times slower throughput } -int DataBlock_Allocator_Bitmap::format() { return -1; } \ No newline at end of file +int DataBlock_Allocator_Bitmap::format() { + const u_int64_t bitmap_region_size = DATABLOCKS_PER_BITMAP_BLOCK + 1; + char buf[BLOCK_SIZE] = {0}; + int err; + u_int64_t i = block_segment_start; + for (; i <= block_segment_end - (2 * bitmap_region_size); + i += bitmap_region_size) { + write_u64(i + bitmap_region_size, buf); + if ((err = disk->write_block(i, buf)) < 0) + return err; + } + if ((err = disk->write_block(i, buf)) < 0) + return err; + if ((err = fs->save_free_list_head(block_segment_start)) < 0) + return err; + return 0; +} \ No newline at end of file diff --git a/lib/fs/fs.cpp b/lib/fs/fs.cpp index 52e8a4d..9beb2df 100644 --- a/lib/fs/fs.cpp +++ b/lib/fs/fs.cpp @@ -42,35 +42,56 @@ int Fs::store_superblock() { return 0; } +int Fs::save_free_list_head(u_int64_t new_free_list_head) { + u_int64_t temp = superblock.free_list_head; + int err; + superblock.free_list_head = new_free_list_head; + if ((err = fs->store_superblock()) < 0) { + superblock.free_list_head = temp; + return err; + } + return 0; +} +int Fs::save_inode_list_head(u_int64_t new_inode_list_head) { + u_int64_t temp = superblock.inode_list_head; + int err; + superblock.inode_list_head = new_inode_list_head; + if ((err = fs->store_superblock()) < 0) { + superblock.inode_list_head = temp; + return err; + } + return 0; +} + int Fs::load_inode(INode_Data *inode_data) { char buf[BLOCK_SIZE]; int err; - u_int64_t block_num = inode_allocator.get_block_num(inode_data); + u_int64_t block_num = inode_allocator.get_block_num(inode_data->inode_num); if (block_num == 0) return -1; - u_int64_t block_offset = inode_allocator.get_block_offset(inode_data); + u_int64_t block_offset = inode_allocator.get_block_offset(inode_data->inode_num); if ((err = disk->read_block(block_num, buf)) < 0) return err; - inode_data->deserialize(&buf[block_offset]) + inode_data->deserialize(&buf[block_offset]); return 0; } -int Fs::store_inode(INode_Data *inode_data) { +int Fs::save_inode(INode_Data *inode_data) { char buf[BLOCK_SIZE]; int err; - u_int64_t block_num = inode_allocator.get_block_num(inode_data); + u_int64_t block_num = inode_allocator.get_block_num(inode_data->inode_num); if (block_num == 0) return -1; - u_int64_t block_offset = inode_allocator.get_block_offset(inode_data); + u_int64_t block_offset = inode_allocator.get_block_offset(inode_data->inode_num); if ((err = disk->read_block(block_num, buf)) < 0) return err; - inode_data->serialize(&buf[block_offset]) + inode_data->serialize(&buf[block_offset]); if ((err = disk->write_block(block_num, buf)) < 0) return err; diff --git a/lib/fs/fs_data_types.cpp b/lib/fs/fs_data_types.cpp index dac0536..9fa5794 100644 --- a/lib/fs/fs_data_types.cpp +++ b/lib/fs/fs_data_types.cpp @@ -1,22 +1,41 @@ #include "fs.hpp" -size_t write_u64(u_int64_t num, char buf[]) { +template T write_int(T num, char buf[]) +{ size_t i = 0; - for (; i < 8; ++i) + for (; i < sizeof(T); ++i) buf[i] = (char)(num >> (i * 8)); return i; } -size_t read_u64(u_int64_t *num, char buf[]) { +template T read_int(T *num, char buf[]) +{ size_t i = 0; - (*num) = 0; - for (; i < 8; ++i) { - (*num) <<= 8; - (*num) |= ((u_int64_t)buf[i]) & 0xFF; + T temp = 0; + for (; i < sizeof(T); ++i) { + temp <<= 8; + temp |= ((T)buf[i]) & 0xFF; } + (*num) = temp; return i; } +size_t write_u64(u_int64_t num, char buf[]) { + return write_int(num, buf); +} + +size_t read_u64(u_int64_t *num, char buf[]) { + return read_int(num, buf); +} + +size_t write_u32(u_int32_t num, char buf[]) { + return write_int(num, buf); +} + +size_t read_u32(u_int32_t *num, char buf[]) { + return read_int(num, buf); +} + SuperBlock_Data::SuperBlock_Data() { free_list_head = 0; inode_list_head = 0; @@ -55,7 +74,8 @@ size_t INode_Data::serialize_metadata(char buf[]) { i += write_u64(metadata.gid, &buf[i]); i += write_u64(metadata.permissions, &buf[i]); i += write_u64(metadata.size, &buf[i]); - i += write_u64(metadata.reference_count, &buf[i]); + i += write_u32(metadata.reference_count, &buf[i]); + i += write_u32(metadata.flags, &buf[i]); return i; } @@ -65,7 +85,8 @@ size_t INode_Data::deserialize_metadata(char buf[]) { i += read_u64(&metadata.gid, &buf[i]); i += read_u64(&metadata.permissions, &buf[i]); i += read_u64(&metadata.size, &buf[i]); - i += read_u64(&metadata.reference_count, &buf[i]); + i += read_u32(&metadata.reference_count, &buf[i]); + i += read_u32(&metadata.flags, &buf[i]); return i; } diff --git a/lib/fs/inode_allocator.cpp b/lib/fs/inode_allocator.cpp index 9ba3fa3..36b8475 100644 --- a/lib/fs/inode_allocator.cpp +++ b/lib/fs/inode_allocator.cpp @@ -5,25 +5,91 @@ INode_Allocator::INode_Allocator(Fs *fs, u_int64_t block_segment_start, fs = fs; block_segment_start = block_segment_start; block_segment_end = block_segment_end; + max_num_inodes = (block_segment_end - block_segment_start) * INODES_PER_BLOCK; } -u_int64_t INode_Allocator::get_block_num(INode_Data *inode_data) { +u_int64_t INode_Allocator::get_block_num(u_int64_t inode_num) { u_int64_t block_num = - block_segment_start + (inode_data->inode_num / INODES_PER_BLOCK); + block_segment_start + (inode_num / INODES_PER_BLOCK); if (block_num >= block_segment_end) return 0; return block_num; } -u_int64_t INode_Allocator::get_block_offset(INode_Data *inode_data) { - return (inode_data->inode_num % INODES_PER_BLOCK) * INODE_SIZE; +u_int64_t INode_Allocator::get_block_offset(u_int64_t inode_num) { + return (inode_num % INODES_PER_BLOCK) * INODE_SIZE; } int INode_Allocator_Freelist::new_inode(u_int64_t uid, u_int64_t gid, u_int64_t permissions, INode_Data *inode_data) { - (*inode_data) = nullptr; - return -1; -} -int INode_Allocator_Freelist::free_inode(INode_Data *inode_data) { return -1; } + char buf[BLOCK_SIZE]; + int err; + u_int64_t inode_num = fs->superblock.inode_list_head; + if(inode_num > max_num_inodes) + return -1; + + u_int64_t block_num = get_block_num(inode_num); -int INode_Allocator_Freelist::format() { return -1; } + if(block_num == 0) + return -1; + + if ((err = disk->read_block(block_num, buf)) < 0) + return err; + + u_int64_t new_inode_list_head = 0; + read_u64(&new_inode_list_head, buf); + if ((err = fs->save_inode_list_head(new_inode_list_head)) < 0) + return err; + + (*inode_data) = INode_Data(inode_num); + + metadata.uid = uid; + metadata.gid = gid; + metadata.permissions = permissions; + + // It is debatable if this function should do this: + if ((err = fs->save_inode(inode_data)) < 0) { + inode_data->inode_num = 0xFFFFFFFFFFFFFFFF; + return err; + } + + return 0; +} +int INode_Allocator_Freelist::free_inode(INode_Data *inode_data) { + char buf[BLOCK_SIZE]; + int err; + + u_int64_t block_num = get_block_num(inode_data->inode_num); + u_int64_t block_offset = get_block_offset(inode_data->inode_num); + + if(block_num == 0) + return -1; + + if ((err = disk->read_block(block_num, buf)) < 0) + return err; + + write_u64(fs->superblock.inode_list_head, &buf[block_offset]); + + if ((err = disk->write_block(block_num, buf)) < 0) + return err; + + if ((err = fs->save_inode_list_head(inode_data->inode_num)) < 0) + return err; + + return 0; +} + +int INode_Allocator_Freelist::format() { + char buf[BLOCK_SIZE]; + int err; + u_int64_t next_inode_num = 1; + for(u_int64_t i = block_segment_start; i < block_segment_end; ++i) { + for(int j = 0; j < INODES_PER_BLOCK; ++next_inode_num, ++j) + write_u64(next_inode_num, &buf[j*INODE_SIZE]); + if ((err = disk->write_block(i, buf)) < 0) + return err; + } + if ((err = fs->save_inode_list_head(0)) < 0) + return err; + return 0; + }