Kernel: Remove the big inode lock

This moves locking to the inodes themselves which allows reducing lock
times significantly. Main inodes (ext2 and tmpfs) still do contain a
single big mutex that gets locked during operations but now we have the
architecture to optimize these.
This commit is contained in:
2026-05-09 21:30:05 +03:00
parent a7356716ff
commit 9f4271f6d8
31 changed files with 378 additions and 189 deletions

View File

@@ -1,4 +1,5 @@
#include <kernel/FS/EventFD.h>
#include <kernel/Lock/LockGuard.h>
#include <sys/epoll.h>
@@ -18,16 +19,20 @@ namespace Kernel
if (buffer.size() < sizeof(uint64_t))
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
while (m_value == 0)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
const uint64_t read_value = m_is_semaphore ? 1 : m_value;
const uint64_t read_value = m_is_semaphore ? 1 : m_value.load();
m_value -= read_value;
buffer.as<uint64_t>() = read_value;
epoll_notify(EPOLLOUT);
m_thread_blocker.unblock();
return sizeof(uint64_t);
}
@@ -40,6 +45,8 @@ namespace Kernel
if (write_value == UINT64_MAX)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
while (m_value + write_value < m_value)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
@@ -48,6 +55,8 @@ namespace Kernel
if (m_value > 0)
epoll_notify(EPOLLIN);
m_thread_blocker.unblock();
return sizeof(uint64_t);
}

View File

@@ -61,6 +61,8 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
LockGuard _(m_lock);
if (block == 0 && !allocate)
return BAN::Optional<uint32_t>();
@@ -115,6 +117,8 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
LockGuard _(m_lock);
if (data_block_index < 12)
{
if (m_inode.block[data_block_index] != 0)
@@ -152,6 +156,9 @@ namespace Kernel
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
{
ASSERT(mode().iflnk());
LockGuard _(m_lock);
if (m_inode.size < sizeof(m_inode.block))
{
BAN::String result;
@@ -168,6 +175,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
{
ASSERT(mode().iflnk());
LockGuard _(m_lock);
if (target.size() < sizeof(m_inode.block))
{
if (m_inode.size >= sizeof(m_inode.block))
@@ -194,10 +204,12 @@ namespace Kernel
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset))
return BAN::Error::from_errno(EOVERFLOW);
LockGuard _0(m_lock);
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= m_inode.size)
return 0;
ScopedSync _(*this);
ScopedSync _1(*this);
uint32_t count = buffer.size();
if (offset + buffer.size() > m_inode.size)
@@ -240,6 +252,8 @@ namespace Kernel
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset))
return BAN::Error::from_errno(EOVERFLOW);
LockGuard _0(m_lock);
if (m_inode.size < offset + buffer.size())
TRY(truncate_impl(offset + buffer.size()));
@@ -300,6 +314,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::truncate_impl(size_t new_size)
{
LockGuard _(m_lock);
if (m_inode.size == new_size)
return {};
@@ -320,6 +336,10 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::chmod_impl(mode_t mode)
{
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
// TODO: this could be atomic
LockGuard _(m_lock);
if (m_inode.mode == mode)
return {};
@@ -337,6 +357,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::chown_impl(uid_t uid, gid_t gid)
{
// TODO: this could be atomic
LockGuard _(m_lock);
if (m_inode.uid == uid && m_inode.gid == gid)
return {};
@@ -357,6 +380,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2])
{
// TODO: this could be atomic
LockGuard _(m_lock);
const uint32_t old_times[2] {
m_inode.atime,
m_inode.mtime,
@@ -379,6 +405,7 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
{
LockGuard _(m_lock);
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, false)); fs_block.has_value())
TRY(m_fs.sync_block(fs_block.value()));
@@ -389,6 +416,8 @@ namespace Kernel
{
ASSERT(block);
LockGuard _(m_lock);
if (depth == 0)
{
TRY(m_fs.release_block(block));
@@ -413,6 +442,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::cleanup_data_blocks()
{
LockGuard _(m_lock);
if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block))
goto done;
@@ -451,6 +482,8 @@ done:
ASSERT(mode().ifdir());
ASSERT(offset >= 0);
LockGuard _(m_lock);
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
return 0;
@@ -552,6 +585,8 @@ done:
{
ASSERT(this->mode().ifdir());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
@@ -586,6 +621,8 @@ done:
ASSERT(this->mode().ifdir());
ASSERT(Mode(mode).ifdir());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
@@ -619,6 +656,8 @@ done:
ASSERT(!inode->mode().ifdir());
ASSERT(&m_fs == inode->filesystem());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
@@ -636,16 +675,17 @@ done:
auto* ext2_parent = static_cast<Ext2Inode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(ext2_parent->m_mutex);
// FIXME: is this a possible deadlock?
LockGuard _0(ext2_parent->m_lock);
LockGuard _1(m_lock);
auto old_inode = TRY(ext2_parent->find_inode_impl(old_name));
auto* ext2_inode = static_cast<Ext2Inode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
if (auto find_result = find_inode_impl(new_name); find_result.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
if (find_result.error().get_error_code() != ENOENT)
return find_result.release_error();
}
else
{
@@ -667,6 +707,8 @@ done:
if (name.size() > 255)
return BAN::Error::from_errno(ENAMETOOLONG);
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL)
{
dwarnln("file creation to indexed directory not supported");
@@ -770,6 +812,8 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
// Confirm that this doesn't contain anything else than '.' or '..'
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
@@ -800,14 +844,17 @@ needs_new_block:
BAN::ErrorOr<void> Ext2Inode::cleanup_default_links()
{
ASSERT(mode().ifdir());
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL)
{
dwarnln("deletion of indexed directory is not supported");
return BAN::Error::from_errno(ENOTSUP);
}
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
@@ -857,14 +904,17 @@ needs_new_block:
BAN::ErrorOr<void> Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory)
{
ASSERT(mode().ifdir());
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL)
{
dwarnln("deletion from indexed directory is not supported");
return BAN::Error::from_errno(ENOTSUP);
}
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
const auto block_index = TRY(fs_block_of_data_block_index(i, false));
@@ -925,6 +975,8 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(inode_location.block, block_buffer));
LockGuard _(m_lock);
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
{
memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
@@ -940,6 +992,7 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
const auto block_index = TRY(fs_block_of_data_block_index(i, false));

View File

@@ -62,7 +62,6 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
{
LockGuard _(m_mutex);
if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
return find_inode_impl(name);
@@ -70,7 +69,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len)
{
LockGuard _(m_mutex);
if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
return list_next_inodes_impl(offset, list, list_len);
@@ -78,7 +76,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (Mode(mode).ifdir())
@@ -90,7 +87,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::create_directory(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (!Mode(mode).ifdir())
@@ -102,7 +98,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::link_inode(BAN::StringView name, BAN::RefPtr<Inode> inode)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (inode->mode().ifdir())
@@ -116,7 +111,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::rename_inode(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (!old_parent->mode().ifdir())
@@ -130,7 +124,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
{
LockGuard _(m_mutex);
if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (name == "."_sv || name == ".."_sv)
@@ -142,7 +135,6 @@ namespace Kernel
BAN::ErrorOr<BAN::String> Inode::link_target()
{
LockGuard _(m_mutex);
if (!mode().iflnk())
return BAN::Error::from_errno(EINVAL);
return link_target_impl();
@@ -150,7 +142,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::set_link_target(BAN::StringView target)
{
LockGuard _(m_mutex);
if (!mode().iflnk())
return BAN::Error::from_errno(EINVAL);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -160,7 +151,6 @@ namespace Kernel
BAN::ErrorOr<long> Inode::accept(sockaddr* address, socklen_t* address_len, int flags)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return accept_impl(address, address_len, flags);
@@ -168,7 +158,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::bind(const sockaddr* address, socklen_t address_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return bind_impl(address, address_len);
@@ -176,7 +165,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::connect(const sockaddr* address, socklen_t address_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return connect_impl(address, address_len);
@@ -184,7 +172,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::listen(int backlog)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return listen_impl(backlog);
@@ -192,7 +179,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::recvmsg(msghdr& message, int flags)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return recvmsg_impl(message, flags);
@@ -200,7 +186,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::sendmsg(const msghdr& message, int flags)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return sendmsg_impl(message, flags);
@@ -208,7 +193,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getsockname(sockaddr* address, socklen_t* address_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return getsockname_impl(address, address_len);
@@ -216,7 +200,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getpeername(sockaddr* address, socklen_t* address_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return getpeername_impl(address, address_len);
@@ -224,7 +207,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getsockopt(int level, int option, void* value, socklen_t* value_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return getsockopt_impl(level, option, value, value_len);
@@ -232,7 +214,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::setsockopt(int level, int option, const void* value, socklen_t value_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return setsockopt_impl(level, option, value, value_len);
@@ -240,7 +221,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
{
LockGuard _(m_mutex);
if (mode().ifdir())
return BAN::Error::from_errno(EISDIR);
return read_impl(offset, buffer);
@@ -248,7 +228,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::write(off_t offset, BAN::ConstByteSpan buffer)
{
LockGuard _(m_mutex);
if (mode().ifdir())
return BAN::Error::from_errno(EISDIR);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -258,7 +237,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::truncate(size_t size)
{
LockGuard _(m_mutex);
if (mode().ifdir())
return BAN::Error::from_errno(EISDIR);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -269,7 +247,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::chmod(mode_t mode)
{
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return chmod_impl(mode);
@@ -277,7 +254,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::chown(uid_t uid, gid_t gid)
{
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return chown_impl(uid, gid);
@@ -285,7 +261,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::utimens(const timespec times[2])
{
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return utimens_impl(times);
@@ -293,40 +268,32 @@ namespace Kernel
BAN::ErrorOr<void> Inode::fsync()
{
LockGuard _(m_mutex);
if (auto shared = m_shared_region.lock())
for (size_t i = 0; i < shared->pages.size(); i++)
shared->sync(i);
// TODO: should we sync shared data?
return fsync_impl();
}
bool Inode::can_read() const
{
LockGuard _(m_mutex);
return can_read_impl();
}
bool Inode::can_write() const
{
LockGuard _(m_mutex);
return can_write_impl();
}
bool Inode::has_error() const
{
LockGuard _(m_mutex);
return has_error_impl();
}
bool Inode::has_hungup() const
{
LockGuard _(m_mutex);
return has_hungup_impl();
}
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
{
LockGuard _(m_mutex);
return ioctl_impl(request, arg);
}

View File

@@ -73,6 +73,8 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{
LockGuard _(m_mutex);
while (m_buffer->empty())
{
if (m_writing_count == 0)
@@ -95,6 +97,8 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer)
{
LockGuard _(m_mutex);
while (m_buffer->full())
{
if (m_reading_count == 0)

View File

@@ -94,6 +94,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode)
{
// FIXME: make this atomic
ASSERT(!(new_mode & Inode::Mode::TYPE_MASK));
m_inode_info.mode &= Inode::Mode::TYPE_MASK;
m_inode_info.mode |= new_mode;
@@ -102,6 +103,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::chown_impl(uid_t new_uid, gid_t new_gid)
{
// FIXME: make this atomic
m_inode_info.uid = new_uid;
m_inode_info.gid = new_gid;
return {};
@@ -109,6 +111,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2])
{
// FIXME: make this atomic
if (times[0].tv_nsec != UTIME_OMIT)
m_inode_info.atime = times[0];
if (times[1].tv_nsec != UTIME_OMIT)
@@ -123,23 +126,24 @@ namespace Kernel
void TmpInode::free_all_blocks()
{
LockGuard _(m_lock);
if (mode().iflnk() && m_inode_info.size <= sizeof(TmpInodeInfo::block))
goto free_all_blocks_done;
for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++)
if (m_inode_info.block[i])
m_fs.free_block(m_inode_info.block[i]);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 0])
free_indirect_blocks(block, 1);
free_indirect_blocks_no_lock(block, 1);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 1])
free_indirect_blocks(block, 2);
free_indirect_blocks_no_lock(block, 2);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 2])
free_indirect_blocks(block, 3);
free_indirect_blocks_no_lock(block, 3);
free_all_blocks_done:
for (auto& block : m_inode_info.block)
block = 0;
}
void TmpInode::free_indirect_blocks(size_t block, uint32_t depth)
void TmpInode::free_indirect_blocks_no_lock(size_t block, uint32_t depth)
{
ASSERT(block != 0);
@@ -160,7 +164,7 @@ namespace Kernel
if (next_block == 0)
continue;
free_indirect_blocks(next_block, depth - 1);
free_indirect_blocks_no_lock(next_block, depth - 1);
}
m_fs.free_block(block);
@@ -168,6 +172,8 @@ namespace Kernel
BAN::Optional<size_t> TmpInode::block_index(size_t data_block_index)
{
LockGuard _(m_lock);
if (data_block_index < TmpInodeInfo::direct_block_count)
{
if (m_inode_info.block[data_block_index] == 0)
@@ -179,20 +185,20 @@ namespace Kernel
const size_t indices_per_block = blksize() / sizeof(size_t);
if (data_block_index < indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
data_block_index -= indices_per_block;
if (data_block_index < indices_per_block * indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
data_block_index -= indices_per_block * indices_per_block;
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
ASSERT_NOT_REACHED();
}
BAN::Optional<size_t> TmpInode::block_index_from_indirect(size_t block, size_t index, uint32_t depth)
BAN::Optional<size_t> TmpInode::block_index_from_indirect_no_lock(size_t block, size_t index, uint32_t depth)
{
if (block == 0)
return {};
@@ -215,11 +221,13 @@ namespace Kernel
if (depth == 1)
return next_block;
return block_index_from_indirect(next_block, index, depth - 1);
return block_index_from_indirect_no_lock(next_block, index, depth - 1);
}
BAN::ErrorOr<size_t> TmpInode::block_index_with_allocation(size_t data_block_index)
{
LockGuard _(m_lock);
if (data_block_index < TmpInodeInfo::direct_block_count)
{
if (m_inode_info.block[data_block_index] == 0)
@@ -234,20 +242,20 @@ namespace Kernel
const size_t indices_per_block = blksize() / sizeof(size_t);
if (data_block_index < indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
data_block_index -= indices_per_block;
if (data_block_index < indices_per_block * indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
data_block_index -= indices_per_block * indices_per_block;
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<size_t> TmpInode::block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth)
BAN::ErrorOr<size_t> TmpInode::block_index_from_indirect_with_allocation_no_lock(size_t& block, size_t index, uint32_t depth)
{
if (block == 0)
{
@@ -280,7 +288,7 @@ namespace Kernel
if (depth == 1)
return next_block;
return block_index_from_indirect_with_allocation(next_block, index, depth - 1);
return block_index_from_indirect_with_allocation_no_lock(next_block, index, depth - 1);
}
/* FILE INODE */
@@ -309,6 +317,8 @@ namespace Kernel
BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer)
{
LockGuard _(m_lock);
if (offset >= size() || out_buffer.size() == 0)
return 0;
@@ -339,7 +349,12 @@ namespace Kernel
BAN::ErrorOr<size_t> TmpFileInode::write_impl(off_t offset, BAN::ConstByteSpan in_buffer)
{
// FIXME: handle overflow
if (offset < 0)
return BAN::Error::from_errno(EINVAL);
if (BAN::Math::will_addition_overflow<size_t>(offset, in_buffer.size()))
return BAN::Error::from_errno(EOVERFLOW);
LockGuard _(m_lock);
if (offset + in_buffer.size() > (size_t)size())
TRY(truncate_impl(offset + in_buffer.size()));
@@ -370,6 +385,7 @@ namespace Kernel
{
// FIXME: if size is decreased, we should probably free
// unused blocks
// FIXME: make this atomic
m_inode_info.size = new_size;
return {};
@@ -427,6 +443,8 @@ namespace Kernel
BAN::ErrorOr<void> TmpSymlinkInode::set_link_target_impl(BAN::StringView new_target)
{
LockGuard _(m_lock);
free_all_blocks();
m_inode_info.size = 0;
@@ -455,6 +473,8 @@ namespace Kernel
BAN::ErrorOr<BAN::String> TmpSymlinkInode::link_target_impl()
{
LockGuard _(m_lock);
BAN::String result;
TRY(result.resize(size()));
@@ -522,7 +542,7 @@ namespace Kernel
{
}
BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink()
BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink_no_lock()
{
ino_t dot_ino = 0;
ino_t dotdot_ino = 0;
@@ -564,15 +584,15 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name)
{
ino_t result = 0;
LockGuard _(m_lock);
ino_t result = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name)
return BAN::Iteration::Continue;
result = entry.ino;
return BAN::Iteration::Break;
});
if (result == 0)
return BAN::Error::from_errno(ENOENT);
@@ -588,6 +608,8 @@ namespace Kernel
return BAN::Error::from_errno(ENOBUFS);
}
LockGuard _(m_lock);
auto block_index = this->block_index(data_block_index);
// if we reach a non-allocated block, it marks the end
@@ -664,6 +686,8 @@ namespace Kernel
ASSERT(!inode->mode().ifdir());
ASSERT(&m_fs == inode->filesystem());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
@@ -680,16 +704,17 @@ namespace Kernel
auto* tmp_parent = static_cast<TmpDirectoryInode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(tmp_parent->m_mutex);
// FIXME: is this a possible deadlock?
LockGuard _0(tmp_parent->m_lock);
LockGuard _1(m_lock);
auto old_inode = TRY(tmp_parent->find_inode_impl(old_name));
auto* tmp_inode = static_cast<TmpInode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
if (auto find_result = find_inode_impl(new_name); find_result.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
if (find_result.error().get_error_code() != ENOENT)
return find_result.release_error();
}
else
{
@@ -711,15 +736,15 @@ namespace Kernel
BAN::ErrorOr<void> TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup)
{
ino_t entry_ino = 0;
LockGuard _(m_lock);
ino_t entry_ino = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name)
return BAN::Iteration::Continue;
entry_ino = entry.ino;
return BAN::Iteration::Break;
});
if (entry_ino == 0)
return BAN::Error::from_errno(ENOENT);
@@ -728,7 +753,7 @@ namespace Kernel
ASSERT(inode->nlink() > 0);
if (cleanup)
TRY(inode->prepare_unlink());
TRY(inode->prepare_unlink_no_lock());
inode->m_inode_info.nlink--;
if (inode->nlink() == 0)
@@ -749,6 +774,8 @@ namespace Kernel
{
static constexpr size_t directory_entry_alignment = sizeof(TmpDirectoryEntry);
LockGuard _(m_lock);
auto find_result = find_inode_impl(name);
if (!find_result.is_error())
return BAN::Error::from_errno(EEXIST);

View File

@@ -1,5 +1,6 @@
#include <BAN/ScopeGuard.h>
#include <kernel/FS/USTARModule.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Timer/Timer.h>
#include <LibDEFLATE/Decompressor.h>