summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendiadyoin1 <leon.a@serenityos.org>2022-06-18 18:38:31 +0200
committerAndreas Kling <kling@serenityos.org>2022-07-15 12:42:43 +0200
commit10d9bb93be15560f5a30e253028518109ca0c7c1 (patch)
treece833ef8cb9d1f7e8d1b9580ca598cceef081901
parentd783389877435ef937b4306ac689470a5ca576bb (diff)
downloadserenity-10d9bb93be15560f5a30e253028518109ca0c7c1.zip
Kernel: Handle multiple regions in sys$msync
-rw-r--r--Kernel/Syscalls/mmap.cpp38
1 files changed, 26 insertions, 12 deletions
diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp
index 998f4b1de5..8359709bc9 100644
--- a/Kernel/Syscalls/mmap.cpp
+++ b/Kernel/Syscalls/mmap.cpp
@@ -571,23 +571,37 @@ ErrorOr<FlatPtr> Process::sys$msync(Userspace<void*> address, size_t size, int f
// Note: This is not specified
auto rounded_size = TRY(Memory::page_round_up(size));
- // FIXME: We probably want to sync all mappings in the address+size range.
- auto* region = address_space().find_region_containing(Memory::VirtualRange { address.vaddr(), rounded_size });
+ auto regions = TRY(address_space().find_regions_intersecting(Memory::VirtualRange { address.vaddr(), rounded_size }));
// All regions from address upto address+size shall be mapped
- if (!region)
+ if (regions.is_empty())
return ENOMEM;
- auto& vmobject = region->vmobject();
- if (!vmobject.is_shared_inode())
- return 0;
+ size_t total_intersection_size = 0;
+ Memory::VirtualRange range_to_sync { address.vaddr(), rounded_size };
+ for (auto const* region : regions) {
+ // Region was not mapped
+ if (!region->is_mmap())
+ return ENOMEM;
+ total_intersection_size += region->range().intersect(range_to_sync).size();
+ }
+ // Part of the indicated range was not mapped
+ if (total_intersection_size != size)
+ return ENOMEM;
+
+ for (auto* region : regions) {
+ auto& vmobject = region->vmobject();
+ if (!vmobject.is_shared_inode())
+ continue;
- off_t offset = region->offset_in_vmobject() + address.ptr() - region->range().base().get();
+ off_t offset = region->offset_in_vmobject() + address.ptr() - region->range().base().get();
- auto& inode_vmobject = static_cast<Memory::SharedInodeVMObject&>(vmobject);
- // FIXME: Handle MS_ASYNC
- TRY(inode_vmobject.sync(offset / PAGE_SIZE, size / PAGE_SIZE));
- // FIXME: Handle MS_INVALIDATE
- // FIXME: If msync() causes any write to a file, the file's st_ctime and st_mtime fields shall be marked for update.
+ auto& inode_vmobject = static_cast<Memory::SharedInodeVMObject&>(vmobject);
+ // FIXME: If multiple regions belong to the same vmobject we might want to coalesce these writes
+ // FIXME: Handle MS_ASYNC
+ TRY(inode_vmobject.sync(offset / PAGE_SIZE, rounded_size / PAGE_SIZE));
+ // FIXME: Handle MS_INVALIDATE
+ // FIXME: If msync() causes any write to a file, the file's st_ctime and st_mtime fields shall be marked for update.
+ }
return 0;
}