Kernel: Cleanup inode stat updating

Inode now handles stat upates itself and calls sync function to make
updates visible on the underlying filesystem
This commit is contained in:
2026-05-19 13:00:05 +03:00
parent a05fcdde8c
commit 1dc26d3c06
17 changed files with 240 additions and 259 deletions

View File

@@ -14,6 +14,25 @@ namespace Kernel
return BAN::RefPtr<Inode>(BAN::RefPtr<EventFD>::adopt(eventfd_ptr));
}
EventFD::EventFD(uint64_t initval, bool is_semaphore)
: m_is_semaphore(is_semaphore)
, m_value(initval)
{
m_ino = 0;
m_mode = Mode::IFCHR | Mode::IRUSR | Mode::IWUSR;
m_nlink = 0;
m_uid = 0;
m_gid = 0;
m_size = 0;
m_atime = {};
m_mtime = {};
m_ctime = {};
m_blksize = 8;
m_blocks = 0;
m_dev = 0;
m_rdev = 0;
}
BAN::ErrorOr<size_t> EventFD::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < sizeof(uint64_t))

View File

@@ -73,6 +73,22 @@ namespace Kernel
return &m_fs;
}
BAN::ErrorOr<void> Ext2Inode::sync_inode(SyncType)
{
RWLockRDGuard _(m_lock);
TRY(sync_inode_no_lock());
return {};
}
BAN::ErrorOr<void> Ext2Inode::sync_data()
{
RWLockRDGuard _(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_no_lock(i, false)); fs_block.has_value())
TRY(m_fs.sync_block(fs_block.value()));
return {};
}
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block_no_lock(uint32_t& block, uint32_t index, uint32_t depth, bool allocate)
{
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
@@ -195,7 +211,7 @@ namespace Kernel
memset(m_ext2_blocks.block, 0, sizeof(m_ext2_blocks.block));
memcpy(m_ext2_blocks.block, target.data(), target.size());
m_size = target.size();
TRY(sync_no_lock());
TRY(sync_inode_no_lock());
return {};
}
@@ -334,7 +350,7 @@ namespace Kernel
const auto old_size = static_cast<size_t>(m_size);
m_size = new_size;
if (auto ret = sync_no_lock(); ret.is_error())
if (auto ret = sync_inode_no_lock(); ret.is_error())
{
m_size = old_size;
return ret.release_error();
@@ -343,80 +359,6 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> Ext2Inode::chmod_impl(mode_t mode)
{
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
RWLockWRGuard _(m_lock);
if (m_mode == mode)
return {};
const auto old_mode = m_mode.load();
m_mode = (m_mode & Inode::Mode::TYPE_MASK) | mode;
if (auto ret = sync_no_lock(); ret.is_error())
{
m_mode = old_mode;
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Ext2Inode::chown_impl(uid_t uid, gid_t gid)
{
RWLockWRGuard _(m_lock);
if (m_uid == uid && m_gid == gid)
return {};
const auto old_uid = m_uid.load();
const auto old_gid = m_gid.load();
m_uid = uid;
m_gid = gid;
if (auto ret = sync_no_lock(); ret.is_error())
{
m_uid = old_uid;
m_gid = old_gid;
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2])
{
RWLockWRGuard _(m_lock);
const timespec old_times[2] {
m_atime,
m_mtime,
};
m_atime = times[0];
m_mtime = times[1];
if (auto ret = sync_no_lock(); ret.is_error())
{
m_atime = old_times[0];
m_mtime = old_times[1];
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
{
RWLockRDGuard _(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_no_lock(i, false)); fs_block.has_value())
TRY(m_fs.sync_block(fs_block.value()));
return {};
}
BAN::ErrorOr<void> Ext2Inode::cleanup_indirect_block_no_lock(uint32_t block, uint32_t depth)
{
ASSERT(block);
@@ -465,7 +407,7 @@ done:
// mark blocks as deleted
memset(m_ext2_blocks.block, 0x00, sizeof(m_ext2_blocks.block));
TRY(sync_no_lock());
TRY(sync_inode_no_lock());
return {};
}
@@ -745,7 +687,7 @@ done:
memcpy(new_entry.name, name.data(), name.size());
inode.m_nlink++;
TRY(inode.sync_no_lock());
TRY(inode.sync_inode_no_lock());
return {};
};
@@ -870,13 +812,13 @@ needs_new_block:
if (entry_name == "."_sv)
{
m_nlink--;
TRY(sync_no_lock());
TRY(sync_inode_no_lock());
}
else if (entry_name == ".."_sv)
{
auto parent = TRY(Ext2Inode::create(m_fs, entry.inode));
parent->m_nlink--;
TRY(parent->sync_no_lock());
TRY(parent->sync_inode_no_lock());
}
else
ASSERT_NOT_REACHED();
@@ -933,7 +875,7 @@ needs_new_block:
else
inode->m_nlink--;
TRY(sync_no_lock());
TRY(sync_inode_no_lock());
// NOTE: If this was the last link to inode we must
// remove it from inode cache to trigger cleanup
@@ -962,13 +904,9 @@ needs_new_block:
return {};
}
BAN::ErrorOr<void> Ext2Inode::sync_no_lock()
BAN::ErrorOr<void> Ext2Inode::sync_inode_no_lock()
{
auto inode_location = TRY(m_fs.locate_inode(ino()));
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(inode_location.block, block_buffer));
Ext2::Inode inode {
const Ext2::Inode inode {
.mode = static_cast<uint16_t>(m_mode),
.uid = static_cast<uint16_t>(m_uid),
.size = static_cast<uint32_t>(m_size),
@@ -986,8 +924,13 @@ needs_new_block:
.file_acl = m_og_file_acl,
.dir_acl = m_og_dir_acl,
.faddr = m_og_faddr,
.osd2 = m_og_osd2
.osd2 = m_og_osd2,
};
auto inode_location = TRY(m_fs.locate_inode(ino()));
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, &inode, sizeof(Ext2::Inode)))
{
memcpy(block_buffer.data() + inode_location.offset, &inode, sizeof(Ext2::Inode));

View File

@@ -246,50 +246,73 @@ namespace Kernel
BAN::ErrorOr<void> Inode::chmod(mode_t mode)
{
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return chmod_impl(mode);
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
mode |= m_mode & Inode::Mode::TYPE_MASK;
const auto old_mode = m_mode.exchange(mode);
if (auto ret = sync_inode(SyncType::Mode); ret.is_error())
{
m_mode.compare_exchange(mode, old_mode);
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Inode::chown(uid_t uid, gid_t gid)
{
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return chown_impl(uid, gid);
// TODO: unify uid and gid to a single atomic operation.
// this needs 64 bit atomic support from 32 bit target
const auto old_uid = m_uid.exchange(uid);
const auto old_gid = m_gid.exchange(gid);
if (auto ret = sync_inode(SyncType::UidGid); ret.is_error())
{
m_uid.compare_exchange(uid, old_uid);
m_gid.compare_exchange(gid, old_gid);
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Inode::utimens(const timespec times[2])
{
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return utimens_impl(times);
// TODO: make these atomic
const auto old_atime = m_atime;
const auto old_mtime = m_mtime;
m_atime = times[0];
m_mtime = times[1];
if (auto ret = sync_inode(SyncType::Times); ret.is_error())
{
m_atime = old_atime;
m_mtime = old_mtime;
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Inode::fsync()
{
// TODO: should we sync shared data?
return fsync_impl();
}
bool Inode::can_read() const
{
return can_read_impl();
}
bool Inode::can_write() const
{
return can_write_impl();
}
bool Inode::has_error() const
{
return has_error_impl();
}
bool Inode::has_hungup() const
{
return has_hungup_impl();
// TODO: should we sync MAP_SHARED data?
TRY(sync_inode(SyncType::General));
TRY(sync_data());
return {};
}
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)

View File

@@ -173,6 +173,44 @@ namespace Kernel
m_thread_blocker.unblock();
}
BAN::ErrorOr<void> Pipe::sync_inode(SyncType type)
{
if (!m_named_inode)
return {};
switch (type)
{
case SyncType::General:
break;
case SyncType::Mode:
TRY(m_named_inode->chmod(m_mode));
break;
case SyncType::UidGid:
TRY(m_named_inode->chown(m_uid, m_gid));
break;
case SyncType::Times:
const timespec times[] { m_atime, m_mtime };
TRY(m_named_inode->utimens(times));
break;
}
m_mode = m_named_inode->mode().mode;
m_uid = m_named_inode->uid();
m_gid = m_named_inode->gid();
m_atime = m_named_inode->atime();
m_mtime = m_named_inode->mtime();
m_ctime = m_named_inode->ctime();
return {};
}
BAN::ErrorOr<void> Pipe::sync_data()
{
return {};
}
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{
LockGuard _(m_mutex);
@@ -225,6 +263,10 @@ namespace Kernel
return to_copy;
}
BAN::ErrorOr<void> Pipe::truncate_impl(size_t)
{
return BAN::Error::from_errno(ENODEV);
}
BAN::ErrorOr<long> Pipe::ioctl_impl(int cmd, void* arg)
{

View File

@@ -92,39 +92,14 @@ namespace Kernel
{
if (nlink() > 0)
{
sync();
write_inode_to_fs();
return;
}
free_all_blocks();
m_fs.delete_inode(ino());
}
BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode)
{
// FIXME: make this atomic
ASSERT(!(new_mode & Inode::Mode::TYPE_MASK));
m_mode &= Inode::Mode::TYPE_MASK;
m_mode |= new_mode;
return {};
}
BAN::ErrorOr<void> TmpInode::chown_impl(uid_t new_uid, gid_t new_gid)
{
// FIXME: make this atomic
m_uid = new_uid;
m_gid = new_gid;
return {};
}
BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2])
{
// FIXME: make this atomic
m_atime = times[0];
m_mtime = times[1];
return {};
}
void TmpInode::sync()
void TmpInode::write_inode_to_fs()
{
TmpInodeInfo info = {
.mode = m_mode.load(),
@@ -141,6 +116,16 @@ namespace Kernel
m_fs.write_inode(m_ino, info);
}
BAN::ErrorOr<void> TmpInode::sync_inode(SyncType)
{
return {};
}
BAN::ErrorOr<void> TmpInode::sync_data()
{
return {};
}
void TmpInode::free_all_blocks()
{
LockGuard _(m_lock);