forked from Bananymous/banan-os
				
			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; } | ||||
| 
 | ||||
| 		BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino); | ||||
| 
 | ||||
| 		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
 | ||||
| 		//        probably some wrapper like PageTable::with_fast_page could work?
 | ||||
|  |  | |||
|  | @ -40,12 +40,14 @@ namespace Kernel | |||
| 
 | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&); | ||||
| 		~TmpInode(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); | ||||
| 
 | ||||
| 		void sync(); | ||||
| 		void free_all_blocks(); | ||||
| 		virtual BAN::ErrorOr<void> prepare_unlink() { return {}; }; | ||||
| 
 | ||||
| 		BAN::Optional<size_t> block_index(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(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		virtual BAN::ErrorOr<void> prepare_unlink() override; | ||||
| 
 | ||||
| 	protected: | ||||
| 		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; | ||||
|  |  | |||
|  | @ -71,6 +71,12 @@ namespace Kernel | |||
| 		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) | ||||
| 	{ | ||||
| 		auto inode_location = find_inode(ino); | ||||
|  | @ -98,6 +104,7 @@ namespace Kernel | |||
| 				ASSERT_EQ(paddr, 0); | ||||
| 			inode_info = {}; | ||||
| 		}); | ||||
| 		ASSERT(!m_inode_cache.contains(ino)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<ino_t> TmpFileSystem::allocate_inode(const TmpInodeInfo& info) | ||||
|  | @ -142,7 +149,20 @@ namespace Kernel | |||
| 
 | ||||
| 	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() | ||||
|  |  | |||
|  | @ -69,6 +69,17 @@ namespace Kernel | |||
| 		MUST(fs.add_to_cache(this)); | ||||
| 	} | ||||
| 
 | ||||
| 	TmpInode::~TmpInode() | ||||
| 	{ | ||||
| 		if (nlink() > 0) | ||||
| 		{ | ||||
| 			sync(); | ||||
| 			return; | ||||
| 		} | ||||
| 		free_all_blocks(); | ||||
| 		m_fs.delete_inode(ino()); | ||||
| 	} | ||||
| 
 | ||||
| 	void TmpInode::sync() | ||||
| 	{ | ||||
| 		m_fs.write_inode(m_ino, m_inode_info); | ||||
|  | @ -76,6 +87,12 @@ namespace Kernel | |||
| 
 | ||||
| 	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) | ||||
| 			ASSERT(block == 0); | ||||
| 	} | ||||
|  | @ -125,13 +142,6 @@ namespace Kernel | |||
| 
 | ||||
| 	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) | ||||
|  | @ -247,13 +257,46 @@ namespace Kernel | |||
| 
 | ||||
| 	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(); | ||||
| 			return; | ||||
| 			auto inode = TRY(m_fs.open_inode(dot_ino)); | ||||
| 			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) | ||||
|  | @ -335,36 +378,38 @@ namespace Kernel | |||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView) | ||||
| 	BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name) | ||||
| 	{ | ||||
| 		ino_t entry_ino = 0; | ||||
| 
 | ||||
| 		for_each_valid_entry([&](TmpDirectoryEntry& entry) { | ||||
| 			if (entry.name_sv() != name) | ||||
| 				return BAN::Iteration::Continue; | ||||
| 
 | ||||
| 			// get ino of entry
 | ||||
| 			entry_ino = entry.ino; | ||||
| 
 | ||||
| 			// invalidate the entry
 | ||||
| 			entry.ino = 0; | ||||
| 			entry.type = DT_UNKNOWN; | ||||
| 
 | ||||
| 			return BAN::Iteration::Break; | ||||
| 		}); | ||||
| 
 | ||||
| 		if (entry_ino == 0) | ||||
| 			return BAN::Error::from_errno(ENOENT); | ||||
| 
 | ||||
| 		// FIXME: this should be able to fail
 | ||||
| 		auto inode = MUST(m_fs.open_inode(entry_ino)); | ||||
| 		auto inode = TRY(m_fs.open_inode(entry_ino)); | ||||
| 
 | ||||
| 		ASSERT(inode->nlink() > 0); | ||||
| 
 | ||||
| 		TRY(inode->prepare_unlink()); | ||||
| 		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); | ||||
| 
 | ||||
| 		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 {}; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -372,6 +417,12 @@ namespace Kernel | |||
| 	{ | ||||
| 		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(); | ||||
| 		if (auto rem = new_entry_size % directory_entry_alignment) | ||||
| 			new_entry_size += directory_entry_alignment - rem; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue