diff --git a/Kernel/API/POSIX/sys/mman.h b/Kernel/API/POSIX/sys/mman.h index 3c996e9699..65a6618385 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 c321b4b7f9..40e55642b1 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 605af54e18..15ad1c39e2 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 c596addbf9..81d6a93ca0 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 3fe8fe2f55..bc9ff41679 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 68a001890d..1b3e99b755 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 457ddd4393..fa2479f4f6 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 2f694ff541..c1eacbe127 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