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