diff --git a/CMakeLists.txt b/CMakeLists.txt index d438466..bb6a172 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ add_executable(fischl lib/fs/datablock_manager.cpp lib/fs/fs_data_types.cpp lib/fs/fs_resize.cpp - lib/fs/fs_read_write.cpp + lib/fs/fs_file_io.cpp lib/fs/fs.cpp lib/fs/inode_manager.cpp diff --git a/lib/fs/datablock_manager.cpp b/lib/fs/datablock_manager.cpp index e6737d7..e793b29 100644 --- a/lib/fs/datablock_manager.cpp +++ b/lib/fs/datablock_manager.cpp @@ -1,7 +1,7 @@ #include "fs.hpp" DataBlock_Manager::DataBlock_Manager(Fs *fs, u_int64_t block_segment_start, - u_int64_t block_segment_end) + u_int64_t block_segment_end) : fs(fs), block_segment_start(block_segment_start), block_segment_end(block_segment_end) {} @@ -122,6 +122,7 @@ int DataBlock_Manager_Bitmap::format() { char buf[IO_BLOCK_SIZE] = {0}; int err; u_int64_t i = block_segment_start; + write_u64(i, buf); for (; i <= block_segment_end - (2 * bitmap_region_size); i += bitmap_region_size) { write_u64(i + bitmap_region_size, buf); diff --git a/lib/fs/fs.cpp b/lib/fs/fs.cpp index c87ced9..5c5744d 100644 --- a/lib/fs/fs.cpp +++ b/lib/fs/fs.cpp @@ -1,10 +1,12 @@ #include "fs.hpp" Fs::Fs(RawDisk *disk) : disk(disk) { + assert((disk->diskSize / IO_BLOCK_SIZE) > + 2 + NUM_INODE_BLOCKS + DATABLOCKS_PER_BITMAP_BLOCK); superblock = SuperBlock_Data(); inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS); - datablock_manager = - new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, NUM_BLOCKS); + datablock_manager = new DataBlock_Manager_Bitmap( + this, 1 + NUM_INODE_BLOCKS, disk->diskSize / IO_BLOCK_SIZE); }; Fs::~Fs() { diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_file_io.cpp similarity index 52% rename from lib/fs/fs_read_write.cpp rename to lib/fs/fs_file_io.cpp index 1aabf8a..57a1de6 100644 --- a/lib/fs/fs_read_write.cpp +++ b/lib/fs/fs_file_io.cpp @@ -6,10 +6,24 @@ public: size_t count; size_t offset; size_t bytes_completed; - RawDisk *disk; - virtual int operation(u_int64_t block_num) = 0; + Fs *fs; + virtual int operation(u_int64_t block_num, bool *delete_block) = 0; + int (*skip)(DatablockOperation *, u_int64_t) = nullptr; }; +int default_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) { + this_op->bytes_completed += (num_blocks * IO_BLOCK_SIZE) - this_op->offset; + this_op->offset = 0; + + if (this_op->bytes_completed >= this_op->count) + return 0; + return 1; +} + +int pass_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) { + return 1; +} + int Fs::sweep_inode_datablocks(INode_Data *inode_data, u_int64_t start_block_index, bool allocate, DatablockOperation *op) { @@ -49,7 +63,7 @@ int Fs::sweep_inode_datablocks(INode_Data *inode_data, return result; } - return -1; + return 1; } // This can simply be made non recursive by copy pasting - it is just @@ -61,12 +75,30 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, int err; int result = -1; - if (allocate && (*block_num) == 0) - if ((err = datablock_manager->new_datablock(block_num)) < 0) - return err; + u_int64_t indirect_block_size = 1; + for (int i = 1; i < indirect_num; ++i) + indirect_block_size *= IO_BLOCK_SIZE; - if (indirect_num == 0) - return op->operation(*block_num); + if ((*block_num) == 0) { + if (allocate) { + if ((err = datablock_manager->new_datablock(block_num)) < 0) + return err; + } else if (op->skip != nullptr) { + return (*(op->skip))(op, indirect_block_size * IO_BLOCK_SIZE); + } + } + + if (indirect_num == 0) { + bool delete_block = false; + if ((result = op->operation(*block_num, &delete_block)) < 0) + return result; + if (delete_block) { + if ((err = datablock_manager->free_datablock(*block_num)) < 0) + return err; + (*block_num) = 0; + } + return result; + } if ((*block_num) == 0) { memset(buf, 0, sizeof(buf)); @@ -75,10 +107,6 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, return err; } - u_int64_t indirect_block_size = 1; - for (int i = 1; i < indirect_num; ++i) - indirect_block_size *= IO_BLOCK_SIZE; - u_int64_t this_layer_start_index = start_block_index / indirect_block_size; u_int64_t next_layer_start_index = start_block_index - (indirect_block_size * this_layer_start_index); @@ -102,16 +130,29 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, break; } - if (modified) - if ((err = disk->write_block(*block_num, buf)) < 0) - return err; + if (modified) { + bool delete_block = true; + for (size_t i = 0; i < IO_BLOCK_SIZE; ++i) + if (buf[i] != 0) { + delete_block = false; + break; + } + if (delete_block) { + if ((err = datablock_manager->free_datablock(*block_num)) < 0) + return err; + (*block_num) = 0; + } else { + if ((err = disk->write_block(*block_num, buf)) < 0) + return err; + } + } return result; } class ReadDatablockOperation : public DatablockOperation { public: - int operation(u_int64_t block_num) override { + int operation(u_int64_t block_num, bool *delete_block) override { char datablock_buf[IO_BLOCK_SIZE]; int err; @@ -122,7 +163,7 @@ public: std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); if (block_num != 0) { - if ((err = disk->read_block(block_num, datablock_buf)) < 0) + if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0) return err; memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size); @@ -141,7 +182,7 @@ public: class WriteDatablockOperation : public DatablockOperation { public: - int operation(u_int64_t block_num) override { + int operation(u_int64_t block_num, bool *delete_block) override { char datablock_buf[IO_BLOCK_SIZE]; int err; @@ -149,12 +190,12 @@ public: std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); if (write_size < IO_BLOCK_SIZE) - if ((err = disk->read_block(block_num, datablock_buf)) < 0) + if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0) return err; memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size); - if ((err = disk->write_block(block_num, datablock_buf)) < 0) + if ((err = fs->disk->write_block(block_num, datablock_buf)) < 0) return err; offset = 0; @@ -166,6 +207,42 @@ public: } }; +class TruncateDatablockOperation : public DatablockOperation { +public: + TruncateDatablockOperation() : skip(pass_skip_func) {} + int operation(u_int64_t block_num, bool *delete_block) override { + if (offset != 0) + return 1; + + offset = 0; + + delete_block = true; + + return 1; + } +}; + +class LseekNextDataDatablockOperation : public DatablockOperation { +public: + LseekNextDataDatablockOperation() : skip(default_skip_func) {} + int operation(u_int64_t block_num, bool *delete_block) override { return 0; } +}; + +class LseekNextHoleDatablockOperation : public DatablockOperation { +public: + int operation(u_int64_t block_num, bool *delete_block) override { + if (block_num == 0) + return 0; + + bytes_completed += (IO_BLOCK_SIZE)-offset; + offset = 0; + + if (bytes_completed >= count) + return 0; + return 1; + } +}; + ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count, size_t offset) { int err; @@ -178,10 +255,10 @@ ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count, op.buf = buf; op.count = std::min(count, inode_data->metadata.size - offset); op.bytes_completed = 0; - op.disk = disk; + op.fs = this; if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, - &op)) < 0) + &op)) != 0) return err; return op.bytes_completed; @@ -199,14 +276,83 @@ ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count, op.buf = buf; op.count = count; op.bytes_completed = 0; - op.disk = disk; + op.fs = this; - if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, &op)) < - 0) + if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, + &op)) != 0) return err; inode_data->metadata.size = std::max(offset + op.bytes_completed, inode_data->metadata.size); + return op.bytes_completed; +} + +int Fs::truncate(INode_Data *inode_data, size_t length) { + int err; + + u_int64_t start_block_index = length / IO_BLOCK_SIZE; + size_t internal_offset = length - (start_block_index * IO_BLOCK_SIZE); + + TruncateDatablockOperation op = TruncateDatablockOperation(); + op.offset = internal_offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + inode_data->metadata.size = length; + + return 0; +} + +int Fs::lseek_next_data(INode_Data *inode_data, size_t offset) { + int err; + + if (offset >= inode_data->metadata.size) + return -1; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + LseekNextDataDatablockOperation op = LseekNextDataDatablockOperation(); + op.offset = internal_offset; + op.count = inode_data->metadata.size; + op.bytes_completed = offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + if (op.bytes_completed >= inode_data->metadata.size) + return -1; + + return op.bytes_completed; +} + +int Fs::lseek_next_hole(INode_Data *inode_data, size_t offset) { + int err; + + if (offset >= inode_data->metadata.size) + return -1; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + LseekNextHoleDatablockOperation op = LseekNextHoleDatablockOperation(); + op.offset = internal_offset; + op.count = inode_data->metadata.size; + op.bytes_completed = offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + if (op.bytes_completed >= inode_data->metadata.size) + return inode_data->metadata.size; + return op.bytes_completed; } \ No newline at end of file diff --git a/lib/fs/fs_resize.cpp b/lib/fs/fs_resize.cpp index 194c064..0fe452a 100644 --- a/lib/fs/fs_resize.cpp +++ b/lib/fs/fs_resize.cpp @@ -1,72 +1,5 @@ #include "fs.hpp" -int Fs::allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) { - int result; - - for (size_t i = 0; i < NUMBER_OF_DIRECT_BLOCKS; ++i) { - result = - allocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num); - if (result <= 0) - return result; - } - - result = - allocate_indirect(&(inode_data->single_indirect_block), 1, datablock_num); - if (result <= 0) - return result; - - result = - allocate_indirect(&(inode_data->double_indirect_block), 2, datablock_num); - if (result <= 0) - return result; - - result = - allocate_indirect(&(inode_data->triple_indirect_block), 3, datablock_num); - if (result <= 0) - return result; - - return -1; -} - -// This can simply be made non recursive by copy pasting - it is just written -// this way as a proof of concept -int Fs::allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num) { - char buf[IO_BLOCK_SIZE]; - int result; - - if ((*storage) == 0) { - if ((result = datablock_manager->new_datablock(storage)) < 0) - return result; - if (n == 0) { - (*datablock_num) = (*storage); - return 0; - } - } - - if (n == 0) - return 1; - - u_int64_t temp; - - if ((result = disk->read_block(*storage, buf)) < 0) - return result; - - for (size_t i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) { - read_u64(&temp, &buf[i]); - result = allocate_indirect(&temp, n - 1, datablock_num); - if (result < 0) - return result; - if (result == 0) { - write_u64(temp, &buf[i]); - if ((result = disk->write_block(*storage, buf)) < 0) - return result; - return 0; - } - } - - return 1; -} - int Fs::deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) { int result;