Ver Fonte

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. :^)
Andreas Kling há 3 anos atrás
pai
commit
32aa37d5dc

+ 4 - 0
Kernel/API/POSIX/sys/mman.h

@@ -34,6 +34,10 @@ extern "C" {
 #define MADV_SET_VOLATILE 0x100
 #define MADV_SET_VOLATILE 0x100
 #define MADV_SET_NONVOLATILE 0x200
 #define MADV_SET_NONVOLATILE 0x200
 
 
+#define MS_SYNC 1
+#define MS_ASYNC 2
+#define MS_INVALIDATE 4
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 1 - 0
Kernel/API/Syscall.h

@@ -124,6 +124,7 @@ enum class NeedsBigProcessLock {
     S(mount, NeedsBigProcessLock::Yes)                      \
     S(mount, NeedsBigProcessLock::Yes)                      \
     S(mprotect, NeedsBigProcessLock::Yes)                   \
     S(mprotect, NeedsBigProcessLock::Yes)                   \
     S(mremap, NeedsBigProcessLock::Yes)                     \
     S(mremap, NeedsBigProcessLock::Yes)                     \
+    S(msync, NeedsBigProcessLock::Yes)                      \
     S(msyscall, NeedsBigProcessLock::Yes)                   \
     S(msyscall, NeedsBigProcessLock::Yes)                   \
     S(munmap, NeedsBigProcessLock::Yes)                     \
     S(munmap, NeedsBigProcessLock::Yes)                     \
     S(open, NeedsBigProcessLock::Yes)                       \
     S(open, NeedsBigProcessLock::Yes)                       \

+ 19 - 0
Kernel/Memory/SharedInodeVMObject.cpp

@@ -5,6 +5,7 @@
  */
  */
 
 
 #include <Kernel/FileSystem/Inode.h>
 #include <Kernel/FileSystem/Inode.h>
+#include <Kernel/Locking/Spinlock.h>
 #include <Kernel/Memory/SharedInodeVMObject.h>
 #include <Kernel/Memory/SharedInodeVMObject.h>
 
 
 namespace Kernel::Memory {
 namespace Kernel::Memory {
@@ -34,4 +35,22 @@ SharedInodeVMObject::SharedInodeVMObject(SharedInodeVMObject const& other)
 {
 {
 }
 }
 
 
+ErrorOr<void> 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 {};
+}
+
 }
 }

+ 2 - 0
Kernel/Memory/SharedInodeVMObject.h

@@ -18,6 +18,8 @@ public:
     static ErrorOr<NonnullRefPtr<SharedInodeVMObject>> try_create_with_inode(Inode&);
     static ErrorOr<NonnullRefPtr<SharedInodeVMObject>> try_create_with_inode(Inode&);
     virtual ErrorOr<NonnullRefPtr<VMObject>> try_clone() override;
     virtual ErrorOr<NonnullRefPtr<VMObject>> try_clone() override;
 
 
+    ErrorOr<void> sync();
+
 private:
 private:
     virtual bool is_shared_inode() const override { return true; }
     virtual bool is_shared_inode() const override { return true; }
 
 

+ 1 - 0
Kernel/Process.h

@@ -313,6 +313,7 @@ public:
     ErrorOr<FlatPtr> sys$mprotect(Userspace<void*>, size_t, int prot);
     ErrorOr<FlatPtr> sys$mprotect(Userspace<void*>, size_t, int prot);
     ErrorOr<FlatPtr> sys$madvise(Userspace<void*>, size_t, int advice);
     ErrorOr<FlatPtr> sys$madvise(Userspace<void*>, size_t, int advice);
     ErrorOr<FlatPtr> sys$msyscall(Userspace<void*>);
     ErrorOr<FlatPtr> sys$msyscall(Userspace<void*>);
+    ErrorOr<FlatPtr> sys$msync(Userspace<void*>, size_t, int flags);
     ErrorOr<FlatPtr> sys$purge(int mode);
     ErrorOr<FlatPtr> sys$purge(int mode);
     ErrorOr<FlatPtr> sys$select(Userspace<const Syscall::SC_select_params*>);
     ErrorOr<FlatPtr> sys$select(Userspace<const Syscall::SC_select_params*>);
     ErrorOr<FlatPtr> sys$poll(Userspace<const Syscall::SC_poll_params*>);
     ErrorOr<FlatPtr> sys$poll(Userspace<const Syscall::SC_poll_params*>);

+ 17 - 0
Kernel/Syscalls/mmap.cpp

@@ -589,4 +589,21 @@ ErrorOr<FlatPtr> Process::sys$msyscall(Userspace<void*> address)
     region->set_syscall_region(true);
     region->set_syscall_region(true);
     return 0;
     return 0;
 }
 }
+
+ErrorOr<FlatPtr> Process::sys$msync(Userspace<void*> 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<Memory::SharedInodeVMObject&>(vmobject);
+    TRY(inode_vmobject.sync());
+    return 0;
+}
+
 }
 }

+ 6 - 0
Userland/Libraries/LibC/sys/mman.cpp

@@ -89,4 +89,10 @@ int mlock(const void*, size_t)
     dbgln("FIXME: Implement mlock()");
     dbgln("FIXME: Implement mlock()");
     return 0;
     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);
+}
 }
 }

+ 1 - 0
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);
 int madvise(void*, size_t, int advice);
 void* allocate_tls(const char* initial_data, size_t);
 void* allocate_tls(const char* initial_data, size_t);
 int mlock(const void*, size_t);
 int mlock(const void*, size_t);
+int msync(void*, size_t, int flags);
 
 
 __END_DECLS
 __END_DECLS