Kernel: Implement TmpFS Inode unlinking and deletion

This commit is contained in:
Bananymous 2023-11-06 21:14:39 +02:00
parent 3e33fc156b
commit b7771e95ac
4 changed files with 102 additions and 24 deletions

View File

@ -40,7 +40,9 @@ namespace Kernel
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; } virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino); BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino);
BAN::ErrorOr<void> add_to_cache(BAN::RefPtr<TmpInode>); BAN::ErrorOr<void> add_to_cache(BAN::RefPtr<TmpInode>);
void remove_from_cache(BAN::RefPtr<TmpInode>);
// FIXME: read_block and write_block should not require external buffer // FIXME: read_block and write_block should not require external buffer
// probably some wrapper like PageTable::with_fast_page could work? // probably some wrapper like PageTable::with_fast_page could work?

View File

@ -40,12 +40,14 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&); static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
~TmpInode();
protected: protected:
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
void sync(); void sync();
void free_all_blocks(); void free_all_blocks();
virtual BAN::ErrorOr<void> prepare_unlink() { return {}; };
BAN::Optional<size_t> block_index(size_t data_block_index); BAN::Optional<size_t> block_index(size_t data_block_index);
BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index); BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index);
@ -95,6 +97,9 @@ namespace Kernel
~TmpDirectoryInode(); ~TmpDirectoryInode();
protected:
virtual BAN::ErrorOr<void> prepare_unlink() override;
protected: protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final; virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final;

View File

@ -71,6 +71,12 @@ namespace Kernel
return {}; return {};
} }
void TmpFileSystem::remove_from_cache(BAN::RefPtr<TmpInode> inode)
{
ASSERT(m_inode_cache.contains(inode->ino()));
m_inode_cache.remove(inode->ino());
}
void TmpFileSystem::read_inode(ino_t ino, TmpInodeInfo& out) void TmpFileSystem::read_inode(ino_t ino, TmpInodeInfo& out)
{ {
auto inode_location = find_inode(ino); auto inode_location = find_inode(ino);
@ -98,6 +104,7 @@ namespace Kernel
ASSERT_EQ(paddr, 0); ASSERT_EQ(paddr, 0);
inode_info = {}; inode_info = {};
}); });
ASSERT(!m_inode_cache.contains(ino));
} }
BAN::ErrorOr<ino_t> TmpFileSystem::allocate_inode(const TmpInodeInfo& info) BAN::ErrorOr<ino_t> TmpFileSystem::allocate_inode(const TmpInodeInfo& info)
@ -142,7 +149,20 @@ namespace Kernel
void TmpFileSystem::free_block(size_t index) void TmpFileSystem::free_block(size_t index)
{ {
ASSERT_NOT_REACHED(); constexpr size_t addresses_per_page = PAGE_SIZE / sizeof(PageInfo);
const size_t index_of_page = (index - first_data_page) / addresses_per_page;
const size_t index_in_page = (index - first_data_page) % addresses_per_page;
paddr_t page_containing = find_indirect(m_data_pages, index_of_page, 2);
PageTable::with_fast_page(page_containing, [&] {
auto& page_info = PageTable::fast_page_as_sized<PageInfo>(index_in_page);
ASSERT(page_info.flags() & PageInfo::Flags::Present);
Heap::get().release_page(page_info.paddr());
page_info.set_paddr(0);
page_info.set_flags(0);
});
} }
BAN::ErrorOr<size_t> TmpFileSystem::allocate_block() BAN::ErrorOr<size_t> TmpFileSystem::allocate_block()

View File

@ -69,6 +69,17 @@ namespace Kernel
MUST(fs.add_to_cache(this)); MUST(fs.add_to_cache(this));
} }
TmpInode::~TmpInode()
{
if (nlink() > 0)
{
sync();
return;
}
free_all_blocks();
m_fs.delete_inode(ino());
}
void TmpInode::sync() void TmpInode::sync()
{ {
m_fs.write_inode(m_ino, m_inode_info); m_fs.write_inode(m_ino, m_inode_info);
@ -76,6 +87,12 @@ namespace Kernel
void TmpInode::free_all_blocks() void TmpInode::free_all_blocks()
{ {
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]);
m_inode_info.block[i] = 0;
}
for (auto block : m_inode_info.block) for (auto block : m_inode_info.block)
ASSERT(block == 0); ASSERT(block == 0);
} }
@ -125,13 +142,6 @@ namespace Kernel
TmpFileInode::~TmpFileInode() TmpFileInode::~TmpFileInode()
{ {
if (nlink() > 0)
{
sync();
return;
}
free_all_blocks();
m_fs.delete_inode(ino());
} }
BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer) BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer)
@ -247,13 +257,46 @@ namespace Kernel
TmpDirectoryInode::~TmpDirectoryInode() TmpDirectoryInode::~TmpDirectoryInode()
{ {
if (nlink() >= 2) }
BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink()
{
ino_t dot_ino = 0;
ino_t dotdot_ino = 0;
bool is_empty = true;
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() == "."sv)
dot_ino = entry.ino;
else if (entry.name_sv() == ".."sv)
dotdot_ino = entry.ino;
else
{
is_empty = false;
return BAN::Iteration::Break;
}
return BAN::Iteration::Continue;
});
if (!is_empty)
return BAN::Error::from_errno(ENOTEMPTY);
// FIXME: can these leak inodes?
if (dot_ino)
{ {
sync(); auto inode = TRY(m_fs.open_inode(dot_ino));
return; ASSERT(inode->nlink() > 0);
inode->m_inode_info.nlink--;
} }
free_all_blocks();
m_fs.delete_inode(ino()); if (dotdot_ino)
{
auto inode = TRY(m_fs.open_inode(dotdot_ino));
ASSERT(inode->nlink() > 0);
inode->m_inode_info.nlink--;
}
return {};
} }
BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name) BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name)
@ -335,36 +378,38 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView) BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name)
{ {
ino_t entry_ino = 0; ino_t entry_ino = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) { for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name) if (entry.name_sv() != name)
return BAN::Iteration::Continue; return BAN::Iteration::Continue;
// get ino of entry
entry_ino = entry.ino; entry_ino = entry.ino;
// invalidate the entry
entry.ino = 0;
entry.type = DT_UNKNOWN;
return BAN::Iteration::Break; return BAN::Iteration::Break;
}); });
if (entry_ino == 0) if (entry_ino == 0)
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
// FIXME: this should be able to fail auto inode = TRY(m_fs.open_inode(entry_ino));
auto inode = MUST(m_fs.open_inode(entry_ino));
ASSERT(inode->nlink() > 0); ASSERT(inode->nlink() > 0);
TRY(inode->prepare_unlink());
inode->m_inode_info.nlink--; inode->m_inode_info.nlink--;
if (inode->nlink() == 0 || (inode->mode().ifdir() && inode->nlink() <= 2)) if (inode->nlink() == 0)
m_fs.remove_from_cache(inode); m_fs.remove_from_cache(inode);
for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name)
return BAN::Iteration::Continue;
entry.ino = 0;
entry.type = DT_UNKNOWN;
return BAN::Iteration::Break;
});
return {}; return {};
} }
@ -372,6 +417,12 @@ namespace Kernel
{ {
static constexpr size_t directory_entry_alignment = 16; static constexpr size_t directory_entry_alignment = 16;
auto find_result = find_inode_impl(name);
if (!find_result.is_error())
return BAN::Error::from_errno(EEXIST);
if (find_result.error().get_error_code() != ENOENT)
return find_result.release_error();
size_t new_entry_size = sizeof(TmpDirectoryEntry) + name.size(); size_t new_entry_size = sizeof(TmpDirectoryEntry) + name.size();
if (auto rem = new_entry_size % directory_entry_alignment) if (auto rem = new_entry_size % directory_entry_alignment)
new_entry_size += directory_entry_alignment - rem; new_entry_size += directory_entry_alignment - rem;