From 32aa37d5dcfedf90a14696a5a6eec76bc029cffa Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 17 Nov 2021 19:33:00 +0100 Subject: [PATCH] Kernel+LibC: Add msync() system call This allows userspace to trigger a full (FIXME) flush of a shared file mapping to disk. We iterate over all the mapped pages in the VMObject and write them out to the underlying inode, one by one. This is rather naive, and there's lots of room for improvement. Note that shared file mappings are currently not possible since mmap() returns ENOTSUP for PROT_WRITE+MAP_SHARED. That restriction will be removed in a subsequent commit. :^) --- Kernel/API/POSIX/sys/mman.h | 4 ++++ Kernel/API/Syscall.h | 1 + Kernel/Memory/SharedInodeVMObject.cpp | 19 +++++++++++++++++++ Kernel/Memory/SharedInodeVMObject.h | 2 ++ Kernel/Process.h | 1 + Kernel/Syscalls/mmap.cpp | 17 +++++++++++++++++ Userland/Libraries/LibC/sys/mman.cpp | 6 ++++++ Userland/Libraries/LibC/sys/mman.h | 1 + 8 files changed, 51 insertions(+) diff --git a/Kernel/API/POSIX/sys/mman.h b/Kernel/API/POSIX/sys/mman.h index 3c996e9699b..65a66183854 100644 --- a/Kernel/API/POSIX/sys/mman.h +++ b/Kernel/API/POSIX/sys/mman.h @@ -34,6 +34,10 @@ extern "C" { #define MADV_SET_VOLATILE 0x100 #define MADV_SET_NONVOLATILE 0x200 +#define MS_SYNC 1 +#define MS_ASYNC 2 +#define MS_INVALIDATE 4 + #ifdef __cplusplus } #endif diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index c321b4b7f93..40e55642b18 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -124,6 +124,7 @@ enum class NeedsBigProcessLock { S(mount, NeedsBigProcessLock::Yes) \ S(mprotect, NeedsBigProcessLock::Yes) \ S(mremap, NeedsBigProcessLock::Yes) \ + S(msync, NeedsBigProcessLock::Yes) \ S(msyscall, NeedsBigProcessLock::Yes) \ S(munmap, NeedsBigProcessLock::Yes) \ S(open, NeedsBigProcessLock::Yes) \ diff --git a/Kernel/Memory/SharedInodeVMObject.cpp b/Kernel/Memory/SharedInodeVMObject.cpp index 605af54e181..15ad1c39e27 100644 --- a/Kernel/Memory/SharedInodeVMObject.cpp +++ b/Kernel/Memory/SharedInodeVMObject.cpp @@ -5,6 +5,7 @@ */ #include +#include #include namespace Kernel::Memory { @@ -34,4 +35,22 @@ SharedInodeVMObject::SharedInodeVMObject(SharedInodeVMObject const& other) { } +ErrorOr SharedInodeVMObject::sync() +{ + SpinlockLocker locker(m_lock); + + for (size_t page_index = 0; page_index < page_count(); ++page_index) { + auto& physical_page = m_physical_pages[page_index]; + if (!physical_page) + continue; + + u8 page_buffer[PAGE_SIZE]; + MM.copy_physical_page(*physical_page, page_buffer); + + TRY(m_inode->write_bytes(page_index * PAGE_SIZE, PAGE_SIZE, UserOrKernelBuffer::for_kernel_buffer(page_buffer), nullptr)); + } + + return {}; +} + } diff --git a/Kernel/Memory/SharedInodeVMObject.h b/Kernel/Memory/SharedInodeVMObject.h index c596addbf9c..81d6a93ca03 100644 --- a/Kernel/Memory/SharedInodeVMObject.h +++ b/Kernel/Memory/SharedInodeVMObject.h @@ -18,6 +18,8 @@ public: static ErrorOr> try_create_with_inode(Inode&); virtual ErrorOr> try_clone() override; + ErrorOr sync(); + private: virtual bool is_shared_inode() const override { return true; } diff --git a/Kernel/Process.h b/Kernel/Process.h index 3fe8fe2f55a..bc9ff416790 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -313,6 +313,7 @@ public: ErrorOr sys$mprotect(Userspace, size_t, int prot); ErrorOr sys$madvise(Userspace, size_t, int advice); ErrorOr sys$msyscall(Userspace); + ErrorOr sys$msync(Userspace, size_t, int flags); ErrorOr sys$purge(int mode); ErrorOr sys$select(Userspace); ErrorOr sys$poll(Userspace); diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp index 68a001890d2..1b3e99b755c 100644 --- a/Kernel/Syscalls/mmap.cpp +++ b/Kernel/Syscalls/mmap.cpp @@ -589,4 +589,21 @@ ErrorOr Process::sys$msyscall(Userspace address) region->set_syscall_region(true); return 0; } + +ErrorOr Process::sys$msync(Userspace address, size_t size, [[maybe_unused]] int flags) +{ + // FIXME: We probably want to sync all mappings in the address+size range. + auto* region = address_space().find_region_from_range(Memory::VirtualRange { address.vaddr(), size }); + if (!region) + return EINVAL; + + auto& vmobject = region->vmobject(); + if (!vmobject.is_shared_inode()) + return 0; + + auto& inode_vmobject = static_cast(vmobject); + TRY(inode_vmobject.sync()); + return 0; +} + } diff --git a/Userland/Libraries/LibC/sys/mman.cpp b/Userland/Libraries/LibC/sys/mman.cpp index 457ddd43939..fa2479f4f6a 100644 --- a/Userland/Libraries/LibC/sys/mman.cpp +++ b/Userland/Libraries/LibC/sys/mman.cpp @@ -89,4 +89,10 @@ int mlock(const void*, size_t) dbgln("FIXME: Implement mlock()"); return 0; } + +int msync(void* address, size_t size, int flags) +{ + int rc = syscall(SC_msync, address, size, flags); + __RETURN_WITH_ERRNO(rc, rc, -1); +} } diff --git a/Userland/Libraries/LibC/sys/mman.h b/Userland/Libraries/LibC/sys/mman.h index 2f694ff5417..c1eacbe127e 100644 --- a/Userland/Libraries/LibC/sys/mman.h +++ b/Userland/Libraries/LibC/sys/mman.h @@ -20,5 +20,6 @@ int set_mmap_name(void*, size_t, const char*); int madvise(void*, size_t, int advice); void* allocate_tls(const char* initial_data, size_t); int mlock(const void*, size_t); +int msync(void*, size_t, int flags); __END_DECLS