mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 18:22:45 +00:00 
			
		
		
		
	Get rid of Vnode concept.
We already have an abstraction between Process and Inode/CharacterDevice/FIFO and it's called FileDescriptor. :^)
This commit is contained in:
		
							parent
							
								
									310a5f4199
								
							
						
					
					
						commit
						b46ae2bf09
					
				
					 15 changed files with 204 additions and 376 deletions
				
			
		|  | @ -263,14 +263,14 @@ bool MemoryManager::copy_on_write(Process& process, Region& region, unsigned pag | |||
| bool Region::page_in(PageDirectory& page_directory) | ||||
| { | ||||
|     ASSERT(!vmo().is_anonymous()); | ||||
|     ASSERT(vmo().vnode()); | ||||
|     ASSERT(vmo().inode()); | ||||
| #ifdef MM_DEBUG | ||||
|     dbgprintf("MM: page_in %u pages\n", page_count()); | ||||
| #endif | ||||
|     for (size_t i = 0; i < page_count(); ++i) { | ||||
|         auto& vmo_page = vmo().physical_pages()[first_page_index() + i]; | ||||
|         if (vmo_page.is_null()) { | ||||
|             bool success = MM.page_in_from_vnode(page_directory, *this, i); | ||||
|             bool success = MM.page_in_from_inode(page_directory, *this, i); | ||||
|             if (!success) | ||||
|                 return false; | ||||
|         } | ||||
|  | @ -279,29 +279,28 @@ bool Region::page_in(PageDirectory& page_directory) | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool MemoryManager::page_in_from_vnode(PageDirectory& page_directory, Region& region, unsigned page_index_in_region) | ||||
| bool MemoryManager::page_in_from_inode(PageDirectory& page_directory, Region& region, unsigned page_index_in_region) | ||||
| { | ||||
|     auto& vmo = region.vmo(); | ||||
|     ASSERT(!vmo.is_anonymous()); | ||||
|     ASSERT(vmo.vnode()); | ||||
|     auto& vnode = *vmo.vnode(); | ||||
|     ASSERT(vmo.inode()); | ||||
|     auto& inode = *vmo.inode(); | ||||
|     auto& vmo_page = vmo.physical_pages()[region.first_page_index() + page_index_in_region]; | ||||
|     ASSERT(vmo_page.is_null()); | ||||
|     vmo_page = allocate_physical_page(); | ||||
|     if (vmo_page.is_null()) { | ||||
|         kprintf("MM: page_in_from_vnode was unable to allocate a physical page\n"); | ||||
|         kprintf("MM: page_in_from_inode was unable to allocate a physical page\n"); | ||||
|         return false; | ||||
|     } | ||||
|     remap_region_page(page_directory, region, page_index_in_region, true); | ||||
|     byte* dest_ptr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE).asPtr(); | ||||
| #ifdef MM_DEBUG | ||||
|     dbgprintf("MM: page_in_from_vnode ready to read from vnode, will write to L%x!\n", dest_ptr); | ||||
|     dbgprintf("MM: page_in_from_inode ready to read from inode, will write to L%x!\n", dest_ptr); | ||||
| #endif | ||||
|     sti(); // Oh god here we go...
 | ||||
|     ASSERT(vnode.core_inode()); | ||||
|     auto nread = vnode.core_inode()->read_bytes(vmo.vnode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr); | ||||
|     auto nread = inode.read_bytes(vmo.inode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr); | ||||
|     if (nread < 0) { | ||||
|         kprintf("MM: page_in_from_vnode had error (%d) while reading!\n", nread); | ||||
|         kprintf("MM: page_in_from_inode had error (%d) while reading!\n", nread); | ||||
|         return false; | ||||
|     } | ||||
|     if (nread < PAGE_SIZE) { | ||||
|  | @ -326,9 +325,9 @@ PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault) | |||
|     } | ||||
|     auto page_index_in_region = region->page_index_from_address(fault.laddr()); | ||||
|     if (fault.is_not_present()) { | ||||
|         if (region->vmo().vnode()) { | ||||
|             dbgprintf("NP(vnode) fault in Region{%p}[%u]\n", region, page_index_in_region); | ||||
|             page_in_from_vnode(*current->m_page_directory, *region, page_index_in_region); | ||||
|         if (region->vmo().inode()) { | ||||
|             dbgprintf("NP(inode) fault in Region{%p}[%u]\n", region, page_index_in_region); | ||||
|             page_in_from_inode(*current->m_page_directory, *region, page_index_in_region); | ||||
|             return PageFaultResponse::Continue; | ||||
|         } else { | ||||
|             dbgprintf("NP(zero) fault in Region{%p}[%u]\n", region, page_index_in_region); | ||||
|  | @ -589,10 +588,10 @@ Region::Region(LinearAddress a, size_t s, String&& n, bool r, bool w, bool cow) | |||
|     MM.register_region(*this); | ||||
| } | ||||
| 
 | ||||
| Region::Region(LinearAddress a, size_t s, RetainPtr<Vnode>&& vnode, String&& n, bool r, bool w) | ||||
| Region::Region(LinearAddress a, size_t s, RetainPtr<Inode>&& inode, String&& n, bool r, bool w) | ||||
|     : linearAddress(a) | ||||
|     , size(s) | ||||
|     , m_vmo(VMObject::create_file_backed(move(vnode), s)) | ||||
|     , m_vmo(VMObject::create_file_backed(move(inode), s)) | ||||
|     , name(move(n)) | ||||
|     , is_readable(r) | ||||
|     , is_writable(w) | ||||
|  | @ -639,14 +638,14 @@ void PhysicalPage::return_to_freelist() | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| RetainPtr<VMObject> VMObject::create_file_backed(RetainPtr<Vnode>&& vnode, size_t size) | ||||
| RetainPtr<VMObject> VMObject::create_file_backed(RetainPtr<Inode>&& inode, size_t size) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     if (vnode->vmo()) | ||||
|         return static_cast<VMObject*>(vnode->vmo()); | ||||
|     if (inode->vmo()) | ||||
|         return static_cast<VMObject*>(inode->vmo()); | ||||
|     size = ceilDiv(size, PAGE_SIZE) * PAGE_SIZE; | ||||
|     auto vmo = adopt(*new VMObject(move(vnode), size)); | ||||
|     vmo->vnode()->set_vmo(vmo.ptr()); | ||||
|     auto vmo = adopt(*new VMObject(move(inode), size)); | ||||
|     vmo->inode()->set_vmo(vmo.ptr()); | ||||
|     return vmo; | ||||
| } | ||||
| 
 | ||||
|  | @ -670,9 +669,9 @@ RetainPtr<VMObject> VMObject::clone() | |||
| VMObject::VMObject(VMObject& other) | ||||
|     : m_name(other.m_name) | ||||
|     , m_anonymous(other.m_anonymous) | ||||
|     , m_vnode_offset(other.m_vnode_offset) | ||||
|     , m_inode_offset(other.m_inode_offset) | ||||
|     , m_size(other.m_size) | ||||
|     , m_vnode(other.m_vnode) | ||||
|     , m_inode(other.m_inode) | ||||
|     , m_physical_pages(other.m_physical_pages) | ||||
| { | ||||
|     MM.register_vmo(*this); | ||||
|  | @ -698,9 +697,9 @@ VMObject::VMObject(PhysicalAddress paddr, size_t size) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| VMObject::VMObject(RetainPtr<Vnode>&& vnode, size_t size) | ||||
| VMObject::VMObject(RetainPtr<Inode>&& inode, size_t size) | ||||
|     : m_size(size) | ||||
|     , m_vnode(move(vnode)) | ||||
|     , m_inode(move(inode)) | ||||
| { | ||||
|     m_physical_pages.resize(page_count()); | ||||
|     MM.register_vmo(*this); | ||||
|  | @ -708,9 +707,9 @@ VMObject::VMObject(RetainPtr<Vnode>&& vnode, size_t size) | |||
| 
 | ||||
| VMObject::~VMObject() | ||||
| { | ||||
|     if (m_vnode) { | ||||
|         ASSERT(m_vnode->vmo() == this); | ||||
|         m_vnode->set_vmo(nullptr); | ||||
|     if (m_inode) { | ||||
|         ASSERT(m_inode->vmo() == this); | ||||
|         m_inode->set_vmo(nullptr); | ||||
|     } | ||||
|     MM.unregister_vmo(*this); | ||||
| } | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ private: | |||
| 
 | ||||
| class VMObject : public Retainable<VMObject> { | ||||
| public: | ||||
|     static RetainPtr<VMObject> create_file_backed(RetainPtr<Vnode>&&, size_t); | ||||
|     static RetainPtr<VMObject> create_file_backed(RetainPtr<Inode>&&, size_t); | ||||
|     static RetainPtr<VMObject> create_anonymous(size_t); | ||||
|     static RetainPtr<VMObject> create_framebuffer_wrapper(PhysicalAddress, size_t); | ||||
|     RetainPtr<VMObject> clone(); | ||||
|  | @ -82,9 +82,9 @@ public: | |||
|     ~VMObject(); | ||||
|     bool is_anonymous() const { return m_anonymous; } | ||||
| 
 | ||||
|     Vnode* vnode() { return m_vnode.ptr(); } | ||||
|     const Vnode* vnode() const { return m_vnode.ptr(); } | ||||
|     size_t vnode_offset() const { return m_vnode_offset; } | ||||
|     Inode* inode() { return m_inode.ptr(); } | ||||
|     const Inode* inode() const { return m_inode.ptr(); } | ||||
|     size_t inode_offset() const { return m_inode_offset; } | ||||
| 
 | ||||
|     String name() const { return m_name; } | ||||
|     void set_name(const String& name) { m_name = name; } | ||||
|  | @ -94,15 +94,15 @@ public: | |||
|     Vector<RetainPtr<PhysicalPage>>& physical_pages() { return m_physical_pages; } | ||||
| 
 | ||||
| private: | ||||
|     VMObject(RetainPtr<Vnode>&&, size_t); | ||||
|     VMObject(RetainPtr<Inode>&&, size_t); | ||||
|     explicit VMObject(VMObject&); | ||||
|     explicit VMObject(size_t); | ||||
|     VMObject(PhysicalAddress, size_t); | ||||
|     String m_name; | ||||
|     bool m_anonymous { false }; | ||||
|     Unix::off_t m_vnode_offset { 0 }; | ||||
|     Unix::off_t m_inode_offset { 0 }; | ||||
|     size_t m_size { 0 }; | ||||
|     RetainPtr<Vnode> m_vnode; | ||||
|     RetainPtr<Inode> m_inode; | ||||
|     Vector<RetainPtr<PhysicalPage>> m_physical_pages; | ||||
| }; | ||||
| 
 | ||||
|  | @ -110,7 +110,7 @@ class Region : public Retainable<Region> { | |||
| public: | ||||
|     Region(LinearAddress, size_t, String&&, bool r, bool w, bool cow = false); | ||||
|     Region(LinearAddress, size_t, RetainPtr<VMObject>&&, size_t offset_in_vmo, String&&, bool r, bool w, bool cow = false); | ||||
|     Region(LinearAddress, size_t, RetainPtr<Vnode>&&, String&&, bool r, bool w); | ||||
|     Region(LinearAddress, size_t, RetainPtr<Inode>&&, String&&, bool r, bool w); | ||||
|     ~Region(); | ||||
| 
 | ||||
|     const VMObject& vmo() const { return *m_vmo; } | ||||
|  | @ -217,7 +217,7 @@ private: | |||
|     static Region* region_from_laddr(Process&, LinearAddress); | ||||
| 
 | ||||
|     bool copy_on_write(Process&, Region&, unsigned page_index_in_region); | ||||
|     bool page_in_from_vnode(PageDirectory&, Region&, unsigned page_index_in_region); | ||||
|     bool page_in_from_inode(PageDirectory&, Region&, unsigned page_index_in_region); | ||||
|     bool zero_page(PageDirectory&, Region& region, unsigned page_index_in_region); | ||||
| 
 | ||||
|     byte* quickmap_page(PhysicalPage&); | ||||
|  |  | |||
|  | @ -354,29 +354,16 @@ ByteBuffer procfs$summary() | |||
|     return buffer; | ||||
| } | ||||
| 
 | ||||
| ByteBuffer procfs$vnodes() | ||||
| ByteBuffer procfs$inodes() | ||||
| { | ||||
|     extern HashTable<Inode*>& all_inodes(); | ||||
|     auto& vfs = VFS::the(); | ||||
|     auto buffer = ByteBuffer::create_uninitialized(vfs.m_max_vnode_count * 256); | ||||
|     auto buffer = ByteBuffer::create_uninitialized(all_inodes().size() * 256); | ||||
|     char* ptr = (char*)buffer.pointer(); | ||||
|     for (size_t i = 0; i < vfs.m_max_vnode_count; ++i) { | ||||
|         auto& vnode = vfs.m_nodes[i]; | ||||
|         // FIXME: Retain the vnode while inspecting it.
 | ||||
|         if (!vnode.inUse()) | ||||
|             continue; | ||||
|         String path; | ||||
|         if (vnode.core_inode()) | ||||
|             path = vfs.absolute_path(*vnode.core_inode()); | ||||
|         if (path.is_empty()) { | ||||
|             if (auto* dev = vnode.characterDevice()) { | ||||
|                 if (dev->is_tty()) | ||||
|                     path = static_cast<const TTY*>(dev)->tty_name(); | ||||
|             } | ||||
|         } | ||||
|         ptr += ksprintf(ptr, "vnode %03u: %02u:%08u (%u) %s", i, vnode.inode.fsid(), vnode.inode.index(), vnode.retain_count(), path.characters()); | ||||
|         if (vnode.characterDevice()) | ||||
|             ptr += ksprintf(ptr, " (chardev: %p)", vnode.characterDevice()); | ||||
|         ptr += ksprintf(ptr, "\n"); | ||||
|     for (auto it : all_inodes()) { | ||||
|         RetainPtr<Inode> inode = *it; | ||||
|         String path = vfs.absolute_path(*inode); | ||||
|         ptr += ksprintf(ptr, "Inode{K%x} %02u:%08u (%u) %s\n", inode.ptr(), inode->fsid(), inode->index(), inode->retain_count(), path.characters()); | ||||
|     } | ||||
|     *ptr = '\0'; | ||||
|     buffer.trim(ptr - (char*)buffer.pointer()); | ||||
|  | @ -392,7 +379,7 @@ bool ProcFS::initialize() | |||
|     add_file(create_generated_file("kmalloc", procfs$kmalloc)); | ||||
|     add_file(create_generated_file("summary", procfs$summary)); | ||||
|     add_file(create_generated_file("cpuinfo", procfs$cpuinfo)); | ||||
|     add_file(create_generated_file("vnodes", procfs$vnodes)); | ||||
|     add_file(create_generated_file("inodes", procfs$inodes)); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -85,9 +85,8 @@ Region* Process::allocate_region(LinearAddress laddr, size_t size, String&& name | |||
|     return m_regions.last().ptr(); | ||||
| } | ||||
| 
 | ||||
| Region* Process::allocate_file_backed_region(LinearAddress laddr, size_t size, RetainPtr<Vnode>&& vnode, String&& name, bool is_readable, bool is_writable) | ||||
| Region* Process::allocate_file_backed_region(LinearAddress laddr, size_t size, RetainPtr<Inode>&& inode, String&& name, bool is_readable, bool is_writable) | ||||
| { | ||||
|     ASSERT(!vnode->isCharacterDevice()); | ||||
|     size = PAGE_ROUND_UP(size); | ||||
|     // FIXME: This needs sanity checks. What if this overlaps existing regions?
 | ||||
|     if (laddr.is_null()) { | ||||
|  | @ -95,7 +94,7 @@ Region* Process::allocate_file_backed_region(LinearAddress laddr, size_t size, R | |||
|         m_nextRegion = m_nextRegion.offset(size).offset(PAGE_SIZE); | ||||
|     } | ||||
|     laddr.mask(0xfffff000); | ||||
|     m_regions.append(adopt(*new Region(laddr, size, move(vnode), move(name), is_readable, is_writable))); | ||||
|     m_regions.append(adopt(*new Region(laddr, size, move(inode), move(name), is_readable, is_writable))); | ||||
|     MM.map_region(*this, *m_regions.last()); | ||||
|     return m_regions.last().ptr(); | ||||
| } | ||||
|  | @ -178,14 +177,14 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params) | |||
|     auto* descriptor = file_descriptor(fd); | ||||
|     if (!descriptor) | ||||
|         return (void*)-EBADF; | ||||
|     if (descriptor->vnode()->isCharacterDevice()) | ||||
|     if (!descriptor->supports_mmap()) | ||||
|         return (void*)-ENODEV; | ||||
|     // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec.
 | ||||
|     auto region_name = descriptor->absolute_path(); | ||||
|     InterruptDisabler disabler; | ||||
|     // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
 | ||||
|     ASSERT(addr == nullptr); | ||||
|     auto* region = allocate_file_backed_region(LinearAddress(), size, descriptor->vnode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); | ||||
|     auto* region = allocate_file_backed_region(LinearAddress(), size, descriptor->inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); | ||||
|     if (!region) | ||||
|         return (void*)-ENOMEM; | ||||
|     return region->linearAddress.asPtr(); | ||||
|  | @ -288,7 +287,7 @@ int Process::do_exec(const String& path, Vector<String>&& arguments, Vector<Stri | |||
|         return -ENOENT; | ||||
| 
 | ||||
|     int error; | ||||
|     auto descriptor = VFS::the().open(path, error, 0, m_cwd ? m_cwd->inode : InodeIdentifier()); | ||||
|     auto descriptor = VFS::the().open(path, error, 0, m_cwd ? m_cwd->identifier() : InodeIdentifier()); | ||||
|     if (!descriptor) { | ||||
|         ASSERT(error != 0); | ||||
|         return error; | ||||
|  | @ -302,7 +301,7 @@ int Process::do_exec(const String& path, Vector<String>&& arguments, Vector<Stri | |||
|         return -ENOTIMPL; | ||||
|     } | ||||
| 
 | ||||
|     auto vmo = VMObject::create_file_backed(descriptor->vnode(), descriptor->metadata().size); | ||||
|     auto vmo = VMObject::create_file_backed(descriptor->inode(), descriptor->metadata().size); | ||||
|     vmo->set_name(descriptor->absolute_path()); | ||||
|     auto* region = allocate_region_with_vmo(LinearAddress(), descriptor->metadata().size, vmo.copyRef(), 0, "helper", true, false); | ||||
| 
 | ||||
|  | @ -403,7 +402,7 @@ int Process::do_exec(const String& path, Vector<String>&& arguments, Vector<Stri | |||
|     m_tss.esp0 = old_esp0; | ||||
|     m_tss.ss2 = m_pid; | ||||
| 
 | ||||
|     m_executable = descriptor->vnode(); | ||||
|     m_executable = descriptor->inode(); | ||||
|     m_arguments = move(arguments); | ||||
|     m_initialEnvironment = move(environment); | ||||
| 
 | ||||
|  | @ -481,14 +480,15 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, | |||
|     if (arguments.is_empty()) { | ||||
|         arguments.append(parts.last()); | ||||
|     } | ||||
|     RetainPtr<Vnode> cwd; | ||||
|     RetainPtr<Inode> cwd; | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         if (auto* parent = Process::from_pid(parent_pid)) | ||||
|             cwd = parent->m_cwd.copyRef(); | ||||
|     } | ||||
| 
 | ||||
|     if (!cwd) | ||||
|         cwd = VFS::the().root(); | ||||
|         cwd = VFS::the().root_inode(); | ||||
| 
 | ||||
|     auto* process = new Process(parts.takeLast(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty); | ||||
| 
 | ||||
|  | @ -570,7 +570,7 @@ Process* Process::create_kernel_process(String&& name, void (*e)()) | |||
|     return process; | ||||
| } | ||||
| 
 | ||||
| Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RetainPtr<Vnode>&& cwd, RetainPtr<Vnode>&& executable, TTY* tty, Process* fork_parent) | ||||
| Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RetainPtr<Inode>&& cwd, RetainPtr<Inode>&& executable, TTY* tty, Process* fork_parent) | ||||
|     : m_name(move(name)) | ||||
|     , m_pid(next_pid++) // FIXME: RACE: This variable looks racy!
 | ||||
|     , m_uid(uid) | ||||
|  | @ -1075,6 +1075,10 @@ ssize_t Process::sys$read(int fd, void* outbuf, size_t nread) | |||
|     auto* descriptor = file_descriptor(fd); | ||||
|     if (!descriptor) | ||||
|         return -EBADF; | ||||
| #ifdef DEBUG_IO | ||||
|     dbgprintf("   > descriptor:%p, is_blocking:%u, can_read:%u\n", descriptor, descriptor->is_blocking(), descriptor->can_read(*this)); | ||||
|     dbgprintf("   > inode:K%x, device:K%x\n", descriptor->inode(), descriptor->character_device()); | ||||
| #endif | ||||
|     if (descriptor->is_blocking()) { | ||||
|         if (!descriptor->can_read(*this)) { | ||||
|             m_blocked_fd = fd; | ||||
|  | @ -1252,7 +1256,7 @@ int Process::sys$chdir(const char* path) | |||
|         return error; | ||||
|     if (!descriptor->is_directory()) | ||||
|         return -ENOTDIR; | ||||
|     m_cwd = descriptor->vnode(); | ||||
|     m_cwd = descriptor->inode(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -237,8 +237,8 @@ public: | |||
|     template<typename T> bool validate_read_typed(T* value, size_t count = 1) { return validate_read(value, sizeof(T) * count); } | ||||
|     template<typename T> bool validate_write_typed(T* value, size_t count = 1) { return validate_write(value, sizeof(T) * count); } | ||||
| 
 | ||||
|     Inode* cwd_inode() { return m_cwd ? m_cwd->core_inode() : nullptr; } | ||||
|     Inode* executable_inode() { return m_executable ? m_executable->core_inode() : nullptr; } | ||||
|     Inode* cwd_inode() { return m_cwd.ptr(); } | ||||
|     Inode* executable_inode() { return m_executable.ptr(); } | ||||
| 
 | ||||
|     size_t number_of_open_file_descriptors() const; | ||||
|     size_t max_open_file_descriptors() const { return m_max_open_file_descriptors; } | ||||
|  | @ -262,7 +262,7 @@ private: | |||
|     friend class Scheduler; | ||||
|     friend class Region; | ||||
| 
 | ||||
|     Process(String&& name, uid_t, gid_t, pid_t ppid, RingLevel, RetainPtr<Vnode>&& cwd = nullptr, RetainPtr<Vnode>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); | ||||
|     Process(String&& name, uid_t, gid_t, pid_t ppid, RingLevel, RetainPtr<Inode>&& cwd = nullptr, RetainPtr<Inode>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); | ||||
| 
 | ||||
|     int do_exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment); | ||||
|     void push_value_on_stack(dword); | ||||
|  | @ -316,13 +316,13 @@ private: | |||
|     byte m_termination_status { 0 }; | ||||
|     byte m_termination_signal { 0 }; | ||||
| 
 | ||||
|     RetainPtr<Vnode> m_cwd; | ||||
|     RetainPtr<Vnode> m_executable; | ||||
|     RetainPtr<Inode> m_cwd; | ||||
|     RetainPtr<Inode> m_executable; | ||||
| 
 | ||||
|     TTY* m_tty { nullptr }; | ||||
| 
 | ||||
|     Region* allocate_region(LinearAddress, size_t, String&& name, bool is_readable = true, bool is_writable = true, bool commit = true); | ||||
|     Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr<Vnode>&& vnode, String&& name, bool is_readable, bool is_writable); | ||||
|     Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr<Inode>&&, String&& name, bool is_readable, bool is_writable); | ||||
|     Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr<VMObject>&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable); | ||||
|     bool deallocate_region(Region& region); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func) | ||||
| { | ||||
|     dbgprintf("USERSPACE(%d) ASSERTION FAILED: %s\n%s:%u in %s\n", getpid(), msg, file, line, func); | ||||
|     fprintf(stderr, "ASSERTION FAILED: %s\n%s:%u in %s\n", msg, file, line, func); | ||||
|     abort(); | ||||
|     for (;;); | ||||
|  |  | |||
|  | @ -59,13 +59,23 @@ static int max(int a, int b) | |||
|     return a > b ? a : b; | ||||
| } | ||||
| 
 | ||||
| static int open_ptm() | ||||
| { | ||||
|     char buf[32]; | ||||
|     for (unsigned i = 0; i < 4; ++i) { | ||||
|         sprintf(buf, "/dev/ptm%u", i); | ||||
|         int fd = open(buf, O_RDWR); | ||||
|         if (fd) | ||||
|             return fd; | ||||
|     } | ||||
|     dbgprintf("No master PTY available :(\n"); | ||||
|     exit(1); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| int main(int, char**) | ||||
| { | ||||
|     int ptm_fd = open("/dev/ptm0", O_RDWR); | ||||
|     if (ptm_fd < 0) { | ||||
|         perror("open"); | ||||
|         return 1; | ||||
|     } | ||||
|     int ptm_fd = open_ptm(); | ||||
| 
 | ||||
|     make_shell(ptm_fd); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| 
 | ||||
| CharacterDevice::~CharacterDevice() | ||||
| { | ||||
|     ASSERT_NOT_REACHED(); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> CharacterDevice::open(int options) | ||||
|  |  | |||
|  | @ -1,15 +1,18 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Retainable.h> | ||||
| #include <AK/Types.h> | ||||
| #include "Limits.h" | ||||
| #include "FileDescriptor.h" | ||||
| 
 | ||||
| class Process; | ||||
| 
 | ||||
| class CharacterDevice { | ||||
| class CharacterDevice : public Retainable<CharacterDevice> { | ||||
| public: | ||||
|     virtual ~CharacterDevice(); | ||||
| 
 | ||||
|     InodeMetadata metadata() const { return { }; } | ||||
| 
 | ||||
|     RetainPtr<FileDescriptor> open(int options); | ||||
| 
 | ||||
|     virtual bool can_read(Process&) const = 0; | ||||
|  |  | |||
|  | @ -11,9 +11,14 @@ | |||
| #include "MasterPTY.h" | ||||
| #endif | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Vnode>&& vnode) | ||||
| RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& inode) | ||||
| { | ||||
|     return adopt(*new FileDescriptor(move(vnode))); | ||||
|     return adopt(*new FileDescriptor(move(inode))); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<CharacterDevice>&& device) | ||||
| { | ||||
|     return adopt(*new FileDescriptor(move(device))); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> FileDescriptor::create_pipe_writer(FIFO& fifo) | ||||
|  | @ -26,8 +31,13 @@ RetainPtr<FileDescriptor> FileDescriptor::create_pipe_reader(FIFO& fifo) | |||
|     return adopt(*new FileDescriptor(fifo, FIFO::Reader)); | ||||
| } | ||||
| 
 | ||||
| FileDescriptor::FileDescriptor(RetainPtr<Vnode>&& vnode) | ||||
|     : m_vnode(move(vnode)) | ||||
| FileDescriptor::FileDescriptor(RetainPtr<Inode>&& inode) | ||||
|     : m_inode(move(inode)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| FileDescriptor::FileDescriptor(RetainPtr<CharacterDevice>&& device) | ||||
|     : m_device(move(device)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | @ -45,7 +55,11 @@ RetainPtr<FileDescriptor> FileDescriptor::clone() | |||
|             ? FileDescriptor::create_pipe_reader(*m_fifo) | ||||
|             : FileDescriptor::create_pipe_writer(*m_fifo); | ||||
|     } else { | ||||
|         descriptor = FileDescriptor::create(m_vnode.copyRef()); | ||||
|         if (m_inode) | ||||
|             descriptor = FileDescriptor::create(m_inode.copyRef()); | ||||
|         else { | ||||
|             descriptor = FileDescriptor::create(m_device.copyRef()); | ||||
|         } | ||||
|     } | ||||
|     if (!descriptor) | ||||
|         return nullptr; | ||||
|  | @ -69,10 +83,10 @@ bool additionWouldOverflow(Unix::off_t a, Unix::off_t b) | |||
| int FileDescriptor::stat(Unix::stat* buffer) | ||||
| { | ||||
|     ASSERT(!is_fifo()); | ||||
|     if (!m_vnode) | ||||
|     if (!m_inode && !m_device) | ||||
|         return -EBADF; | ||||
| 
 | ||||
|     auto metadata = m_vnode->metadata(); | ||||
|     auto metadata = this->metadata(); | ||||
|     if (!metadata.isValid()) | ||||
|         return -EIO; | ||||
| 
 | ||||
|  | @ -95,12 +109,12 @@ int FileDescriptor::stat(Unix::stat* buffer) | |||
| Unix::off_t FileDescriptor::seek(Unix::off_t offset, int whence) | ||||
| { | ||||
|     ASSERT(!is_fifo()); | ||||
|     if (!m_vnode) | ||||
|     if (!m_inode && !m_device) | ||||
|         return -EBADF; | ||||
| 
 | ||||
|     // FIXME: The file type should be cached on the vnode.
 | ||||
|     //        It's silly that we have to do a full metadata lookup here.
 | ||||
|     auto metadata = m_vnode->metadata(); | ||||
|     auto metadata = this->metadata(); | ||||
|     if (!metadata.isValid()) | ||||
|         return -EIO; | ||||
| 
 | ||||
|  | @ -140,9 +154,9 @@ ssize_t FileDescriptor::read(Process& process, byte* buffer, size_t count) | |||
|         ASSERT(fifo_direction() == FIFO::Reader); | ||||
|         return m_fifo->read(buffer, count); | ||||
|     } | ||||
|     if (m_vnode->isCharacterDevice()) { | ||||
|     if (m_device) { | ||||
|         // FIXME: What should happen to m_currentOffset?
 | ||||
|         return m_vnode->characterDevice()->read(process, buffer, count); | ||||
|         return m_device->read(process, buffer, count); | ||||
|     } | ||||
|     ASSERT(inode()); | ||||
|     ssize_t nread = inode()->read_bytes(m_current_offset, count, buffer, this); | ||||
|  | @ -156,9 +170,9 @@ ssize_t FileDescriptor::write(Process& process, const byte* data, size_t size) | |||
|         ASSERT(fifo_direction() == FIFO::Writer); | ||||
|         return m_fifo->write(data, size); | ||||
|     } | ||||
|     if (m_vnode->isCharacterDevice()) { | ||||
|     if (m_device) { | ||||
|         // FIXME: What should happen to m_currentOffset?
 | ||||
|         return m_vnode->characterDevice()->write(process, data, size); | ||||
|         return m_device->write(process, data, size); | ||||
|     } | ||||
|     // FIXME: Implement non-device writes.
 | ||||
|     ASSERT_NOT_REACHED(); | ||||
|  | @ -171,8 +185,8 @@ bool FileDescriptor::can_write(Process& process) | |||
|         ASSERT(fifo_direction() == FIFO::Writer); | ||||
|         return m_fifo->can_write(); | ||||
|     } | ||||
|     if (m_vnode->isCharacterDevice()) | ||||
|         return m_vnode->characterDevice()->can_write(process); | ||||
|     if (m_device) | ||||
|         return m_device->can_write(process); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -182,8 +196,8 @@ bool FileDescriptor::can_read(Process& process) | |||
|         ASSERT(fifo_direction() == FIFO::Reader); | ||||
|         return m_fifo->can_read(); | ||||
|     } | ||||
|     if (m_vnode->isCharacterDevice()) | ||||
|         return m_vnode->characterDevice()->can_read(process); | ||||
|     if (m_device) | ||||
|         return m_device->can_read(process); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -191,26 +205,26 @@ ByteBuffer FileDescriptor::read_entire_file(Process& process) | |||
| { | ||||
|     ASSERT(!is_fifo()); | ||||
| 
 | ||||
|     if (m_vnode->isCharacterDevice()) { | ||||
|     if (m_device) { | ||||
|         auto buffer = ByteBuffer::create_uninitialized(1024); | ||||
|         ssize_t nread = m_vnode->characterDevice()->read(process, buffer.pointer(), buffer.size()); | ||||
|         ssize_t nread = m_device->read(process, buffer.pointer(), buffer.size()); | ||||
|         buffer.trim(nread); | ||||
|         return buffer; | ||||
|     } | ||||
| 
 | ||||
|     ASSERT(inode()); | ||||
|     return inode()->read_entire(this); | ||||
|     ASSERT(m_inode); | ||||
|     return m_inode->read_entire(this); | ||||
| } | ||||
| 
 | ||||
| bool FileDescriptor::is_directory() const | ||||
| { | ||||
|     ASSERT(!is_fifo()); | ||||
|     return m_vnode->metadata().isDirectory(); | ||||
|     return metadata().isDirectory(); | ||||
| } | ||||
| 
 | ||||
| ssize_t FileDescriptor::get_dir_entries(byte* buffer, size_t size) | ||||
| { | ||||
|     auto metadata = m_vnode->metadata(); | ||||
|     auto metadata = this->metadata(); | ||||
|     if (!metadata.isValid()) | ||||
|         return -EIO; | ||||
|     if (!metadata.isDirectory()) | ||||
|  | @ -219,7 +233,7 @@ ssize_t FileDescriptor::get_dir_entries(byte* buffer, size_t size) | |||
|     // FIXME: Compute the actual size needed.
 | ||||
|     auto tempBuffer = ByteBuffer::create_uninitialized(2048); | ||||
|     BufferStream stream(tempBuffer); | ||||
|     m_vnode->vfs()->traverse_directory_inode(*m_vnode->core_inode(), [&stream] (auto& entry) { | ||||
|     VFS::the().traverse_directory_inode(*m_inode, [&stream] (auto& entry) { | ||||
|         stream << (dword)entry.inode.index(); | ||||
|         stream << (byte)entry.fileType; | ||||
|         stream << (dword)entry.name_length; | ||||
|  | @ -233,41 +247,30 @@ ssize_t FileDescriptor::get_dir_entries(byte* buffer, size_t size) | |||
|     memcpy(buffer, tempBuffer.pointer(), stream.offset()); | ||||
|     return stream.offset(); | ||||
| } | ||||
| \ | ||||
| #ifdef SERENITY | ||||
| 
 | ||||
| bool FileDescriptor::is_tty() const | ||||
| { | ||||
|     if (is_fifo()) | ||||
|         return false; | ||||
|     if (auto* device = m_vnode->characterDevice()) | ||||
|         return device->is_tty(); | ||||
|     return false; | ||||
|     return m_device && m_device->is_tty(); | ||||
| } | ||||
| 
 | ||||
| const TTY* FileDescriptor::tty() const | ||||
| { | ||||
|     if (is_fifo()) | ||||
|     if (!is_tty()) | ||||
|         return nullptr; | ||||
|     if (auto* device = m_vnode->characterDevice()) | ||||
|         return static_cast<const TTY*>(device); | ||||
|     return nullptr; | ||||
|     return static_cast<const TTY*>(m_device.ptr()); | ||||
| } | ||||
| 
 | ||||
| TTY* FileDescriptor::tty() | ||||
| { | ||||
|     if (is_fifo()) | ||||
|     if (!is_tty()) | ||||
|         return nullptr; | ||||
|     if (auto* device = m_vnode->characterDevice()) | ||||
|         return static_cast<TTY*>(device); | ||||
|     return nullptr; | ||||
|     return static_cast<TTY*>(m_device.ptr()); | ||||
| } | ||||
| 
 | ||||
| bool FileDescriptor::is_master_pty() const | ||||
| { | ||||
|     if (is_fifo()) | ||||
|         return false; | ||||
|     if (auto* device = m_vnode->characterDevice()) | ||||
|         return device->is_master_pty(); | ||||
|     if (m_device) | ||||
|         return m_device->is_master_pty(); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|  | @ -275,16 +278,15 @@ const MasterPTY* FileDescriptor::master_pty() const | |||
| { | ||||
|     if (!is_master_pty()) | ||||
|         return nullptr; | ||||
|     return static_cast<const MasterPTY*>(m_vnode->characterDevice()); | ||||
|     return static_cast<const MasterPTY*>(m_device.ptr()); | ||||
| } | ||||
| 
 | ||||
| MasterPTY* FileDescriptor::master_pty() | ||||
| { | ||||
|     if (!is_master_pty()) | ||||
|         return nullptr; | ||||
|     return static_cast<MasterPTY*>(m_vnode->characterDevice()); | ||||
|     return static_cast<MasterPTY*>(m_device.ptr()); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int FileDescriptor::close() | ||||
| { | ||||
|  | @ -294,17 +296,15 @@ int FileDescriptor::close() | |||
| String FileDescriptor::absolute_path() | ||||
| { | ||||
|     Stopwatch sw("absolute_path"); | ||||
| #ifdef SERENITY | ||||
|     if (is_tty()) | ||||
|         return tty()->tty_name(); | ||||
| #endif | ||||
|     if (is_fifo()) { | ||||
|         char buf[32]; | ||||
|         ksprintf(buf, "fifo:%x", m_fifo.ptr()); | ||||
|         return buf; | ||||
|     } | ||||
|     ASSERT(m_vnode->core_inode()); | ||||
|     return VFS::the().absolute_path(*m_vnode->core_inode()); | ||||
|     ASSERT(m_inode); | ||||
|     return VFS::the().absolute_path(*m_inode); | ||||
| } | ||||
| 
 | ||||
| FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction) | ||||
|  | @ -314,3 +314,10 @@ FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction) | |||
| { | ||||
|     m_fifo->open(direction); | ||||
| } | ||||
| 
 | ||||
| InodeMetadata FileDescriptor::metadata() const | ||||
| { | ||||
|     if (m_inode) | ||||
|         return m_inode->metadata(); | ||||
|     return { }; | ||||
| } | ||||
|  |  | |||
|  | @ -15,7 +15,8 @@ class Process; | |||
| 
 | ||||
| class FileDescriptor : public Retainable<FileDescriptor> { | ||||
| public: | ||||
|     static RetainPtr<FileDescriptor> create(RetainPtr<Vnode>&&); | ||||
|     static RetainPtr<FileDescriptor> create(RetainPtr<Inode>&&); | ||||
|     static RetainPtr<FileDescriptor> create(RetainPtr<CharacterDevice>&&); | ||||
|     static RetainPtr<FileDescriptor> create_pipe_writer(FIFO&); | ||||
|     static RetainPtr<FileDescriptor> create_pipe_reader(FIFO&); | ||||
|     ~FileDescriptor(); | ||||
|  | @ -40,8 +41,9 @@ public: | |||
| 
 | ||||
|     bool is_directory() const; | ||||
| 
 | ||||
|     bool is_character_device() const { return m_vnode && m_vnode->isCharacterDevice(); } | ||||
|     CharacterDevice* character_device() { return m_vnode ? m_vnode->characterDevice() : nullptr; } | ||||
|     bool is_character_device() const { return m_device.ptr(); } | ||||
|     CharacterDevice* character_device() { return m_device.ptr(); } | ||||
|     const CharacterDevice* character_device() const { return m_device.ptr(); } | ||||
| 
 | ||||
| #ifdef SERENITY | ||||
|     bool is_tty() const; | ||||
|  | @ -53,10 +55,11 @@ public: | |||
|     MasterPTY* master_pty(); | ||||
| #endif | ||||
| 
 | ||||
|     InodeMetadata metadata() const { return m_vnode->metadata(); } | ||||
|     InodeMetadata metadata() const; | ||||
|     Inode* inode() { return m_inode.ptr(); } | ||||
|     const Inode* inode() const { return m_inode.ptr(); } | ||||
| 
 | ||||
|     Vnode* vnode() { return m_vnode.ptr(); } | ||||
|     Inode* inode() { return m_vnode ? m_vnode->core_inode() : nullptr; } | ||||
|     bool supports_mmap() const { return m_inode && !m_device; } | ||||
| 
 | ||||
| #ifdef SERENITY | ||||
|     bool is_blocking() const { return m_is_blocking; } | ||||
|  | @ -73,10 +76,12 @@ public: | |||
| 
 | ||||
| private: | ||||
|     friend class VFS; | ||||
|     explicit FileDescriptor(RetainPtr<Vnode>&&); | ||||
|     explicit FileDescriptor(RetainPtr<Inode>&&); | ||||
|     explicit FileDescriptor(RetainPtr<CharacterDevice>&&); | ||||
|     FileDescriptor(FIFO&, FIFO::Direction); | ||||
| 
 | ||||
|     RetainPtr<Vnode> m_vnode; | ||||
|     RetainPtr<Inode> m_inode; | ||||
|     RetainPtr<CharacterDevice> m_device; | ||||
| 
 | ||||
|     Unix::off_t m_current_offset { 0 }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include <AK/HashMap.h> | ||||
| #include <LibC/errno_numbers.h> | ||||
| #include "FileSystem.h" | ||||
| #include "MemoryManager.h" | ||||
| 
 | ||||
| static dword s_lastFileSystemID; | ||||
| static HashMap<dword, FS*>* s_fs_map; | ||||
|  | @ -14,7 +15,7 @@ static HashMap<dword, FS*>& all_fses() | |||
|     return *s_fs_map; | ||||
| } | ||||
| 
 | ||||
| static HashTable<Inode*>& all_inodes() | ||||
| HashTable<Inode*>& all_inodes() | ||||
| { | ||||
|     if (!s_inode_set) | ||||
|         s_inode_set = new HashTable<Inode*>(); | ||||
|  | @ -143,3 +144,8 @@ void FS::sync() | |||
|             inode->flush_metadata(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Inode::set_vmo(RetainPtr<VMObject>&& vmo) | ||||
| { | ||||
|     m_vmo = move(vmo); | ||||
| } | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ static const dword mepoch = 476763780; | |||
| 
 | ||||
| class Inode; | ||||
| class FileDescriptor; | ||||
| class VMObject; | ||||
| 
 | ||||
| class FS : public Retainable<FS> { | ||||
| public: | ||||
|  | @ -71,6 +72,7 @@ public: | |||
|     size_t size() const { return metadata().size; } | ||||
|     bool is_symlink() const { return metadata().isSymbolicLink(); } | ||||
|     bool is_directory() const { return metadata().isDirectory(); } | ||||
|     bool is_character_device() const { return metadata().isCharacterDevice(); } | ||||
| 
 | ||||
|     InodeIdentifier identifier() const { return { fsid(), index() }; } | ||||
|     virtual InodeMetadata metadata() const = 0; | ||||
|  | @ -97,6 +99,10 @@ public: | |||
| 
 | ||||
|     void will_be_destroyed(); | ||||
| 
 | ||||
|     void set_vmo(RetainPtr<VMObject>&&); | ||||
|     VMObject* vmo() { return m_vmo.ptr(); } | ||||
|     const VMObject* vmo() const { return m_vmo.ptr(); } | ||||
| 
 | ||||
| protected: | ||||
|     Inode(FS& fs, unsigned index); | ||||
| 
 | ||||
|  | @ -104,6 +110,7 @@ protected: | |||
| private: | ||||
|     FS& m_fs; | ||||
|     unsigned m_index { 0 }; | ||||
|     RetainPtr<VMObject> m_vmo; | ||||
|     bool m_metadata_dirty { false }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,101 +31,16 @@ VFS::VFS() | |||
|     kprintf("VFS: Constructing VFS\n"); | ||||
| #endif | ||||
|     s_the = this; | ||||
|     m_max_vnode_count = 16; | ||||
|     m_nodes = reinterpret_cast<Vnode*>(kmalloc(sizeof(Vnode) * max_vnode_count())); | ||||
|     memset(m_nodes, 0, sizeof(Vnode) * max_vnode_count()); | ||||
| 
 | ||||
|     for (unsigned i = 0; i < m_max_vnode_count; ++i) | ||||
|         m_vnode_freelist.append(&m_nodes[i]); | ||||
| } | ||||
| 
 | ||||
| VFS::~VFS() | ||||
| { | ||||
|     kprintf("VFS: ~VirtualFileSystem with %u nodes allocated\n", allocated_vnode_count()); | ||||
|     // FIXME: m_nodes is never freed. Does it matter though?
 | ||||
| } | ||||
| 
 | ||||
| auto VFS::makeNode(InodeIdentifier inode) -> RetainPtr<Vnode> | ||||
| { | ||||
|     auto core_inode = inode.fs()->get_inode(inode); | ||||
|     if (!core_inode) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto metadata = core_inode->metadata(); | ||||
| 
 | ||||
|     InterruptDisabler disabler; | ||||
| 
 | ||||
|     CharacterDevice* characterDevice = nullptr; | ||||
|     if (metadata.isCharacterDevice()) { | ||||
|         auto it = m_character_devices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice)); | ||||
|         if (it != m_character_devices.end()) { | ||||
|             characterDevice = (*it).value; | ||||
|         } else { | ||||
|             kprintf("VFS: makeNode() no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice); | ||||
|             return nullptr; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     auto vnode = allocateNode(); | ||||
|     ASSERT(vnode); | ||||
| 
 | ||||
|     FS* fileSystem = inode.fs(); | ||||
|     fileSystem->retain(); | ||||
| 
 | ||||
|     vnode->inode = inode; | ||||
|     vnode->m_core_inode = move(core_inode); | ||||
| 
 | ||||
| #ifdef VFS_DEBUG | ||||
|     kprintf("makeNode: inode=%u, size=%u, mode=%o, uid=%u, gid=%u\n", inode.index(), metadata.size, metadata.mode, metadata.uid, metadata.gid); | ||||
| #endif | ||||
| 
 | ||||
|     m_inode2vnode.set(inode, vnode.ptr()); | ||||
|     vnode->m_characterDevice = characterDevice; | ||||
| 
 | ||||
|     return vnode; | ||||
| } | ||||
| 
 | ||||
| auto VFS::makeNode(CharacterDevice& device) -> RetainPtr<Vnode> | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     auto vnode = allocateNode(); | ||||
|     ASSERT(vnode); | ||||
| 
 | ||||
| #ifdef VFS_DEBUG | ||||
|     kprintf("makeNode: device=%p (%u,%u)\n", &device, device.major(), device.minor()); | ||||
| #endif | ||||
| 
 | ||||
|     m_device2vnode.set(encodedDevice(device.major(), device.minor()), vnode.ptr()); | ||||
|     vnode->m_characterDevice = &device; | ||||
| 
 | ||||
|     return vnode; | ||||
| } | ||||
| 
 | ||||
| auto VFS::get_or_create_node(InodeIdentifier inode) -> RetainPtr<Vnode> | ||||
| { | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         auto it = m_inode2vnode.find(inode); | ||||
|         if (it != m_inode2vnode.end()) | ||||
|             return (*it).value; | ||||
|     } | ||||
|     return makeNode(inode); | ||||
| } | ||||
| 
 | ||||
| auto VFS::get_or_create_node(CharacterDevice& device) -> RetainPtr<Vnode> | ||||
| { | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         auto it = m_device2vnode.find(encodedDevice(device.major(), device.minor())); | ||||
|         if (it != m_device2vnode.end()) | ||||
|             return (*it).value; | ||||
|     } | ||||
|     return makeNode(device); | ||||
| } | ||||
| 
 | ||||
| InodeIdentifier VFS::root_inode_id() const | ||||
| { | ||||
|     return m_root_vnode->inode; | ||||
|     ASSERT(m_root_inode); | ||||
|     return m_root_inode->identifier(); | ||||
| } | ||||
| 
 | ||||
| bool VFS::mount(RetainPtr<FS>&& fileSystem, const String& path) | ||||
|  | @ -147,67 +62,30 @@ bool VFS::mount(RetainPtr<FS>&& fileSystem, const String& path) | |||
| 
 | ||||
| bool VFS::mount_root(RetainPtr<FS>&& fileSystem) | ||||
| { | ||||
|     if (m_root_vnode) { | ||||
|     if (m_root_inode) { | ||||
|         kprintf("VFS: mount_root can't mount another root\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     auto mount = make<Mount>(InodeIdentifier(), move(fileSystem)); | ||||
| 
 | ||||
|     auto node = makeNode(mount->guest()); | ||||
|     if (!node->inUse()) { | ||||
|         kprintf("VFS: root inode for / is not in use :(\n"); | ||||
|         return false; | ||||
|     } | ||||
|     if (!node->metadata().isDirectory()) { | ||||
|         kprintf("VFS: root inode for / is not a directory :(\n"); | ||||
|     auto root_inode_id = mount->guest().fs()->root_inode(); | ||||
|     auto root_inode = mount->guest().fs()->get_inode(root_inode_id); | ||||
|     if (!root_inode->is_directory()) { | ||||
|         kprintf("VFS: root inode (%02u:%08u) for / is not a directory :(\n", root_inode_id.fsid(), root_inode_id.index()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     m_root_vnode = move(node); | ||||
|     m_root_inode = move(root_inode); | ||||
| 
 | ||||
|     kprintf("VFS: mounted root on %s{%p}\n", | ||||
|         m_root_vnode->fs()->class_name(), | ||||
|         m_root_vnode->fs()); | ||||
|         m_root_inode->fs().class_name(), | ||||
|         &m_root_inode->fs()); | ||||
| 
 | ||||
|     m_mounts.append(move(mount)); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| auto VFS::allocateNode() -> RetainPtr<Vnode> | ||||
| { | ||||
|     if (m_vnode_freelist.is_empty()) { | ||||
|         kprintf("VFS: allocateNode has no nodes left\n"); | ||||
|         return nullptr; | ||||
|     } | ||||
|     auto* node = m_vnode_freelist.takeLast(); | ||||
|     ASSERT(node->retainCount == 0); | ||||
|     node->retainCount = 1; | ||||
|     node->m_vfs = this; | ||||
|     node->m_vmo = nullptr; | ||||
|     return adopt(*node); | ||||
| } | ||||
| 
 | ||||
| void VFS::freeNode(Vnode* node) | ||||
| { | ||||
|     InterruptDisabler disabler; | ||||
|     ASSERT(node); | ||||
|     ASSERT(node->inUse()); | ||||
|     if (node->inode.is_valid()) { | ||||
|         m_inode2vnode.remove(node->inode); | ||||
|         node->inode.fs()->release(); | ||||
|         node->inode = InodeIdentifier(); | ||||
|         node->m_core_inode = nullptr; | ||||
|     } | ||||
|     if (node->m_characterDevice) { | ||||
|         m_device2vnode.remove(encodedDevice(node->m_characterDevice->major(), node->m_characterDevice->minor())); | ||||
|         node->m_characterDevice = nullptr; | ||||
|     } | ||||
|     node->m_vfs = nullptr; | ||||
|     node->m_vmo = nullptr; | ||||
|     m_vnode_freelist.append(move(node)); | ||||
| } | ||||
| 
 | ||||
| auto VFS::find_mount_for_host(InodeIdentifier inode) -> Mount* | ||||
| { | ||||
|     for (auto& mount : m_mounts) { | ||||
|  | @ -228,7 +106,7 @@ auto VFS::find_mount_for_guest(InodeIdentifier inode) -> Mount* | |||
| 
 | ||||
| bool VFS::is_vfs_root(InodeIdentifier inode) const | ||||
| { | ||||
|     return inode == m_root_vnode->inode; | ||||
|     return inode == root_inode_id(); | ||||
| } | ||||
| 
 | ||||
| void VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntry&)> callback) | ||||
|  | @ -254,22 +132,25 @@ RetainPtr<FileDescriptor> VFS::open(CharacterDevice& device, int options) | |||
| { | ||||
|     // FIXME: Respect options.
 | ||||
|     (void) options; | ||||
|     auto vnode = get_or_create_node(device); | ||||
|     if (!vnode) | ||||
|         return nullptr; | ||||
|     return FileDescriptor::create(move(vnode)); | ||||
|     return FileDescriptor::create(device); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, InodeIdentifier base) | ||||
| { | ||||
|     auto inode = resolve_path(path, base, error, options); | ||||
|     if (!inode.is_valid()) | ||||
|     auto inode_id = resolve_path(path, base, error, options); | ||||
|     auto inode = get_inode(inode_id); | ||||
|     if (!inode) | ||||
|         return nullptr; | ||||
|     // FIXME: Propagate any error from get_or_create_node().
 | ||||
|     auto vnode = get_or_create_node(inode); | ||||
|     if (!vnode) | ||||
|         return nullptr; | ||||
|     return FileDescriptor::create(move(vnode)); | ||||
|     auto metadata = inode->metadata(); | ||||
|     if (metadata.isCharacterDevice()) { | ||||
|         auto it = m_character_devices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice)); | ||||
|         if (it == m_character_devices.end()) { | ||||
|             kprintf("VFS::open: no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice); | ||||
|             return nullptr; | ||||
|         } | ||||
|         return FileDescriptor::create((*it).value); | ||||
|     } | ||||
|     return FileDescriptor::create(move(inode)); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> VFS::create(const String& path, InodeIdentifier base, int& error) | ||||
|  | @ -277,7 +158,7 @@ RetainPtr<FileDescriptor> VFS::create(const String& path, InodeIdentifier base, | |||
|     // FIXME: Do the real thing, not just this fake thing!
 | ||||
|     (void) path; | ||||
|     (void) base; | ||||
|     m_root_vnode->fs()->create_inode(m_root_vnode->fs()->root_inode(), "empty", 0100644, 0, error); | ||||
|     m_root_inode->fs().create_inode(m_root_inode->fs().root_inode(), "empty", 0100644, 0, error); | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
|  | @ -337,7 +218,7 @@ String VFS::absolute_path(Inode& core_inode) | |||
|     int error; | ||||
|     Vector<InodeIdentifier> lineage; | ||||
|     RetainPtr<Inode> inode = &core_inode; | ||||
|     while (inode->identifier() != m_root_vnode->inode) { | ||||
|     while (inode->identifier() != root_inode_id()) { | ||||
|         if (auto* mount = find_mount_for_guest(inode->identifier())) | ||||
|             lineage.append(mount->host()); | ||||
|         else | ||||
|  | @ -354,7 +235,7 @@ String VFS::absolute_path(Inode& core_inode) | |||
|     } | ||||
|     if (lineage.is_empty()) | ||||
|         return "/"; | ||||
|     lineage.append(m_root_vnode->inode); | ||||
|     lineage.append(root_inode_id()); | ||||
|     StringBuilder builder; | ||||
|     for (size_t i = lineage.size() - 1; i >= 1; --i) { | ||||
|         auto& child = lineage[i - 1]; | ||||
|  | @ -379,9 +260,9 @@ InodeIdentifier VFS::resolve_path(const String& path, InodeIdentifier base, int& | |||
|     InodeIdentifier crumb_id; | ||||
| 
 | ||||
|     if (path[0] == '/') | ||||
|         crumb_id = m_root_vnode->inode; | ||||
|         crumb_id = root_inode_id(); | ||||
|     else | ||||
|         crumb_id = base.is_valid() ? base : m_root_vnode->inode; | ||||
|         crumb_id = base.is_valid() ? base : root_inode_id(); | ||||
| 
 | ||||
|     if (deepest_dir) | ||||
|         *deepest_dir = crumb_id; | ||||
|  | @ -459,29 +340,6 @@ InodeIdentifier VFS::resolve_path(const String& path, InodeIdentifier base, int& | |||
|     return crumb_id; | ||||
| } | ||||
| 
 | ||||
| void Vnode::retain() | ||||
| { | ||||
|     InterruptDisabler disabler; // FIXME: Make a Retainable with atomic retain count instead.
 | ||||
|     ++retainCount; | ||||
| } | ||||
| 
 | ||||
| void Vnode::release() | ||||
| { | ||||
|     InterruptDisabler disabler; // FIXME: Make a Retainable with atomic retain count instead.
 | ||||
|     ASSERT(retainCount); | ||||
|     if (--retainCount == 0) { | ||||
|         m_vfs->freeNode(this); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| InodeMetadata Vnode::metadata() const | ||||
| { | ||||
|     if (m_core_inode) | ||||
|         return m_core_inode->metadata(); | ||||
|     ASSERT_NOT_REACHED(); | ||||
|     return { }; | ||||
| } | ||||
| 
 | ||||
| VFS::Mount::Mount(InodeIdentifier host, RetainPtr<FS>&& guest_fs) | ||||
|     : m_host(host) | ||||
|     , m_guest(guest_fs->root_inode()) | ||||
|  |  | |||
|  | @ -35,46 +35,8 @@ inline constexpr dword encodedDevice(unsigned major, unsigned minor) | |||
| 
 | ||||
| class VFS; | ||||
| 
 | ||||
| class Vnode { | ||||
| public: | ||||
|     InodeIdentifier inode; | ||||
|     InodeMetadata metadata() const; | ||||
| 
 | ||||
|     bool inUse() const { return inode.is_valid() || m_characterDevice; } | ||||
| 
 | ||||
|     bool isCharacterDevice() const { return m_characterDevice; } | ||||
|     CharacterDevice* characterDevice() { return m_characterDevice; } | ||||
|     const CharacterDevice* characterDevice() const { return m_characterDevice; } | ||||
| 
 | ||||
|     void retain(); | ||||
|     void release(); | ||||
| 
 | ||||
|     FS* fs() { return inode.fs(); } | ||||
|     const FS* fs() const { return inode.fs(); } | ||||
| 
 | ||||
|     VFS* vfs() { return m_vfs; } | ||||
|     const VFS* vfs() const { return m_vfs; } | ||||
| 
 | ||||
|     void* vmo() { return m_vmo; } | ||||
|     void set_vmo(void* vmo) { m_vmo = vmo; } | ||||
| 
 | ||||
|     unsigned retain_count() const { return retainCount; } | ||||
| 
 | ||||
|     Inode* core_inode() { return m_core_inode.ptr(); } | ||||
| 
 | ||||
| private: | ||||
|     friend class VFS; | ||||
|     VFS* m_vfs { nullptr }; | ||||
|     unsigned retainCount { 0 }; | ||||
|     CharacterDevice* m_characterDevice { nullptr }; | ||||
|     mutable InodeMetadata m_cachedMetadata; | ||||
|     void* m_vmo { nullptr }; | ||||
|     RetainPtr<Inode> m_core_inode; | ||||
| }; | ||||
| 
 | ||||
| class VFS { | ||||
|     AK_MAKE_ETERNAL | ||||
|     friend ByteBuffer procfs$vnodes(); | ||||
| public: | ||||
|     static void initialize_globals(); | ||||
| 
 | ||||
|  | @ -98,12 +60,6 @@ public: | |||
|     VFS(); | ||||
|     ~VFS(); | ||||
| 
 | ||||
|     unsigned max_vnode_count() const { return m_max_vnode_count; } | ||||
|     unsigned allocated_vnode_count() const { return m_max_vnode_count - m_vnode_freelist.size(); } | ||||
| 
 | ||||
|     Vnode* root() { return m_root_vnode.ptr(); } | ||||
|     const Vnode* root() const { return m_root_vnode.ptr(); } | ||||
| 
 | ||||
|     bool mount_root(RetainPtr<FS>&&); | ||||
|     bool mount(RetainPtr<FS>&&, const String& path); | ||||
| 
 | ||||
|  | @ -122,12 +78,13 @@ public: | |||
|     String absolute_path(Inode&); | ||||
| 
 | ||||
|     InodeIdentifier root_inode_id() const; | ||||
|     Inode* root_inode() { return m_root_inode.ptr(); } | ||||
|     const Inode* root_inode() const { return m_root_inode.ptr(); } | ||||
| 
 | ||||
|     void sync(); | ||||
| 
 | ||||
| private: | ||||
|     friend class FileDescriptor; | ||||
|     friend class Vnode; | ||||
| 
 | ||||
|     RetainPtr<Inode> get_inode(InodeIdentifier); | ||||
| 
 | ||||
|  | @ -137,29 +94,11 @@ private: | |||
|     InodeIdentifier resolve_path(const String& path, InodeIdentifier base, int& error, int options = 0, InodeIdentifier* deepest_dir = nullptr); | ||||
|     InodeIdentifier resolve_symbolic_link(InodeIdentifier base, Inode& symlink_inode, int& error); | ||||
| 
 | ||||
|     RetainPtr<Vnode> allocateNode(); | ||||
|     void freeNode(Vnode*); | ||||
| 
 | ||||
|     RetainPtr<Vnode> makeNode(InodeIdentifier); | ||||
|     RetainPtr<Vnode> makeNode(CharacterDevice&); | ||||
|     RetainPtr<Vnode> get_or_create_node(InodeIdentifier); | ||||
|     RetainPtr<Vnode> get_or_create_node(CharacterDevice&); | ||||
| 
 | ||||
|     Mount* find_mount_for_host(InodeIdentifier); | ||||
|     Mount* find_mount_for_guest(InodeIdentifier); | ||||
| 
 | ||||
|     HashMap<InodeIdentifier, Vnode*> m_inode2vnode; | ||||
|     HashMap<dword, Vnode*> m_device2vnode; | ||||
| 
 | ||||
|     RetainPtr<Inode> m_root_inode; | ||||
|     Vector<OwnPtr<Mount>> m_mounts; | ||||
| 
 | ||||
|     unsigned m_max_vnode_count { 0 }; | ||||
|     Vnode* m_nodes { nullptr }; | ||||
| 
 | ||||
|     Vector<Vnode*> m_vnode_freelist; | ||||
| 
 | ||||
|     RetainPtr<Vnode> m_root_vnode; | ||||
| 
 | ||||
|     HashMap<dword, CharacterDevice*> m_character_devices; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling