From 60e755210c574b9e5ba06ad5f1dfe1d8a7ce4bc7 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 22 Nov 2023 22:44:06 +0200 Subject: [PATCH] Kernel/LibC: Implement very basic msync --- .../include/kernel/Memory/FileBackedRegion.h | 4 ++ .../kernel/Memory/MemoryBackedRegion.h | 3 +- kernel/include/kernel/Memory/MemoryRegion.h | 2 + kernel/include/kernel/Process.h | 1 + kernel/kernel/Memory/FileBackedRegion.cpp | 50 +++++++++++++++---- kernel/kernel/Process.cpp | 18 +++++++ kernel/kernel/Syscall.cpp | 3 ++ libc/include/sys/syscall.h | 1 + libc/sys/mman.cpp | 5 ++ 9 files changed, 75 insertions(+), 12 deletions(-) diff --git a/kernel/include/kernel/Memory/FileBackedRegion.h b/kernel/include/kernel/Memory/FileBackedRegion.h index 8943197cb7..45cf9f41ac 100644 --- a/kernel/include/kernel/Memory/FileBackedRegion.h +++ b/kernel/include/kernel/Memory/FileBackedRegion.h @@ -10,6 +10,8 @@ namespace Kernel { ~SharedFileData(); + void sync(size_t page_index); + // FIXME: this should probably be ordered tree like map // for fast lookup and less memory usage BAN::Vector pages; @@ -26,6 +28,8 @@ namespace Kernel static BAN::ErrorOr> create(BAN::RefPtr, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t); ~FileBackedRegion(); + virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override; + virtual BAN::ErrorOr> clone(PageTable& new_page_table) override; protected: diff --git a/kernel/include/kernel/Memory/MemoryBackedRegion.h b/kernel/include/kernel/Memory/MemoryBackedRegion.h index 0b778f0c6b..087bdd7363 100644 --- a/kernel/include/kernel/Memory/MemoryBackedRegion.h +++ b/kernel/include/kernel/Memory/MemoryBackedRegion.h @@ -14,9 +14,10 @@ namespace Kernel static BAN::ErrorOr> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t); ~MemoryBackedRegion(); - virtual BAN::ErrorOr> clone(PageTable& new_page_table) override; + virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override { return {}; } + // Copy data from buffer into this region // This can fail if no memory is mapped and no free memory was available BAN::ErrorOr copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size); diff --git a/kernel/include/kernel/Memory/MemoryRegion.h b/kernel/include/kernel/Memory/MemoryRegion.h index 99a3078d5f..9bd4de7a1f 100644 --- a/kernel/include/kernel/Memory/MemoryRegion.h +++ b/kernel/include/kernel/Memory/MemoryRegion.h @@ -40,6 +40,8 @@ namespace Kernel size_t virtual_page_count() const { return BAN::Math::div_round_up(m_size, PAGE_SIZE); } size_t physical_page_count() const { return m_physical_page_count; } + virtual BAN::ErrorOr msync(vaddr_t, size_t, int) = 0; + // Returns error if no memory was available // Returns true if page was succesfully allocated // Returns false if page was already allocated diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 92cfc37f1e..067ae4ad69 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -130,6 +130,7 @@ namespace Kernel BAN::ErrorOr sys_mmap(const sys_mmap_t*); BAN::ErrorOr sys_munmap(void* addr, size_t len); + BAN::ErrorOr sys_msync(void* addr, size_t len, int flags); BAN::ErrorOr sys_tty_ctrl(int fildes, int command, int flags); diff --git a/kernel/kernel/Memory/FileBackedRegion.cpp b/kernel/kernel/Memory/FileBackedRegion.cpp index 97742cf05d..1d09795b0d 100644 --- a/kernel/kernel/Memory/FileBackedRegion.cpp +++ b/kernel/kernel/Memory/FileBackedRegion.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace Kernel { @@ -46,7 +48,7 @@ namespace Kernel , m_offset(offset) { } - + FileBackedRegion::~FileBackedRegion() { if (m_vaddr == 0) @@ -70,19 +72,45 @@ namespace Kernel { if (pages[i] == 0) continue; - - { - CriticalScope _; - PageTable::map_fast_page(pages[i]); - memcpy(page_buffer, PageTable::fast_page_as_ptr(), PAGE_SIZE); - PageTable::unmap_fast_page(); - } - - if (auto ret = inode->write(i * PAGE_SIZE, BAN::ConstByteSpan::from(page_buffer)); ret.is_error()) - dwarnln("{}", ret.error()); + sync(i); } } + void SharedFileData::sync(size_t page_index) + { + // FIXME: should this be locked? + + if (pages[page_index] == 0) + return; + + { + CriticalScope _; + PageTable::with_fast_page(pages[page_index], [&] { + memcpy(page_buffer, PageTable::fast_page_as_ptr(), PAGE_SIZE); + }); + } + + if (auto ret = inode->write(page_index * PAGE_SIZE, BAN::ConstByteSpan::from(page_buffer)); ret.is_error()) + dwarnln("{}", ret.error()); + } + + BAN::ErrorOr FileBackedRegion::msync(vaddr_t address, size_t size, int flags) + { + if (flags != MS_SYNC) + return BAN::Error::from_errno(ENOTSUP); + if (m_type != Type::SHARED) + return {}; + + vaddr_t first_page = address & PAGE_ADDR_MASK; + vaddr_t last_page = BAN::Math::div_round_up(address + size, PAGE_SIZE) * PAGE_SIZE; + + for (vaddr_t page_addr = first_page; page_addr < last_page; page_addr += PAGE_SIZE) + if (contains(page_addr)) + m_shared_data->sync((page_addr - m_vaddr) / PAGE_SIZE); + + return {}; + } + BAN::ErrorOr FileBackedRegion::allocate_page_containing_impl(vaddr_t address) { ASSERT(contains(address)); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index c709741f78..121fa10736 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1098,6 +1098,24 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_msync(void* addr, size_t len, int flags) + { + if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE) + return BAN::Error::from_errno(EINVAL); + + vaddr_t vaddr = (vaddr_t)addr; + if (vaddr % PAGE_SIZE != 0) + return BAN::Error::from_errno(EINVAL); + + LockGuard _(m_lock); + + for (auto& mapped_region : m_mapped_regions) + if (mapped_region->overlaps(vaddr, len)) + TRY(mapped_region->msync(vaddr, len, flags)); + + return 0; + } + BAN::ErrorOr Process::sys_tty_ctrl(int fildes, int command, int flags) { LockGuard _(m_lock); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index b3c574cdb5..f7613b2f2d 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -217,6 +217,9 @@ namespace Kernel case SYS_READLINKAT: ret = Process::current().sys_readlinkat((int)arg1, (const char*)arg2, (char*)arg3, (size_t)arg4); break; + case SYS_MSYNC: + ret = Process::current().sys_msync((void*)arg1, (size_t)arg2, (int)arg3); + break; default: dwarnln("Unknown syscall {}", syscall); break; diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index b07079a4a4..3a8c9d9551 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -61,6 +61,7 @@ __BEGIN_DECLS #define SYS_UNLINK 58 #define SYS_READLINK 59 #define SYS_READLINKAT 60 +#define SYS_MSYNC 61 __END_DECLS diff --git a/libc/sys/mman.cpp b/libc/sys/mman.cpp index c43ecf3fb7..f08a002217 100644 --- a/libc/sys/mman.cpp +++ b/libc/sys/mman.cpp @@ -22,3 +22,8 @@ int munmap(void* addr, size_t len) { return syscall(SYS_MUNMAP, addr, len); } + +int msync(void* addr, size_t len, int flags) +{ + return syscall(SYS_MSYNC, addr, len, flags); +}