Kernel: Implement TmpFS Inode unlinking and deletion
This commit is contained in:
parent
af330f7b8e
commit
a20f8607de
|
@ -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?
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
|
||||||
{
|
|
||||||
sync();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
free_all_blocks();
|
|
||||||
m_fs.delete_inode(ino());
|
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)
|
||||||
|
{
|
||||||
|
auto inode = TRY(m_fs.open_inode(dot_ino));
|
||||||
|
ASSERT(inode->nlink() > 0);
|
||||||
|
inode->m_inode_info.nlink--;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
Loading…
Reference in New Issue