diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 9ff1525b21..37cb27619a 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -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, String&& n, bool r, bool w) +Region::Region(LinearAddress a, size_t s, RetainPtr&& 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::create_file_backed(RetainPtr&& vnode, size_t size) +RetainPtr VMObject::create_file_backed(RetainPtr&& inode, size_t size) { InterruptDisabler disabler; - if (vnode->vmo()) - return static_cast(vnode->vmo()); + if (inode->vmo()) + return static_cast(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::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, size_t size) +VMObject::VMObject(RetainPtr&& 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, 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); } diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index a2b58cd727..6e3eab003b 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -74,7 +74,7 @@ private: class VMObject : public Retainable { public: - static RetainPtr create_file_backed(RetainPtr&&, size_t); + static RetainPtr create_file_backed(RetainPtr&&, size_t); static RetainPtr create_anonymous(size_t); static RetainPtr create_framebuffer_wrapper(PhysicalAddress, size_t); RetainPtr 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>& physical_pages() { return m_physical_pages; } private: - VMObject(RetainPtr&&, size_t); + VMObject(RetainPtr&&, 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 m_vnode; + RetainPtr m_inode; Vector> m_physical_pages; }; @@ -110,7 +110,7 @@ class Region : public Retainable { public: Region(LinearAddress, size_t, String&&, bool r, bool w, bool cow = false); Region(LinearAddress, size_t, RetainPtr&&, size_t offset_in_vmo, String&&, bool r, bool w, bool cow = false); - Region(LinearAddress, size_t, RetainPtr&&, String&&, bool r, bool w); + Region(LinearAddress, size_t, RetainPtr&&, 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&); diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index a4a4d2a9e7..c90e89af0f 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -354,29 +354,16 @@ ByteBuffer procfs$summary() return buffer; } -ByteBuffer procfs$vnodes() +ByteBuffer procfs$inodes() { + extern HashTable& 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(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 = *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; } diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 6c726a9e82..dbc9f56ab8 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -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, String&& name, bool is_readable, bool is_writable) +Region* Process::allocate_file_backed_region(LinearAddress laddr, size_t size, RetainPtr&& 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&& arguments, Vectorinode : 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&& arguments, Vectorvnode(), 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&& arguments, Vectorvnode(); + 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 cwd; + RetainPtr 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&& cwd, RetainPtr&& executable, TTY* tty, Process* fork_parent) +Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RetainPtr&& cwd, RetainPtr&& 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; } diff --git a/Kernel/Process.h b/Kernel/Process.h index 2660a6f201..4e96a5328c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -237,8 +237,8 @@ public: template bool validate_read_typed(T* value, size_t count = 1) { return validate_read(value, sizeof(T) * count); } template 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&& cwd = nullptr, RetainPtr&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); + Process(String&& name, uid_t, gid_t, pid_t ppid, RingLevel, RetainPtr&& cwd = nullptr, RetainPtr&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); int do_exec(const String& path, Vector&& arguments, Vector&& environment); void push_value_on_stack(dword); @@ -316,13 +316,13 @@ private: byte m_termination_status { 0 }; byte m_termination_signal { 0 }; - RetainPtr m_cwd; - RetainPtr m_executable; + RetainPtr m_cwd; + RetainPtr 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, String&& name, bool is_readable, bool is_writable); + Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr&&, String&& name, bool is_readable, bool is_writable); Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable); bool deallocate_region(Region& region); diff --git a/LibC/assert.cpp b/LibC/assert.cpp index d8fb42a151..a123c911da 100644 --- a/LibC/assert.cpp +++ b/LibC/assert.cpp @@ -1,11 +1,13 @@ #include #include #include +#include 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 (;;); diff --git a/Terminal/main.cpp b/Terminal/main.cpp index 6b2fa8b3da..90b0cb23e0 100644 --- a/Terminal/main.cpp +++ b/Terminal/main.cpp @@ -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); diff --git a/VirtualFileSystem/CharacterDevice.cpp b/VirtualFileSystem/CharacterDevice.cpp index 851664ba9b..61150da2e9 100644 --- a/VirtualFileSystem/CharacterDevice.cpp +++ b/VirtualFileSystem/CharacterDevice.cpp @@ -3,6 +3,7 @@ CharacterDevice::~CharacterDevice() { + ASSERT_NOT_REACHED(); } RetainPtr CharacterDevice::open(int options) diff --git a/VirtualFileSystem/CharacterDevice.h b/VirtualFileSystem/CharacterDevice.h index 811e340427..58df4618ab 100644 --- a/VirtualFileSystem/CharacterDevice.h +++ b/VirtualFileSystem/CharacterDevice.h @@ -1,15 +1,18 @@ #pragma once +#include #include #include "Limits.h" #include "FileDescriptor.h" class Process; -class CharacterDevice { +class CharacterDevice : public Retainable { public: virtual ~CharacterDevice(); + InodeMetadata metadata() const { return { }; } + RetainPtr open(int options); virtual bool can_read(Process&) const = 0; diff --git a/VirtualFileSystem/FileDescriptor.cpp b/VirtualFileSystem/FileDescriptor.cpp index a6f422752e..d98bd28b8f 100644 --- a/VirtualFileSystem/FileDescriptor.cpp +++ b/VirtualFileSystem/FileDescriptor.cpp @@ -11,9 +11,14 @@ #include "MasterPTY.h" #endif -RetainPtr FileDescriptor::create(RetainPtr&& vnode) +RetainPtr FileDescriptor::create(RetainPtr&& inode) { - return adopt(*new FileDescriptor(move(vnode))); + return adopt(*new FileDescriptor(move(inode))); +} + +RetainPtr FileDescriptor::create(RetainPtr&& device) +{ + return adopt(*new FileDescriptor(move(device))); } RetainPtr FileDescriptor::create_pipe_writer(FIFO& fifo) @@ -26,8 +31,13 @@ RetainPtr FileDescriptor::create_pipe_reader(FIFO& fifo) return adopt(*new FileDescriptor(fifo, FIFO::Reader)); } -FileDescriptor::FileDescriptor(RetainPtr&& vnode) - : m_vnode(move(vnode)) +FileDescriptor::FileDescriptor(RetainPtr&& inode) + : m_inode(move(inode)) +{ +} + +FileDescriptor::FileDescriptor(RetainPtr&& device) + : m_device(move(device)) { } @@ -45,7 +55,11 @@ RetainPtr 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(device); - return nullptr; + return static_cast(m_device.ptr()); } TTY* FileDescriptor::tty() { - if (is_fifo()) + if (!is_tty()) return nullptr; - if (auto* device = m_vnode->characterDevice()) - return static_cast(device); - return nullptr; + return static_cast(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(m_vnode->characterDevice()); + return static_cast(m_device.ptr()); } MasterPTY* FileDescriptor::master_pty() { if (!is_master_pty()) return nullptr; - return static_cast(m_vnode->characterDevice()); + return static_cast(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 { }; +} diff --git a/VirtualFileSystem/FileDescriptor.h b/VirtualFileSystem/FileDescriptor.h index ba16df3c29..860e3a09df 100644 --- a/VirtualFileSystem/FileDescriptor.h +++ b/VirtualFileSystem/FileDescriptor.h @@ -15,7 +15,8 @@ class Process; class FileDescriptor : public Retainable { public: - static RetainPtr create(RetainPtr&&); + static RetainPtr create(RetainPtr&&); + static RetainPtr create(RetainPtr&&); static RetainPtr create_pipe_writer(FIFO&); static RetainPtr 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&&); + explicit FileDescriptor(RetainPtr&&); + explicit FileDescriptor(RetainPtr&&); FileDescriptor(FIFO&, FIFO::Direction); - RetainPtr m_vnode; + RetainPtr m_inode; + RetainPtr m_device; Unix::off_t m_current_offset { 0 }; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index 59633ab229..61d336a215 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -2,6 +2,7 @@ #include #include #include "FileSystem.h" +#include "MemoryManager.h" static dword s_lastFileSystemID; static HashMap* s_fs_map; @@ -14,7 +15,7 @@ static HashMap& all_fses() return *s_fs_map; } -static HashTable& all_inodes() +HashTable& all_inodes() { if (!s_inode_set) s_inode_set = new HashTable(); @@ -143,3 +144,8 @@ void FS::sync() inode->flush_metadata(); } } + +void Inode::set_vmo(RetainPtr&& vmo) +{ + m_vmo = move(vmo); +} diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index ae147bca98..9aff339819 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -18,6 +18,7 @@ static const dword mepoch = 476763780; class Inode; class FileDescriptor; +class VMObject; class FS : public Retainable { 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* 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 m_vmo; bool m_metadata_dirty { false }; }; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index d23be21a32..3700ea332a 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -31,101 +31,16 @@ VFS::VFS() kprintf("VFS: Constructing VFS\n"); #endif s_the = this; - m_max_vnode_count = 16; - m_nodes = reinterpret_cast(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 -{ - 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 -{ - 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 -{ - { - 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 -{ - { - 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&& fileSystem, const String& path) @@ -147,67 +62,30 @@ bool VFS::mount(RetainPtr&& fileSystem, const String& path) bool VFS::mount_root(RetainPtr&& fileSystem) { - if (m_root_vnode) { + if (m_root_inode) { kprintf("VFS: mount_root can't mount another root\n"); return false; } auto mount = make(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 -{ - 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 callback) @@ -254,22 +132,25 @@ RetainPtr 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 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 VFS::create(const String& path, InodeIdentifier base, int& error) @@ -277,7 +158,7 @@ RetainPtr 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 lineage; RetainPtr 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&& guest_fs) : m_host(host) , m_guest(guest_fs->root_inode()) diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index e53c1712ae..86a19e62f5 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -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 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&&); bool mount(RetainPtr&&, 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 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 allocateNode(); - void freeNode(Vnode*); - - RetainPtr makeNode(InodeIdentifier); - RetainPtr makeNode(CharacterDevice&); - RetainPtr get_or_create_node(InodeIdentifier); - RetainPtr get_or_create_node(CharacterDevice&); - Mount* find_mount_for_host(InodeIdentifier); Mount* find_mount_for_guest(InodeIdentifier); - HashMap m_inode2vnode; - HashMap m_device2vnode; - + RetainPtr m_root_inode; Vector> m_mounts; - - unsigned m_max_vnode_count { 0 }; - Vnode* m_nodes { nullptr }; - - Vector m_vnode_freelist; - - RetainPtr m_root_vnode; - HashMap m_character_devices; };