Kernel: Start work on making inodes more thread safe
All inode operations are now locked and thread blocked
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/FS/Ext2/FileSystem.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
|
||||
#define EXT2_DEBUG_PRINT 0
|
||||
#define EXT2_VERIFY_INODE 0
|
||||
@@ -135,6 +136,8 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
ASSERT(ext2_inode.size == 0);
|
||||
|
||||
if (m_superblock.free_inodes_count == 0)
|
||||
@@ -213,6 +216,8 @@ namespace Kernel
|
||||
|
||||
void Ext2FS::read_block(uint32_t block, BAN::Span<uint8_t> buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
const uint32_t sector_size = m_partition.device().sector_size();
|
||||
const uint32_t block_size = this->block_size();
|
||||
const uint32_t sectors_per_block = block_size / sector_size;
|
||||
@@ -225,6 +230,8 @@ namespace Kernel
|
||||
|
||||
void Ext2FS::write_block(uint32_t block, BAN::Span<const uint8_t> buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
const uint32_t sector_size = m_partition.device().sector_size();
|
||||
const uint32_t block_size = this->block_size();
|
||||
const uint32_t sectors_per_block = block_size / sector_size;
|
||||
@@ -237,6 +244,8 @@ namespace Kernel
|
||||
|
||||
void Ext2FS::sync_superblock()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
const uint32_t sector_size = m_partition.device().sector_size();
|
||||
ASSERT(1024 % sector_size == 0);
|
||||
|
||||
@@ -261,6 +270,8 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
|
||||
return BAN::Error::from_errno(ENOSPC);
|
||||
|
||||
@@ -325,6 +336,8 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
ASSERT(ino <= superblock().inodes_count);
|
||||
|
||||
const uint32_t block_size = this->block_size();
|
||||
@@ -366,6 +379,8 @@ namespace Kernel
|
||||
|
||||
Ext2FS::BlockLocation Ext2FS::locate_block_group_descriptior(uint32_t group_index)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
const uint32_t block_group_count = BAN::Math::div_round_up(superblock().inodes_count, superblock().inodes_per_group);
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace Kernel
|
||||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::String> Ext2Inode::link_target()
|
||||
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
|
||||
{
|
||||
ASSERT(mode().iflnk());
|
||||
if (m_inode.size < sizeof(m_inode.block))
|
||||
@@ -167,12 +167,15 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Ext2Inode::read(size_t offset, void* buffer, size_t count)
|
||||
BAN::ErrorOr<size_t> Ext2Inode::read_impl(off_t offset, void* buffer, size_t count)
|
||||
{
|
||||
// FIXME: update atime if needed
|
||||
|
||||
if (mode().ifdir())
|
||||
return BAN::Error::from_errno(EISDIR);
|
||||
ASSERT(!mode().ifdir());
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
if (offset >= UINT32_MAX || count >= UINT32_MAX || offset + count >= UINT32_MAX)
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
if (offset >= m_inode.size)
|
||||
return 0;
|
||||
@@ -204,16 +207,18 @@ namespace Kernel
|
||||
return n_read;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Ext2Inode::write(size_t offset, const void* buffer, size_t count)
|
||||
BAN::ErrorOr<size_t> Ext2Inode::write_impl(off_t offset, const void* buffer, size_t count)
|
||||
{
|
||||
if (offset >= UINT32_MAX || count == UINT32_MAX || offset + count >= UINT32_MAX)
|
||||
// FIXME: update atime if needed
|
||||
|
||||
ASSERT(!mode().ifdir());
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
if (offset >= UINT32_MAX || count >= UINT32_MAX || offset + count >= UINT32_MAX)
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
if (mode().ifdir())
|
||||
return BAN::Error::from_errno(EISDIR);
|
||||
|
||||
if (m_inode.size < offset + count)
|
||||
TRY(truncate(offset + count));
|
||||
TRY(truncate_impl(offset + count));
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
@@ -222,6 +227,8 @@ namespace Kernel
|
||||
|
||||
const uint8_t* u8buffer = (const uint8_t*)buffer;
|
||||
|
||||
size_t written = 0;
|
||||
|
||||
// Write partial block
|
||||
if (offset % block_size)
|
||||
{
|
||||
@@ -229,7 +236,7 @@ namespace Kernel
|
||||
uint32_t block_offset = offset % block_size;
|
||||
|
||||
uint32_t data_block_index = TRY(this->data_block_index(block_index));
|
||||
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, count);
|
||||
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, written);
|
||||
|
||||
m_fs.read_block(data_block_index, block_buffer.span());
|
||||
memcpy(block_buffer.data() + block_offset, buffer, to_copy);
|
||||
@@ -237,10 +244,10 @@ namespace Kernel
|
||||
|
||||
u8buffer += to_copy;
|
||||
offset += to_copy;
|
||||
count -= to_copy;
|
||||
written -= to_copy;
|
||||
}
|
||||
|
||||
while (count >= block_size)
|
||||
while (written >= block_size)
|
||||
{
|
||||
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
|
||||
|
||||
@@ -248,22 +255,22 @@ namespace Kernel
|
||||
|
||||
u8buffer += block_size;
|
||||
offset += block_size;
|
||||
count -= block_size;
|
||||
written -= block_size;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
if (written > 0)
|
||||
{
|
||||
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
|
||||
|
||||
m_fs.read_block(data_block_index, block_buffer.span());
|
||||
memcpy(block_buffer.data(), u8buffer, count);
|
||||
memcpy(block_buffer.data(), u8buffer, written);
|
||||
m_fs.write_block(data_block_index, block_buffer.span());
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::truncate(size_t new_size)
|
||||
BAN::ErrorOr<void> Ext2Inode::truncate_impl(size_t new_size)
|
||||
{
|
||||
if (m_inode.size == new_size)
|
||||
return {};
|
||||
@@ -304,10 +311,10 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::directory_read_next_entries(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||
BAN::ErrorOr<void> Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||
{
|
||||
if (!mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
ASSERT(mode().ifdir());
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
const uint32_t data_block_count = blocks();
|
||||
if (offset >= data_block_count)
|
||||
@@ -369,7 +376,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
BAN::ErrorOr<void> Ext2Inode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
if (!this->mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
@@ -386,7 +393,7 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
auto error_or = directory_find_inode(name);
|
||||
auto error_or = find_inode_impl(name);
|
||||
if (!error_or.is_error())
|
||||
return BAN::Error::from_errno(EEXISTS);
|
||||
if (error_or.error().get_error_code() != ENOENT)
|
||||
@@ -424,7 +431,7 @@ namespace Kernel
|
||||
|
||||
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len)
|
||||
{
|
||||
auto typed_mode = Mode { mode };
|
||||
auto typed_mode = Mode(mode);
|
||||
uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0
|
||||
: typed_mode.ifreg() ? Ext2::Enum::REG_FILE
|
||||
: typed_mode.ifdir() ? Ext2::Enum::DIR
|
||||
@@ -542,10 +549,9 @@ needs_new_block:
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::directory_find_inode(BAN::StringView file_name)
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::find_inode_impl(BAN::StringView file_name)
|
||||
{
|
||||
if (!mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
const uint32_t data_block_count = blocks();
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -55,4 +57,74 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (!mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
return find_inode_impl(name);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::list_next_inodes(off_t offset, DirectoryEntryList* list, size_t list_len)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (!mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
return list_next_inodes_impl(offset, list, list_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (!this->mode().ifdir())
|
||||
return BAN::Error::from_errno(ENOTDIR);
|
||||
return create_file_impl(name, mode, uid, gid);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::String> Inode::link_target()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (!mode().iflnk())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
return link_target_impl();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Inode::read(off_t offset, void* buffer, size_t bytes)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (mode().ifdir())
|
||||
return BAN::Error::from_errno(EISDIR);
|
||||
return read_impl(offset, buffer, bytes);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Inode::write(off_t offset, const void* buffer, size_t bytes)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (mode().ifdir())
|
||||
return BAN::Error::from_errno(EISDIR);
|
||||
return write_impl(offset, buffer, bytes);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::truncate(size_t size)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
if (mode().ifdir())
|
||||
return BAN::Error::from_errno(EISDIR);
|
||||
return truncate_impl(size);
|
||||
}
|
||||
|
||||
bool Inode::has_data() const
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
Thread::TerminateBlocker blocker(Thread::current());
|
||||
return has_data_impl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,9 +39,9 @@ namespace Kernel
|
||||
m_semaphore.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Pipe::read(size_t, void* buffer, size_t count)
|
||||
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, void* buffer, size_t count)
|
||||
{
|
||||
m_lock.lock();
|
||||
LockGuard _(m_lock);
|
||||
while (m_buffer.empty())
|
||||
{
|
||||
if (m_writing_count == 0)
|
||||
@@ -61,12 +61,10 @@ namespace Kernel
|
||||
|
||||
m_semaphore.unblock();
|
||||
|
||||
m_lock.unlock();
|
||||
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Pipe::write(size_t, const void* buffer, size_t count)
|
||||
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, const void* buffer, size_t count)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<RamInode>> RamInode::create(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
ASSERT(Mode{ mode }.ifreg());
|
||||
ASSERT(Mode(mode).ifreg());
|
||||
auto* ram_inode = new RamInode(fs, mode, uid, gid);
|
||||
if (ram_inode == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
@@ -40,26 +40,26 @@ namespace Kernel
|
||||
m_inode_info.rdev = 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> RamInode::read(size_t offset, void* buffer, size_t bytes)
|
||||
BAN::ErrorOr<size_t> RamInode::read_impl(off_t offset, void* buffer, size_t bytes)
|
||||
{
|
||||
if (offset >= (size_t)size())
|
||||
ASSERT(offset >= 0);
|
||||
if (offset >= size())
|
||||
return 0;
|
||||
|
||||
size_t to_copy = BAN::Math::min<size_t>(m_inode_info.size - offset, bytes);
|
||||
memcpy(buffer, m_data.data(), to_copy);
|
||||
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> RamInode::write(size_t offset, const void* buffer, size_t bytes)
|
||||
BAN::ErrorOr<size_t> RamInode::write_impl(off_t offset, const void* buffer, size_t bytes)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
if (offset + bytes > (size_t)size())
|
||||
TRY(truncate(offset + bytes));
|
||||
TRY(truncate_impl(offset + bytes));
|
||||
memcpy(m_data.data() + offset, buffer, bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> RamInode::truncate(size_t new_size)
|
||||
BAN::ErrorOr<void> RamInode::truncate_impl(size_t new_size)
|
||||
{
|
||||
TRY(m_data.resize(new_size, 0));
|
||||
m_inode_info.size = m_data.size();
|
||||
@@ -75,7 +75,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<RamDirectoryInode>> RamDirectoryInode::create(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
ASSERT(Mode{ mode }.ifdir());
|
||||
ASSERT(Mode(mode).ifdir());
|
||||
auto* ram_inode = new RamDirectoryInode(fs, parent, mode, uid, gid);
|
||||
if (ram_inode == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
@@ -101,7 +101,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> RamDirectoryInode::directory_find_inode(BAN::StringView name)
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> RamDirectoryInode::find_inode_impl(BAN::StringView name)
|
||||
{
|
||||
if (name == "."sv)
|
||||
{
|
||||
@@ -127,8 +127,10 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> RamDirectoryInode::directory_read_next_entries(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||
BAN::ErrorOr<void> RamDirectoryInode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
// TODO: don't require memory for all entries on single call
|
||||
if (offset != 0)
|
||||
{
|
||||
@@ -175,12 +177,12 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> RamDirectoryInode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
BAN::ErrorOr<void> RamDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
BAN::RefPtr<RamInode> inode;
|
||||
if (Mode{ mode }.ifreg())
|
||||
if (Mode(mode).ifreg())
|
||||
inode = TRY(RamInode::create(m_fs, mode, uid, gid));
|
||||
else if (Mode{ mode }.ifdir())
|
||||
else if (Mode(mode).ifdir())
|
||||
inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode, uid, gid));
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
@@ -222,7 +224,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<RamSymlinkInode>> RamSymlinkInode::create(RamFileSystem& fs, BAN::StringView target, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
ASSERT(Mode{ mode }.iflnk());
|
||||
ASSERT(Mode(mode).iflnk());
|
||||
auto* ram_inode = new RamSymlinkInode(fs, mode, uid, gid);
|
||||
if (ram_inode == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
@@ -235,7 +237,7 @@ namespace Kernel
|
||||
: RamInode(fs, mode, uid, gid)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<BAN::String> RamSymlinkInode::link_target()
|
||||
BAN::ErrorOr<BAN::String> RamSymlinkInode::link_target_impl()
|
||||
{
|
||||
BAN::String result;
|
||||
TRY(result.append(m_target));
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Kernel
|
||||
ASSERT(root.size() >= 5 && root.substring(0, 5) == "/dev/"sv);;
|
||||
root = root.substring(5);
|
||||
|
||||
auto partition_inode = MUST(DevFileSystem::get().root_inode()->directory_find_inode(root));
|
||||
auto partition_inode = MUST(DevFileSystem::get().root_inode()->find_inode(root));
|
||||
s_instance->m_root_fs = MUST(Ext2FS::create(*(Partition*)partition_inode.ptr()));
|
||||
|
||||
Credentials root_creds { 0, 0, 0, 0 };
|
||||
@@ -119,9 +119,9 @@ namespace Kernel
|
||||
else if (path_part == ".."sv)
|
||||
{
|
||||
if (auto* mount_point = mount_from_root_inode(inode))
|
||||
inode = TRY(mount_point->host.inode->directory_find_inode(".."sv));
|
||||
inode = TRY(mount_point->host.inode->find_inode(".."sv));
|
||||
else
|
||||
inode = TRY(inode->directory_find_inode(".."sv));
|
||||
inode = TRY(inode->find_inode(".."sv));
|
||||
|
||||
if (!canonical_path.empty())
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace Kernel
|
||||
if (!inode->can_access(credentials, O_SEARCH))
|
||||
return BAN::Error::from_errno(EACCES);
|
||||
|
||||
inode = TRY(inode->directory_find_inode(path_part));
|
||||
inode = TRY(inode->find_inode(path_part));
|
||||
|
||||
if (auto* mount_point = mount_from_host_inode(inode))
|
||||
inode = mount_point->target->root_inode();
|
||||
|
||||
Reference in New Issue
Block a user