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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user