From 6065b638011f5f91a80392f2fd4aef81aa3b38ba Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 6 Sep 2023 09:56:24 +0200 Subject: [PATCH] kernel/ext2: Add support for files larger than 4MB --- kernel/src/fs/ext2/Inode.cpp | 52 +++++++++++++++++++++++++++++------- kernel/src/fs/ext2/Inode.h | 3 ++- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/kernel/src/fs/ext2/Inode.cpp b/kernel/src/fs/ext2/Inode.cpp index 8c132e79..e1bbd47c 100644 --- a/kernel/src/fs/ext2/Inode.cpp +++ b/kernel/src/fs/ext2/Inode.cpp @@ -7,6 +7,13 @@ namespace Ext2 { } + Result Inode::prepare_buffer() const + { + if (!m_block_buffer.is_empty()) return {}; + return m_block_buffer.try_resize(m_fs->m_block_size); + } + + // FIXME: This code seems awfully similar to BlockDevice::read(). Can this be merged with it in some way? Result Inode::read(u8* buf, usize offset, usize length) const { if (length == 0) return 0; @@ -66,22 +73,47 @@ namespace Ext2 { if (index < 12) return m_raw_inode.direct_pointers[index]; - usize block_index = (index - 12) * sizeof(u32); - if (block_index >= m_fs->m_block_size) - { - fail("ext2: Finding blocks beyond the singly indirect pointer block is not yet supported"); - } + const usize block_size = m_fs->m_block_size; + const usize blocks_per_indirect_block = block_size / sizeof(u32); - usize block_size = m_fs->m_block_size; + index -= 12; - if (m_singly_indirect_block.is_empty()) + TRY(prepare_buffer()); + + // Singly indirect block + if (index < blocks_per_indirect_block) { - TRY(m_singly_indirect_block.try_resize(block_size)); - TRY(m_fs->m_host_device->read(m_singly_indirect_block.data(), m_raw_inode.singly_indirect_ptr * block_size, + TRY(m_fs->m_host_device->read(m_block_buffer.data(), m_raw_inode.singly_indirect_ptr * block_size, block_size)); + return ((u32*)m_block_buffer.data())[index]; } - return *reinterpret_cast(&m_singly_indirect_block.data()[block_index]); + index -= blocks_per_indirect_block; + + // Doubly indirect block + if (index < blocks_per_indirect_block * blocks_per_indirect_block) + { + TRY(m_fs->m_host_device->read(m_block_buffer.data(), m_raw_inode.doubly_indirect_ptr * block_size, + block_size)); + const u32 block = ((u32*)m_block_buffer.data())[index / blocks_per_indirect_block]; + + TRY(m_fs->m_host_device->read(m_block_buffer.data(), block * block_size, block_size)); + return ((u32*)m_block_buffer.data())[index % blocks_per_indirect_block]; + } + + index -= blocks_per_indirect_block * blocks_per_indirect_block; + + check(index < blocks_per_indirect_block * blocks_per_indirect_block * blocks_per_indirect_block); + + // Triply indirect block + TRY(m_fs->m_host_device->read(m_block_buffer.data(), m_raw_inode.triply_indirect_ptr * block_size, block_size)); + u32 block = ((u32*)m_block_buffer.data())[index / (blocks_per_indirect_block * blocks_per_indirect_block)]; + + TRY(m_fs->m_host_device->read(m_block_buffer.data(), block * block_size, block_size)); + block = ((u32*)m_block_buffer.data())[(index / blocks_per_indirect_block) % blocks_per_indirect_block]; + + TRY(m_fs->m_host_device->read(m_block_buffer.data(), block * block_size, block_size)); + return ((u32*)m_block_buffer.data())[index % blocks_per_indirect_block]; } Result Inode::lazy_initialize_dir() const diff --git a/kernel/src/fs/ext2/Inode.h b/kernel/src/fs/ext2/Inode.h index fa7211f3..6234f144 100644 --- a/kernel/src/fs/ext2/Inode.h +++ b/kernel/src/fs/ext2/Inode.h @@ -115,7 +115,7 @@ namespace Ext2 FileSystem* m_fs; ino_t m_inum; - mutable Buffer m_singly_indirect_block; + mutable Buffer m_block_buffer; String m_link; @@ -123,6 +123,7 @@ namespace Ext2 mutable bool m_dir_already_lazily_initialized { false }; Result find_block(usize index) const; + Result prepare_buffer() const; friend class FileSystem; };