Kernel: Optimize ext2 filesystem
block lookup can now also allocate blocks so there is no need to do multiple lookups of the block did not exist
This commit is contained in:
parent
33b6536e6b
commit
941e8aa5d5
|
|
@ -61,8 +61,8 @@ namespace Kernel
|
|||
// NOTE: the inode might have more blocks than what this suggests if it has been shrinked
|
||||
uint32_t max_used_data_block_count() const { return size() / blksize(); }
|
||||
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth);
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index);
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> block_from_indirect_block(uint32_t& block, uint32_t index, uint32_t depth, bool allocate);
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index, bool allocate);
|
||||
|
||||
BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
|
||||
BAN::ErrorOr<void> remove_inode_from_directory(BAN::StringView name, bool cleanup_directory);
|
||||
|
|
@ -72,8 +72,6 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> cleanup_default_links();
|
||||
BAN::ErrorOr<void> cleanup_from_fs();
|
||||
|
||||
BAN::ErrorOr<uint32_t> allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth);
|
||||
BAN::ErrorOr<uint32_t> allocate_new_block(uint32_t data_block_index);
|
||||
BAN::ErrorOr<void> sync();
|
||||
|
||||
uint32_t block_group() const;
|
||||
|
|
|
|||
|
|
@ -56,52 +56,103 @@ namespace Kernel
|
|||
return &m_fs;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t& block, uint32_t index, uint32_t depth, bool allocate)
|
||||
{
|
||||
if (block == 0)
|
||||
return BAN::Optional<uint32_t>();
|
||||
ASSERT(depth >= 1);
|
||||
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
|
||||
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
if (depth == 0)
|
||||
{
|
||||
if (block == 0)
|
||||
{
|
||||
if (!allocate)
|
||||
return BAN::Optional<uint32_t>();
|
||||
|
||||
block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size());
|
||||
TRY(m_fs.write_block(block, block_buffer));
|
||||
|
||||
TRY(sync());
|
||||
}
|
||||
|
||||
return BAN::Optional<uint32_t>(block);
|
||||
}
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
TRY(m_fs.read_block(block, block_buffer));
|
||||
|
||||
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
|
||||
bool needs_sync = false;
|
||||
|
||||
if (block != 0)
|
||||
TRY(m_fs.read_block(block, block_buffer));
|
||||
else
|
||||
{
|
||||
if (!allocate)
|
||||
return BAN::Optional<uint32_t>();
|
||||
|
||||
block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
|
||||
memset(block_buffer.data(), 0, block_buffer.size());
|
||||
|
||||
needs_sync = true;
|
||||
}
|
||||
|
||||
uint32_t divisor = 1;
|
||||
for (uint32_t i = 1; i < depth; i++)
|
||||
divisor *= indices_per_block;
|
||||
divisor *= indices_per_fs_block;
|
||||
|
||||
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block];
|
||||
if (next_block == 0)
|
||||
return BAN::Optional<uint32_t>();
|
||||
if (depth == 1)
|
||||
return BAN::Optional<uint32_t>(next_block);
|
||||
uint32_t& new_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_fs_block];
|
||||
const auto old_block = new_block;
|
||||
|
||||
return block_from_indirect_block(next_block, index, depth - 1);
|
||||
const auto result = TRY(block_from_indirect_block(new_block, index, depth - 1, allocate));
|
||||
|
||||
if (needs_sync || old_block != new_block)
|
||||
TRY(m_fs.write_block(block, block_buffer));
|
||||
if (needs_sync)
|
||||
TRY(sync());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index, bool allocate)
|
||||
{
|
||||
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
|
||||
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
if (data_block_index < 12)
|
||||
{
|
||||
if (m_inode.block[data_block_index] == 0)
|
||||
if (m_inode.block[data_block_index] != 0)
|
||||
return BAN::Optional<uint32_t>(m_inode.block[data_block_index]);
|
||||
if (!allocate)
|
||||
return BAN::Optional<uint32_t>();
|
||||
return BAN::Optional<uint32_t>(m_inode.block[data_block_index]);
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
memset(block_buffer.data(), 0, block_buffer.size());
|
||||
|
||||
const auto block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
TRY(m_fs.write_block(block, block_buffer));
|
||||
|
||||
m_inode.block[data_block_index] = block;
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
TRY(sync());
|
||||
|
||||
return BAN::Optional<uint32_t>(block);
|
||||
}
|
||||
data_block_index -= 12;
|
||||
|
||||
if (data_block_index < indices_per_block)
|
||||
return block_from_indirect_block(m_inode.block[12], data_block_index, 1);
|
||||
return block_from_indirect_block(m_inode.block[12], data_block_index, 1, allocate);
|
||||
data_block_index -= indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block)
|
||||
return block_from_indirect_block(m_inode.block[13], data_block_index, 2);
|
||||
return block_from_indirect_block(m_inode.block[13], data_block_index, 2, allocate);
|
||||
data_block_index -= indices_per_block * indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
|
||||
return block_from_indirect_block(m_inode.block[14], data_block_index, 3);
|
||||
return block_from_indirect_block(m_inode.block[14], data_block_index, 3, allocate);
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -167,7 +218,7 @@ namespace Kernel
|
|||
|
||||
for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
|
||||
{
|
||||
auto block_index = TRY(fs_block_of_data_block_index(data_block_index));
|
||||
auto block_index = TRY(fs_block_of_data_block_index(data_block_index, false));
|
||||
if (block_index.has_value())
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
else
|
||||
|
|
@ -206,17 +257,13 @@ namespace Kernel
|
|||
// Write partial block
|
||||
if (offset % block_size)
|
||||
{
|
||||
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
|
||||
if (block_index.has_value())
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
else
|
||||
{
|
||||
block_index = TRY(allocate_new_block(offset / block_size));;
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size());
|
||||
}
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(offset / block_size, true));
|
||||
ASSERT(block_index.has_value());
|
||||
|
||||
uint32_t block_offset = offset % block_size;
|
||||
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
const uint32_t block_offset = offset % block_size;
|
||||
const uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
|
||||
|
||||
memcpy(block_buffer.data() + block_offset, buffer.data(), to_copy);
|
||||
TRY(m_fs.write_block(block_index.value(), block_buffer));
|
||||
|
|
@ -228,9 +275,8 @@ namespace Kernel
|
|||
|
||||
while (to_write >= block_size)
|
||||
{
|
||||
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
|
||||
if (!block_index.has_value())
|
||||
block_index = TRY(allocate_new_block(offset / block_size));
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(offset / block_size, true));
|
||||
ASSERT(block_index.has_value());
|
||||
|
||||
memcpy(block_buffer.data(), buffer.data() + written, block_buffer.size());
|
||||
TRY(m_fs.write_block(block_index.value(), block_buffer));
|
||||
|
|
@ -242,14 +288,10 @@ namespace Kernel
|
|||
|
||||
if (to_write > 0)
|
||||
{
|
||||
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
|
||||
if (block_index.has_value())
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
else
|
||||
{
|
||||
block_index = TRY(allocate_new_block(offset / block_size));
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size());
|
||||
}
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(offset / block_size, true));
|
||||
ASSERT(block_index.has_value());
|
||||
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
memcpy(block_buffer.data(), buffer.data() + written, to_write);
|
||||
TRY(m_fs.write_block(block_index.value(), block_buffer));
|
||||
|
|
@ -340,7 +382,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
|
||||
{
|
||||
for (size_t i = 0; i < max_used_data_block_count(); i++)
|
||||
if (const auto fs_block = TRY(fs_block_of_data_block_index(i)); fs_block.has_value())
|
||||
if (const auto fs_block = TRY(fs_block_of_data_block_index(i, false)); fs_block.has_value())
|
||||
TRY(m_fs.sync_block(fs_block.value()));
|
||||
return {};
|
||||
}
|
||||
|
|
@ -412,12 +454,12 @@ done:
|
|||
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
|
||||
return 0;
|
||||
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = TRY(fs_block_of_data_block_index(offset)).value();
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(offset, false));
|
||||
if (!block_index.has_value())
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
// First determine if we have big enough list
|
||||
size_t entry_count = 0;
|
||||
|
|
@ -681,7 +723,7 @@ done:
|
|||
goto needs_new_block;
|
||||
|
||||
// Try to insert inode to last data block
|
||||
block_index = TRY(fs_block_of_data_block_index(data_block_count - 1)).value();
|
||||
block_index = TRY(fs_block_of_data_block_index(data_block_count - 1, true)).value();
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
|
||||
while (entry_offset < block_size)
|
||||
|
|
@ -712,7 +754,7 @@ done:
|
|||
}
|
||||
|
||||
needs_new_block:
|
||||
block_index = TRY(allocate_new_block(data_block_count));
|
||||
block_index = TRY(fs_block_of_data_block_index(data_block_count, true)).value();
|
||||
m_inode.size += blksize();
|
||||
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size());
|
||||
|
|
@ -731,9 +773,10 @@ needs_new_block:
|
|||
// Confirm that this doesn't contain anything else than '.' or '..'
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
|
||||
if (!block_index.has_value())
|
||||
continue;
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
blksize_t offset = 0;
|
||||
while (offset < blksize())
|
||||
|
|
@ -767,9 +810,10 @@ needs_new_block:
|
|||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
|
||||
if (!block_index.has_value())
|
||||
continue;
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
bool modified = false;
|
||||
|
||||
|
|
@ -804,7 +848,7 @@ needs_new_block:
|
|||
}
|
||||
|
||||
if (modified)
|
||||
TRY(m_fs.write_block(block_index, block_buffer));
|
||||
TRY(m_fs.write_block(block_index.value(), block_buffer));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
@ -823,9 +867,10 @@ needs_new_block:
|
|||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
|
||||
if (!block_index.has_value())
|
||||
continue;
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
blksize_t offset = 0;
|
||||
while (offset < blksize())
|
||||
|
|
@ -859,7 +904,7 @@ needs_new_block:
|
|||
|
||||
// FIXME: This should expand the last inode if exists
|
||||
entry.inode = 0;
|
||||
TRY(m_fs.write_block(block_index, block_buffer));
|
||||
TRY(m_fs.write_block(block_index.value(), block_buffer));
|
||||
}
|
||||
offset += entry.rec_len;
|
||||
}
|
||||
|
|
@ -874,73 +919,6 @@ needs_new_block:
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth)
|
||||
{
|
||||
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
|
||||
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
if (depth == 0)
|
||||
ASSERT(block == 0);
|
||||
|
||||
if (block == 0)
|
||||
{
|
||||
block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size());
|
||||
TRY(m_fs.write_block(block, block_buffer));
|
||||
}
|
||||
|
||||
if (depth == 0)
|
||||
return block;
|
||||
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
TRY(m_fs.read_block(block, block_buffer));
|
||||
|
||||
uint32_t divisor = 1;
|
||||
for (uint32_t i = 1; i < depth; i++)
|
||||
divisor *= indices_per_fs_block;
|
||||
|
||||
uint32_t& new_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_fs_block];
|
||||
|
||||
uint32_t allocated_block = TRY(allocate_new_block_to_indirect_block(new_block, index, depth - 1));
|
||||
TRY(m_fs.write_block(block, block_buffer));
|
||||
|
||||
TRY(sync());
|
||||
|
||||
return allocated_block;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block(uint32_t data_block_index)
|
||||
{
|
||||
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
|
||||
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
if (data_block_index < 12)
|
||||
{
|
||||
ASSERT(m_inode.block[data_block_index] == 0);
|
||||
m_inode.block[data_block_index] = TRY(m_fs.reserve_free_block(block_group()));
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
TRY(sync());
|
||||
return m_inode.block[data_block_index];
|
||||
}
|
||||
data_block_index -= 12;
|
||||
|
||||
if (data_block_index < indices_per_fs_block)
|
||||
return TRY(allocate_new_block_to_indirect_block(m_inode.block[12], data_block_index, 1));
|
||||
data_block_index -= indices_per_fs_block;
|
||||
|
||||
if (data_block_index < indices_per_fs_block * indices_per_fs_block)
|
||||
return TRY(allocate_new_block_to_indirect_block(m_inode.block[13], data_block_index, 2));
|
||||
data_block_index -= indices_per_fs_block * indices_per_fs_block;
|
||||
|
||||
if (data_block_index < indices_per_fs_block * indices_per_fs_block * indices_per_fs_block)
|
||||
return TRY(allocate_new_block_to_indirect_block(m_inode.block[14], data_block_index, 3));
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::sync()
|
||||
{
|
||||
auto inode_location = TRY(m_fs.locate_inode(ino()));
|
||||
|
|
@ -964,9 +942,10 @@ needs_new_block:
|
|||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
|
||||
if (!block_index.has_value())
|
||||
continue;
|
||||
TRY(m_fs.read_block(block_index.value(), block_buffer));
|
||||
|
||||
BAN::ConstByteSpan entry_span = block_buffer.span();
|
||||
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
||||
|
|
|
|||
Loading…
Reference in New Issue