diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index d93d68d8..c5329b11 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -49,6 +49,7 @@ namespace Kernel BAN::ErrorOr link_inode_to_directory(Ext2Inode&, BAN::StringView name); BAN::ErrorOr is_directory_empty(); + void cleanup_indirect_block(uint32_t block, uint32_t depth); BAN::ErrorOr cleanup_default_links(); void cleanup_from_fs(); diff --git a/kernel/kernel/FS/Ext2/FileSystem.cpp b/kernel/kernel/FS/Ext2/FileSystem.cpp index 8a2bb6af..48da9e3f 100644 --- a/kernel/kernel/FS/Ext2/FileSystem.cpp +++ b/kernel/kernel/FS/Ext2/FileSystem.cpp @@ -4,6 +4,7 @@ #define EXT2_DEBUG_PRINT 0 #define EXT2_VERIFY_INODE 0 +#define EXT2_VERIFY_NO_BLOCKS 1 namespace Kernel { @@ -244,6 +245,10 @@ namespace Kernel auto inode_location = locate_inode(ino); read_block(inode_location.block, inode_buffer); auto& inode = inode_buffer.span().slice(inode_location.offset).as(); +#if EXT2_VERIFY_NO_BLOCKS + static const char zero_buffer[sizeof(inode.block)] {}; + ASSERT(memcmp(inode.block, zero_buffer, sizeof(inode.block)) == 0); +#endif bool is_directory = Inode::Mode(inode.mode).ifdir(); memset(&inode, 0x00, m_superblock.inode_size); write_block(inode_location.block, inode_buffer); diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index 29b81bc7..28c0afc7 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -259,11 +259,54 @@ namespace Kernel return {}; } + void Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth) + { + ASSERT(block); + + if (depth == 0) + { + m_fs.release_block(block); + return; + } + + auto block_buffer = m_fs.get_block_buffer(); + m_fs.read_block(block, block_buffer); + + const uint32_t ids_per_block = blksize() / sizeof(uint32_t); + for (uint32_t i = 0; i < ids_per_block; i++) + { + const uint32_t idx = ((uint32_t*)block_buffer.data())[i]; + if (idx > 0) + cleanup_indirect_block(idx, depth - 1); + } + + m_fs.release_block(block); + } + void Ext2Inode::cleanup_from_fs() { ASSERT(m_inode.links_count == 0); - for (uint32_t i = 0; i < blocks(); i++) - m_fs.release_block(fs_block_of_data_block_index(i)); + + // cleanup direct blocks + for (uint32_t i = 0; i < 12; i++) + if (m_inode.block[i]) + m_fs.release_block(m_inode.block[i]); + + // cleanup indirect blocks + if (m_inode.block[12]) + cleanup_indirect_block(m_inode.block[12], 1); + if (m_inode.block[13]) + cleanup_indirect_block(m_inode.block[13], 2); + if (m_inode.block[14]) + cleanup_indirect_block(m_inode.block[14], 3); + + // mark blocks as deleted + memset(m_inode.block, 0x00, sizeof(m_inode.block)); + + // FIXME: this is only required since fs does not get + // deleting inode from its cache + sync(); + m_fs.delete_inode(ino()); }