Serenity Operating System
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Kernel: Implement basic support for sys$mmap() with MAP_PRIVATE

You can now mmap a file as private and writable, and the changes you
make will only be visible to you.

This works because internally a MAP_PRIVATE region is backed by a
unique PrivateInodeVMObject instead of using the globally shared
SharedInodeVMObject like we always did before. :^)

Fixes #1045.

+44 -30
+3 -1
Kernel/Devices/BXVGADevice.cpp
··· 166 166 return framebuffer_address; 167 167 } 168 168 169 - KResultOr<Region*> BXVGADevice::mmap(Process& process, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot) 169 + KResultOr<Region*> BXVGADevice::mmap(Process& process, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) 170 170 { 171 171 REQUIRE_PROMISE(video); 172 + if (!shared) 173 + return KResult(-ENODEV); 172 174 ASSERT(offset == 0); 173 175 ASSERT(size == framebuffer_size_in_bytes()); 174 176 auto vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, framebuffer_size_in_bytes());
+1 -1
Kernel/Devices/BXVGADevice.h
··· 41 41 BXVGADevice(); 42 42 43 43 virtual int ioctl(FileDescription&, unsigned request, unsigned arg) override; 44 - virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t, int prot) override; 44 + virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t, int prot, bool shared) override; 45 45 46 46 private: 47 47 virtual const char* class_name() const override { return "BXVGA"; }
+3 -1
Kernel/Devices/MBVGADevice.cpp
··· 51 51 s_the = this; 52 52 } 53 53 54 - KResultOr<Region*> MBVGADevice::mmap(Process& process, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot) 54 + KResultOr<Region*> MBVGADevice::mmap(Process& process, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) 55 55 { 56 56 REQUIRE_PROMISE(video); 57 + if (!shared) 58 + return KResult(-ENODEV); 57 59 ASSERT(offset == 0); 58 60 ASSERT(size == framebuffer_size_in_bytes()); 59 61 auto vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, framebuffer_size_in_bytes());
+1 -1
Kernel/Devices/MBVGADevice.h
··· 41 41 MBVGADevice(PhysicalAddress addr, int pitch, int width, int height); 42 42 43 43 virtual int ioctl(FileDescription&, unsigned request, unsigned arg) override; 44 - virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t, int prot) override; 44 + virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t, int prot, bool shared) override; 45 45 46 46 private: 47 47 virtual const char* class_name() const override { return "MBVGA"; }
+1 -1
Kernel/FileSystem/File.cpp
··· 54 54 return -ENOTTY; 55 55 } 56 56 57 - KResultOr<Region*> File::mmap(Process&, FileDescription&, VirtualAddress, size_t, size_t, int) 57 + KResultOr<Region*> File::mmap(Process&, FileDescription&, VirtualAddress, size_t, size_t, int, bool) 58 58 { 59 59 return KResult(-ENODEV); 60 60 }
+1 -1
Kernel/FileSystem/File.h
··· 77 77 virtual ssize_t read(FileDescription&, u8*, ssize_t) = 0; 78 78 virtual ssize_t write(FileDescription&, const u8*, ssize_t) = 0; 79 79 virtual int ioctl(FileDescription&, unsigned request, unsigned arg); 80 - virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot); 80 + virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared); 81 81 82 82 virtual String absolute_path(const FileDescription&) const = 0; 83 83
+2 -2
Kernel/FileSystem/FileDescription.cpp
··· 281 281 return {}; 282 282 } 283 283 284 - KResultOr<Region*> FileDescription::mmap(Process& process, VirtualAddress vaddr, size_t offset, size_t size, int prot) 284 + KResultOr<Region*> FileDescription::mmap(Process& process, VirtualAddress vaddr, size_t offset, size_t size, int prot, bool shared) 285 285 { 286 286 LOCKER(m_lock); 287 - return m_file->mmap(process, *this, vaddr, offset, size, prot); 287 + return m_file->mmap(process, *this, vaddr, offset, size, prot, shared); 288 288 } 289 289 290 290 KResult FileDescription::truncate(u64 length)
+1 -1
Kernel/FileSystem/FileDescription.h
··· 109 109 Custody* custody() { return m_custody.ptr(); } 110 110 const Custody* custody() const { return m_custody.ptr(); } 111 111 112 - KResultOr<Region*> mmap(Process&, VirtualAddress, size_t offset, size_t, int prot); 112 + KResultOr<Region*> mmap(Process&, VirtualAddress, size_t offset, size_t, int prot, bool shared); 113 113 114 114 bool is_blocking() const { return m_is_blocking; } 115 115 void set_blocking(bool b) { m_is_blocking = b; }
+10 -2
Kernel/FileSystem/InodeFile.cpp
··· 29 29 #include <Kernel/FileSystem/InodeFile.h> 30 30 #include <Kernel/FileSystem/VirtualFileSystem.h> 31 31 #include <Kernel/Process.h> 32 + #include <Kernel/VM/PrivateInodeVMObject.h> 32 33 #include <Kernel/VM/SharedInodeVMObject.h> 33 34 34 35 namespace Kernel { ··· 60 61 return nwritten; 61 62 } 62 63 63 - KResultOr<Region*> InodeFile::mmap(Process& process, FileDescription& description, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot) 64 + KResultOr<Region*> InodeFile::mmap(Process& process, FileDescription& description, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) 64 65 { 65 66 ASSERT(offset == 0); 66 67 // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. 67 - auto* region = process.allocate_region_with_vmobject(preferred_vaddr, size, SharedInodeVMObject::create_with_inode(inode()), offset, description.absolute_path(), prot); 68 + RefPtr<InodeVMObject> vmobject; 69 + if (shared) 70 + vmobject = SharedInodeVMObject::create_with_inode(inode()); 71 + else 72 + vmobject = PrivateInodeVMObject::create_with_inode(inode()); 73 + if (!vmobject) 74 + return KResult(-ENOMEM); 75 + auto* region = process.allocate_region_with_vmobject(preferred_vaddr, size, *vmobject, offset, description.absolute_path(), prot); 68 76 if (!region) 69 77 return KResult(-ENOMEM); 70 78 return region;
+1 -1
Kernel/FileSystem/InodeFile.h
··· 49 49 50 50 virtual ssize_t read(FileDescription&, u8*, ssize_t) override; 51 51 virtual ssize_t write(FileDescription&, const u8*, ssize_t) override; 52 - virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot) override; 52 + virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) override; 53 53 54 54 virtual String absolute_path(const FileDescription&) const override; 55 55
+20 -18
Kernel/Process.cpp
··· 321 321 return true; 322 322 } 323 323 324 - static bool validate_inode_mmap_prot(const Process& process, int prot, const Inode& inode) 324 + static bool validate_inode_mmap_prot(const Process& process, int prot, const Inode& inode, bool map_shared) 325 325 { 326 326 auto metadata = inode.metadata(); 327 - if ((prot & PROT_WRITE) && !metadata.may_write(process)) 328 - return false; 329 327 if ((prot & PROT_READ) && !metadata.may_read(process)) 330 328 return false; 331 - InterruptDisabler disabler; 332 - if (inode.shared_vmobject()) { 333 - if ((prot & PROT_EXEC) && inode.shared_vmobject()->writable_mappings()) 329 + 330 + if (map_shared) { 331 + if ((prot & PROT_WRITE) && !metadata.may_write(process)) 334 332 return false; 335 - if ((prot & PROT_WRITE) && inode.shared_vmobject()->executable_mappings()) 336 - return false; 333 + InterruptDisabler disabler; 334 + if (inode.shared_vmobject()) { 335 + if ((prot & PROT_EXEC) && inode.shared_vmobject()->writable_mappings()) 336 + return false; 337 + if ((prot & PROT_WRITE) && inode.shared_vmobject()->executable_mappings()) 338 + return false; 339 + } 337 340 } 338 341 return true; 339 342 } ··· 433 436 return (void*)-EINVAL; 434 437 if (static_cast<size_t>(offset) & ~PAGE_MASK) 435 438 return (void*)-EINVAL; 436 - // FIXME: Implement MAP_PRIVATE for FileDescription-backed mmap 437 - if (map_private) 438 - return (void*)-ENOTSUP; 439 439 auto description = file_description(fd); 440 440 if (!description) 441 441 return (void*)-EBADF; ··· 443 443 return (void*)-ENODEV; 444 444 if ((prot & PROT_READ) && !description->is_readable()) 445 445 return (void*)-EACCES; 446 - if ((prot & PROT_WRITE) && !description->is_writable()) 447 - return (void*)-EACCES; 446 + if (map_shared) { 447 + if ((prot & PROT_WRITE) && !description->is_writable()) 448 + return (void*)-EACCES; 449 + } 448 450 if (description->inode()) { 449 - if (!validate_inode_mmap_prot(*this, prot, *description->inode())) 451 + if (!validate_inode_mmap_prot(*this, prot, *description->inode(), map_shared)) 450 452 return (void*)-EACCES; 451 453 } 452 - auto region_or_error = description->mmap(*this, VirtualAddress(addr), static_cast<size_t>(offset), size, prot); 454 + auto region_or_error = description->mmap(*this, VirtualAddress(addr), static_cast<size_t>(offset), size, prot, map_shared); 453 455 if (region_or_error.is_error()) { 454 456 // Fail if MAP_FIXED or address is 0, retry otherwise 455 457 if (map_fixed || addr == 0) 456 458 return (void*)(int)region_or_error.error(); 457 - region_or_error = description->mmap(*this, {}, static_cast<size_t>(offset), size, prot); 459 + region_or_error = description->mmap(*this, {}, static_cast<size_t>(offset), size, prot, map_shared); 458 460 } 459 461 if (region_or_error.is_error()) 460 462 return (void*)(int)region_or_error.error(); ··· 537 539 if (whole_region->access() == prot_to_region_access_flags(prot)) 538 540 return 0; 539 541 if (whole_region->vmobject().is_inode() 540 - && !validate_inode_mmap_prot(*this, prot, static_cast<const SharedInodeVMObject&>(whole_region->vmobject()).inode())) { 542 + && !validate_inode_mmap_prot(*this, prot, static_cast<const SharedInodeVMObject&>(whole_region->vmobject()).inode(), whole_region->is_shared())) { 541 543 return -EACCES; 542 544 } 543 545 whole_region->set_readable(prot & PROT_READ); ··· 556 558 if (old_region->access() == prot_to_region_access_flags(prot)) 557 559 return 0; 558 560 if (old_region->vmobject().is_inode() 559 - && !validate_inode_mmap_prot(*this, prot, static_cast<const SharedInodeVMObject&>(old_region->vmobject()).inode())) { 561 + && !validate_inode_mmap_prot(*this, prot, static_cast<const SharedInodeVMObject&>(old_region->vmobject()).inode(), old_region->is_shared())) { 560 562 return -EACCES; 561 563 } 562 564