Kernel: start work on ram file system
This commit is contained in:
		
							parent
							
								
									6d93c1eb92
								
							
						
					
					
						commit
						f1089e2b8a
					
				|  | @ -21,6 +21,8 @@ set(KERNEL_SOURCES | |||
| 	kernel/FS/Ext2.cpp | ||||
| 	kernel/FS/Inode.cpp | ||||
| 	kernel/FS/Pipe.cpp | ||||
| 	kernel/FS/RamFS/FileSystem.cpp | ||||
| 	kernel/FS/RamFS/Inode.cpp | ||||
| 	kernel/FS/VirtualFileSystem.cpp | ||||
| 	kernel/Input/PS2Controller.cpp | ||||
| 	kernel/Input/PS2Keyboard.cpp | ||||
|  |  | |||
|  | @ -0,0 +1,40 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/HashMap.h> | ||||
| #include <kernel/FS/FileSystem.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 	 | ||||
| 	class RamInode; | ||||
| 
 | ||||
| 	class RamFileSystem final : public FileSystem | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<RamFileSystem*> create(size_t size, mode_t, uid_t, gid_t); | ||||
| 		~RamFileSystem() = default; | ||||
| 
 | ||||
| 		virtual BAN::RefPtr<Inode> root_inode() override { return m_inodes[m_root_inode]; } | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> add_inode(BAN::RefPtr<RamInode>); | ||||
| 		BAN::ErrorOr<BAN::RefPtr<RamInode>> get_inode(ino_t); | ||||
| 
 | ||||
| 		blksize_t blksize() const { return m_blksize; } | ||||
| 		ino_t next_ino() { return m_next_ino++; } | ||||
| 
 | ||||
| 	private: | ||||
| 		RamFileSystem() = default; | ||||
| 
 | ||||
| 	private: | ||||
| 		SpinLock m_lock; | ||||
| 		size_t m_size { 0 }; | ||||
| 
 | ||||
| 		BAN::HashMap<ino_t, BAN::RefPtr<RamInode>> m_inodes; | ||||
| 		ino_t m_root_inode; | ||||
| 
 | ||||
| 		const blksize_t m_blksize = PAGE_SIZE; | ||||
| 		ino_t m_next_ino { 1 }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,95 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/FS/Inode.h> | ||||
| 
 | ||||
| #include <limits.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class RamFileSystem; | ||||
| 
 | ||||
| 	class RamInode : public Inode | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual ~RamInode() = default; | ||||
| 	 | ||||
| 		virtual ino_t		ino()		const override { return m_inode_info.ino; } | ||||
| 		virtual Mode		mode()		const override { return { m_inode_info.mode }; } | ||||
| 		virtual nlink_t		nlink()		const override { return m_inode_info.nlink; } | ||||
| 		virtual uid_t		uid()		const override { return m_inode_info.uid; } | ||||
| 		virtual gid_t		gid()		const override { return m_inode_info.gid; } | ||||
| 		virtual off_t		size()		const override { return m_inode_info.size; } | ||||
| 		virtual timespec	atime()		const override { return m_inode_info.atime; } | ||||
| 		virtual timespec	mtime()		const override { return m_inode_info.mtime; } | ||||
| 		virtual timespec	ctime()		const override { return m_inode_info.ctime; } | ||||
| 		virtual blksize_t	blksize()	const override { return m_inode_info.blksize; } | ||||
| 		virtual blkcnt_t	blocks()	const override { return m_inode_info.blocks; } | ||||
| 		virtual dev_t		dev()		const override { return m_inode_info.dev; } | ||||
| 		virtual dev_t		rdev()		const override { return m_inode_info.rdev; } | ||||
| 
 | ||||
| 		virtual BAN::StringView name() const override { ASSERT_NOT_REACHED(); } | ||||
| 
 | ||||
| 		void add_link() { m_inode_info.nlink++; } | ||||
| 
 | ||||
| 	protected: | ||||
| 		RamInode(RamFileSystem& fs, mode_t, uid_t, gid_t); | ||||
| 		static BAN::ErrorOr<BAN::RefPtr<RamInode>> create(RamFileSystem&, mode_t, uid_t, gid_t); | ||||
| 
 | ||||
| 	protected: | ||||
| 		struct FullInodeInfo | ||||
| 		{ | ||||
| 			ino_t		ino; | ||||
| 			mode_t		mode; | ||||
| 			nlink_t		nlink; | ||||
| 			uid_t		uid; | ||||
| 			gid_t		gid; | ||||
| 			off_t		size; | ||||
| 			timespec	atime; | ||||
| 			timespec	mtime; | ||||
| 			timespec	ctime; | ||||
| 			blksize_t	blksize; | ||||
| 			blkcnt_t	blocks; | ||||
| 			dev_t		dev; | ||||
| 			dev_t		rdev; | ||||
| 		}; | ||||
| 
 | ||||
| 	protected: | ||||
| 		RamFileSystem& m_fs; | ||||
| 		FullInodeInfo m_inode_info; | ||||
| 
 | ||||
| 		BAN::Vector<uint8_t> m_data; | ||||
| 
 | ||||
| 		friend class RamFileSystem; | ||||
| 	}; | ||||
| 
 | ||||
| 	class RamDirectoryInode final : public RamInode | ||||
| 	{ | ||||
| 	public: | ||||
| 		~RamDirectoryInode() = default; | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<BAN::RefPtr<Inode>> directory_find_inode(BAN::StringView) override; | ||||
| 		virtual BAN::ErrorOr<void> directory_read_next_entries(off_t, DirectoryEntryList*, size_t) override; | ||||
| 		virtual BAN::ErrorOr<void> create_file(BAN::StringView, mode_t)	override; | ||||
| 
 | ||||
| 	private: | ||||
| 		RamDirectoryInode(RamFileSystem&, ino_t parent, mode_t, uid_t, gid_t); | ||||
| 		static BAN::ErrorOr<BAN::RefPtr<RamDirectoryInode>> create(RamFileSystem&, ino_t parent, mode_t, uid_t, gid_t); | ||||
| 	 | ||||
| 	private: | ||||
| 		static constexpr size_t m_name_max = NAME_MAX; | ||||
| 		struct Entry | ||||
| 		{ | ||||
| 			char name[m_name_max + 1]; | ||||
| 			size_t name_len = 0; | ||||
| 			ino_t ino; | ||||
| 		}; | ||||
| 
 | ||||
| 	private: | ||||
| 		BAN::Vector<Entry> m_entries; | ||||
| 		ino_t m_parent; | ||||
| 
 | ||||
| 		friend class RamFileSystem; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,45 @@ | |||
| #include <BAN/ScopeGuard.h> | ||||
| #include <kernel/FS/RamFS/FileSystem.h> | ||||
| #include <kernel/FS/RamFS/Inode.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/RTC.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	BAN::ErrorOr<RamFileSystem*> RamFileSystem::create(size_t size, mode_t mode, uid_t uid, gid_t gid) | ||||
| 	{ | ||||
| 		auto* ramfs = new RamFileSystem; | ||||
| 		if (ramfs == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		ramfs->m_size = size; | ||||
| 
 | ||||
| 		BAN::ScopeGuard deleter([ramfs] { delete ramfs; }); | ||||
| 
 | ||||
| 		auto root_inode = TRY(RamDirectoryInode::create(*ramfs, 0, mode, uid, gid)); | ||||
| 		TRY(ramfs->add_inode(root_inode)); | ||||
| 		ramfs->m_root_inode = root_inode->ino(); | ||||
| 
 | ||||
| 		deleter.disable(); | ||||
| 
 | ||||
| 		return ramfs; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> RamFileSystem::add_inode(BAN::RefPtr<RamInode> inode) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		if (m_inodes.contains(inode->ino())) | ||||
| 			return BAN::Error::from_errno(EEXIST); | ||||
| 		TRY(m_inodes.insert(inode->ino(), inode)); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<RamInode>> RamFileSystem::get_inode(ino_t ino) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		if (!m_inodes.contains(ino)) | ||||
| 			return BAN::Error::from_errno(ENOENT); | ||||
| 		return m_inodes[ino]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,161 @@ | |||
| #include <kernel/FS/RamFS/FileSystem.h> | ||||
| #include <kernel/FS/RamFS/Inode.h> | ||||
| #include <kernel/RTC.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 | ||||
| 		RAM INODE | ||||
| 
 | ||||
| 	*/ | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<RamInode>> RamInode::create(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) | ||||
| 	{ | ||||
| 		ASSERT(Mode{ mode }.ifreg()); | ||||
| 		auto* ram_inode = new RamInode(fs, mode, uid, gid); | ||||
| 		if (ram_inode == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<RamInode>::adopt(ram_inode); | ||||
| 	} | ||||
| 
 | ||||
| 	RamInode::RamInode(RamFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) | ||||
| 			: m_fs(fs) | ||||
| 	{ | ||||
| 		uint64_t current_unix_time = BAN::to_unix_time(RTC::get_current_time()); | ||||
| 		timespec current_timespec; | ||||
| 		current_timespec.tv_sec = current_unix_time; | ||||
| 		current_timespec.tv_nsec = 0; | ||||
| 
 | ||||
| 		m_inode_info.ino = fs.next_ino(); | ||||
| 		m_inode_info.mode = mode; | ||||
| 		m_inode_info.nlink = 1; | ||||
| 		m_inode_info.uid = uid; | ||||
| 		m_inode_info.gid = gid; | ||||
| 		m_inode_info.size = 0; | ||||
| 		m_inode_info.atime = current_timespec; | ||||
| 		m_inode_info.mtime = current_timespec; | ||||
| 		m_inode_info.ctime = current_timespec; | ||||
| 		m_inode_info.blksize = fs.blksize(); | ||||
| 		m_inode_info.blocks = 0; | ||||
| 		m_inode_info.dev = 0; | ||||
| 		m_inode_info.rdev = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 | ||||
| 		RAM DIRECTORY INODE | ||||
| 
 | ||||
| 	*/ | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<RamDirectoryInode>> RamDirectoryInode::create(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid) | ||||
| 	{ | ||||
| 		ASSERT(Mode{ mode }.ifdir()); | ||||
| 		auto* ram_inode = new RamDirectoryInode(fs, parent, mode, uid, gid); | ||||
| 		if (ram_inode == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<RamDirectoryInode>::adopt(ram_inode); | ||||
| 	} | ||||
| 
 | ||||
| 	RamDirectoryInode::RamDirectoryInode(RamFileSystem& fs, ino_t parent, mode_t mode, uid_t uid, gid_t gid) | ||||
| 		: RamInode(fs, mode, uid, gid) | ||||
| 	{ | ||||
| 		// "." links to this
 | ||||
| 		m_inode_info.nlink++; | ||||
| 
 | ||||
| 		// ".." links to this, if there is no parent
 | ||||
| 		if (parent == 0) | ||||
| 		{ | ||||
| 			m_inode_info.nlink++; | ||||
| 			m_parent = ino(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			MUST(fs.get_inode(parent))->add_link(); | ||||
| 			m_parent = parent; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<Inode>> RamDirectoryInode::directory_find_inode(BAN::StringView name) | ||||
| 	{ | ||||
| 		if (name == "."sv) | ||||
| 		{ | ||||
| 			BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(ino())); | ||||
| 			return inode; | ||||
| 		} | ||||
| 
 | ||||
| 		if (name == ".."sv) | ||||
| 		{ | ||||
| 			BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(m_parent)); | ||||
| 			return inode; | ||||
| 		} | ||||
| 
 | ||||
| 		for (const auto& entry : m_entries) | ||||
| 		{ | ||||
| 			if (name == entry.name) | ||||
| 			{ | ||||
| 				BAN::RefPtr<Inode> inode = TRY(m_fs.get_inode(entry.ino)); | ||||
| 				return inode; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		sizeof(Entry); | ||||
| 
 | ||||
| 		return BAN::Error::from_errno(ENOENT); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> RamDirectoryInode::directory_read_next_entries(off_t offset, DirectoryEntryList* list, size_t list_size) | ||||
| 	{ | ||||
| 		// TODO: don't require memory for all entries on single call
 | ||||
| 		if (offset != 0) | ||||
| 		{ | ||||
| 			list->entry_count = 0; | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		size_t needed_size = sizeof(DirectoryEntryList); | ||||
| 		needed_size += sizeof(DirectoryEntry) + 2; // "."
 | ||||
| 		needed_size += sizeof(DirectoryEntry) + 3; // ".."
 | ||||
| 		for (auto& entry : m_entries) | ||||
| 			needed_size += sizeof(DirectoryEntry) + entry.name_len + 1; | ||||
| 		if (needed_size > list_size) | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 
 | ||||
| 		DirectoryEntry* ptr = list->array; | ||||
| 
 | ||||
| 		// "."
 | ||||
| 		{ | ||||
| 			ptr->dirent.d_ino = ino(); | ||||
| 			ptr->rec_len = sizeof(DirectoryEntry) + 2; | ||||
| 			strcpy(ptr->dirent.d_name, "."); | ||||
| 			ptr = ptr->next(); | ||||
| 		} | ||||
| 
 | ||||
| 		// ".."
 | ||||
| 		{ | ||||
| 			ptr->dirent.d_ino = m_parent; | ||||
| 			ptr->rec_len = sizeof(DirectoryEntry) + 3; | ||||
| 			strcpy(ptr->dirent.d_name, ".."); | ||||
| 			ptr = ptr->next(); | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto& entry : m_entries) | ||||
| 		{ | ||||
| 			ptr->dirent.d_ino = entry.ino; | ||||
| 			ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1; | ||||
| 			strcpy(ptr->dirent.d_name, entry.name); | ||||
| 			ptr = ptr->next(); | ||||
| 		} | ||||
| 
 | ||||
| 		list->entry_count = m_entries.size() + 2; | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> RamDirectoryInode::create_file(BAN::StringView, mode_t) | ||||
| 	{ | ||||
| 		ASSERT_NOT_REACHED(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -2,6 +2,8 @@ | |||
| #include <BAN/StringView.h> | ||||
| #include <kernel/DeviceManager.h> | ||||
| #include <kernel/FS/Ext2.h> | ||||
| #include <kernel/FS/RamFS/FileSystem.h> | ||||
| #include <kernel/FS/RamFS/Inode.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <fcntl.h> | ||||
|  | @ -23,8 +25,17 @@ namespace Kernel | |||
| 		auto partition_inode = MUST(DeviceManager::get().directory_find_inode(root)); | ||||
| 		s_instance->m_root_fs = MUST(Ext2FS::create(*(Partition*)partition_inode.ptr())); | ||||
| 
 | ||||
| 		Credentials root_creds { 0, 0, 0, 0 }; | ||||
| 
 | ||||
| 		DeviceManager::get().set_blksize(s_instance->m_root_fs->root_inode()->blksize()); | ||||
| 		MUST(s_instance->mount({ 0, 0, 0, 0 }, &DeviceManager::get(), "/dev")); | ||||
| 		MUST(s_instance->mount(root_creds, &DeviceManager::get(), "/dev")); | ||||
| 
 | ||||
| 		mode_t tmpfs_mode = Inode::Mode::IFDIR | ||||
| 			 | Inode::Mode::IRUSR | Inode::Mode::IWUSR | Inode::Mode::IXUSR | ||||
| 			 | Inode::Mode::IRGRP | Inode::Mode::IWGRP | Inode::Mode::IXGRP | ||||
| 			 | Inode::Mode::IROTH | Inode::Mode::IWOTH | Inode::Mode::IXOTH; | ||||
| 		auto* tmpfs = MUST(RamFileSystem::create(1024 * 1024, tmpfs_mode, 0, 0)); | ||||
| 		MUST(s_instance->mount(root_creds, tmpfs, "/tmp")); | ||||
| 	} | ||||
| 	 | ||||
| 	VirtualFileSystem& VirtualFileSystem::get() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue