Kernel: Don't crash if Ext2 filesystem doing too many fileops
I had a hardlimit of 10 block buffers and if they ran out, the kernel would crash. this patchs increases the number of buffers to 16 and removes the crash condition when they run out :D
This commit is contained in:
parent
948ef2c820
commit
391fc0c4c2
|
@ -26,18 +26,40 @@ namespace Kernel
|
|||
class BlockBufferWrapper
|
||||
{
|
||||
BAN_NON_COPYABLE(BlockBufferWrapper);
|
||||
BAN_NON_MOVABLE(BlockBufferWrapper);
|
||||
|
||||
public:
|
||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used)
|
||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker)
|
||||
: m_buffer(buffer)
|
||||
, m_used(used)
|
||||
, m_mutex(mutex)
|
||||
, m_blocker(blocker)
|
||||
{
|
||||
ASSERT(m_used);
|
||||
ASSERT(m_used && *m_used);
|
||||
}
|
||||
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
|
||||
~BlockBufferWrapper()
|
||||
{
|
||||
m_used = false;
|
||||
if (m_used == nullptr)
|
||||
return;
|
||||
m_mutex->lock();
|
||||
*m_used = false;
|
||||
m_blocker->unblock();
|
||||
m_mutex->unlock();
|
||||
}
|
||||
|
||||
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
|
||||
{
|
||||
this->m_buffer = other.m_buffer;
|
||||
this->m_used = other.m_used;
|
||||
this->m_mutex = other.m_mutex;
|
||||
this->m_blocker = other.m_blocker;
|
||||
|
||||
other.m_buffer = {};
|
||||
other.m_used = nullptr;
|
||||
other.m_mutex = nullptr;
|
||||
other.m_blocker = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t size() const { return m_buffer.size(); }
|
||||
|
@ -53,7 +75,9 @@ namespace Kernel
|
|||
|
||||
private:
|
||||
BAN::Span<uint8_t> m_buffer;
|
||||
bool& m_used;
|
||||
bool* m_used;
|
||||
Mutex* m_mutex;
|
||||
ThreadBlocker* m_blocker;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -79,7 +103,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> sync_superblock();
|
||||
BAN::ErrorOr<void> sync_block(uint32_t block);
|
||||
|
||||
BlockBufferWrapper get_block_buffer();
|
||||
BAN::ErrorOr<BlockBufferWrapper> get_block_buffer();
|
||||
|
||||
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
|
||||
BAN::ErrorOr<void> release_block(uint32_t block);
|
||||
|
@ -102,7 +126,7 @@ namespace Kernel
|
|||
{
|
||||
public:
|
||||
BlockBufferManager() = default;
|
||||
BlockBufferWrapper get_buffer();
|
||||
BAN::ErrorOr<BlockBufferWrapper> get_buffer();
|
||||
|
||||
BAN::ErrorOr<void> initialize(size_t block_size);
|
||||
|
||||
|
@ -114,7 +138,9 @@ namespace Kernel
|
|||
};
|
||||
|
||||
private:
|
||||
BAN::Array<BlockBuffer, 10> m_buffers;
|
||||
Mutex m_buffer_mutex;
|
||||
ThreadBlocker m_buffer_blocker;
|
||||
BAN::Array<BlockBuffer, 16> m_buffers;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace Kernel
|
|||
TRY(m_buffer_manager.initialize(block_size()));
|
||||
|
||||
{
|
||||
auto block_buffer = m_buffer_manager.get_buffer();
|
||||
auto block_buffer = TRY(m_buffer_manager.get_buffer());
|
||||
|
||||
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
|
||||
{
|
||||
|
@ -170,6 +170,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode)
|
||||
{
|
||||
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
|
||||
auto inode_bitmap = TRY(m_buffer_manager.get_buffer());
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
ASSERT(ext2_inode.size == 0);
|
||||
|
@ -179,9 +182,6 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
auto inode_bitmap = m_buffer_manager.get_buffer();
|
||||
|
||||
uint32_t current_group = -1;
|
||||
BlockLocation bgd_location {};
|
||||
Ext2::BlockGroupDescriptor* bgd = nullptr;
|
||||
|
@ -248,15 +248,15 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> Ext2FS::delete_inode(uint32_t ino)
|
||||
{
|
||||
auto bgd_buffer = TRY(get_block_buffer());
|
||||
auto bitmap_buffer = TRY(get_block_buffer());
|
||||
auto inode_buffer = TRY(get_block_buffer());
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
ASSERT(ino >= superblock().first_ino);
|
||||
ASSERT(ino <= superblock().inodes_count);
|
||||
|
||||
auto bgd_buffer = get_block_buffer();
|
||||
auto bitmap_buffer = get_block_buffer();
|
||||
auto inode_buffer = get_block_buffer();
|
||||
|
||||
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
|
||||
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
|
||||
|
||||
|
@ -334,6 +334,8 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> Ext2FS::sync_superblock()
|
||||
{
|
||||
auto superblock_buffer = TRY(get_block_buffer());
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
const uint32_t sector_size = m_block_device->blksize();
|
||||
|
@ -347,8 +349,6 @@ namespace Kernel
|
|||
const uint32_t lba = 1024 / sector_size;
|
||||
const uint32_t sector_count = BAN::Math::div_round_up<uint32_t>(superblock_bytes, sector_size);
|
||||
|
||||
auto superblock_buffer = get_block_buffer();
|
||||
|
||||
TRY(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span()));
|
||||
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
|
||||
{
|
||||
|
@ -370,22 +370,21 @@ namespace Kernel
|
|||
return m_block_device->sync_blocks(block * sectors_per_block, sectors_per_block);
|
||||
}
|
||||
|
||||
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
|
||||
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::get_block_buffer()
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return m_buffer_manager.get_buffer();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
|
||||
{
|
||||
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
|
||||
auto block_bitmap = TRY(m_buffer_manager.get_buffer());
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
|
||||
return BAN::Error::from_errno(ENOSPC);
|
||||
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
auto block_bitmap = m_buffer_manager.get_buffer();
|
||||
|
||||
auto check_block_group =
|
||||
[&](uint32_t block_group) -> BAN::ErrorOr<uint32_t>
|
||||
{
|
||||
|
@ -439,6 +438,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> Ext2FS::release_block(uint32_t block)
|
||||
{
|
||||
auto bgd_buffer = TRY(get_block_buffer());
|
||||
auto bitmap_buffer = TRY(get_block_buffer());
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
ASSERT(block >= m_superblock.first_data_block);
|
||||
|
@ -447,9 +449,6 @@ namespace Kernel
|
|||
const uint32_t block_group = (block - m_superblock.first_data_block) / m_superblock.blocks_per_group;
|
||||
const uint32_t block_offset = (block - m_superblock.first_data_block) % m_superblock.blocks_per_group;
|
||||
|
||||
auto bgd_buffer = get_block_buffer();
|
||||
auto bitmap_buffer = get_block_buffer();
|
||||
|
||||
auto bgd_location = locate_block_group_descriptior(block_group);
|
||||
TRY(read_block(bgd_location.block, bgd_buffer));
|
||||
|
||||
|
@ -480,7 +479,7 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
|
||||
|
||||
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
|
||||
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
|
||||
|
@ -533,16 +532,22 @@ namespace Kernel
|
|||
};
|
||||
}
|
||||
|
||||
Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer()
|
||||
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
|
||||
{
|
||||
for (auto& buffer : m_buffers)
|
||||
LockGuard _(m_buffer_mutex);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (buffer.used)
|
||||
continue;
|
||||
buffer.used = true;
|
||||
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used);
|
||||
for (auto& buffer : m_buffers)
|
||||
{
|
||||
if (buffer.used)
|
||||
continue;
|
||||
buffer.used = true;
|
||||
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker);
|
||||
}
|
||||
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex));
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Kernel
|
|||
|
||||
auto inode_location = TRY(fs.locate_inode(inode_ino));
|
||||
|
||||
auto block_buffer = fs.get_block_buffer();
|
||||
auto block_buffer = TRY(fs.get_block_buffer());
|
||||
TRY(fs.read_block(inode_location.block, block_buffer));
|
||||
|
||||
auto& inode = block_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
|
||||
|
@ -61,7 +61,7 @@ namespace Kernel
|
|||
return BAN::Optional<uint32_t>();
|
||||
ASSERT(depth >= 1);
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
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);
|
||||
|
@ -152,7 +152,7 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
const uint32_t first_block = offset / block_size;
|
||||
const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size);
|
||||
|
@ -192,7 +192,7 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
size_t written = 0;
|
||||
size_t to_write = buffer.size();
|
||||
|
@ -349,7 +349,7 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
TRY(m_fs.read_block(block, block_buffer));
|
||||
|
||||
const uint32_t ids_per_block = blksize() / sizeof(uint32_t);
|
||||
|
@ -409,7 +409,7 @@ done:
|
|||
// 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();
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
TRY(m_fs.read_block(block_index, block_buffer));
|
||||
|
||||
|
@ -602,7 +602,7 @@ done:
|
|||
|
||||
const uint32_t block_size = m_fs.block_size();
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
auto write_inode =
|
||||
[&](uint32_t entry_offset, uint32_t entry_rec_len) -> BAN::ErrorOr<void>
|
||||
|
@ -689,7 +689,7 @@ needs_new_block:
|
|||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
// Confirm that this doesn't contain anything else than '.' or '..'
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
|
@ -726,7 +726,7 @@ needs_new_block:
|
|||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
|
@ -782,7 +782,7 @@ needs_new_block:
|
|||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
|
@ -844,7 +844,7 @@ needs_new_block:
|
|||
block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
m_inode.blocks += inode_blocks_per_fs_block;
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
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));
|
||||
}
|
||||
|
@ -852,7 +852,7 @@ needs_new_block:
|
|||
if (depth == 0)
|
||||
return block;
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
TRY(m_fs.read_block(block, block_buffer));
|
||||
|
||||
uint32_t divisor = 1;
|
||||
|
@ -901,7 +901,7 @@ needs_new_block:
|
|||
BAN::ErrorOr<void> Ext2Inode::sync()
|
||||
{
|
||||
auto inode_location = TRY(m_fs.locate_inode(ino()));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
TRY(m_fs.read_block(inode_location.block, block_buffer));
|
||||
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
|
||||
|
@ -917,7 +917,7 @@ needs_new_block:
|
|||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue