mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:17:44 +00:00
Kernel+UE: Add MAP_FIXED_NOREPLACE mmap() flag
This feature was introduced in version 4.17 of the Linux kernel, and while it's not specified by POSIX, I think it will be a nice addition to our system. MAP_FIXED_NOREPLACE provides a less error-prone alternative to MAP_FIXED: while regular fixed mappings would cause any intersecting ranges to be unmapped, MAP_FIXED_NOREPLACE returns EEXIST instead. This ensures that we don't corrupt our process's address space if something is already at the requested address. Note that the more portable way to do this is to use regular MAP_ANONYMOUS, and check afterwards whether the returned address matches what we wanted. This, however, has a large performance impact on programs like Wine which try to reserve large portions of the address space at once, as the non-matching addresses have to be unmapped separately.
This commit is contained in:
parent
4195a7ef4b
commit
77f9272aaf
6 changed files with 18 additions and 15 deletions
|
@ -135,7 +135,7 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> use
|
|||
REQUIRE_PROMISE(prot_exec);
|
||||
}
|
||||
|
||||
if (prot & MAP_FIXED) {
|
||||
if (prot & MAP_FIXED || prot & MAP_FIXED_NOREPLACE) {
|
||||
REQUIRE_PROMISE(map_fixed);
|
||||
}
|
||||
|
||||
|
@ -167,6 +167,7 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> use
|
|||
bool map_fixed = flags & MAP_FIXED;
|
||||
bool map_noreserve = flags & MAP_NORESERVE;
|
||||
bool map_randomized = flags & MAP_RANDOMIZED;
|
||||
bool map_fixed_noreplace = flags & MAP_FIXED_NOREPLACE;
|
||||
|
||||
if (map_shared && map_private)
|
||||
return EINVAL;
|
||||
|
@ -174,7 +175,7 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> use
|
|||
if (!map_shared && !map_private)
|
||||
return EINVAL;
|
||||
|
||||
if (map_fixed && map_randomized)
|
||||
if ((map_fixed || map_fixed_noreplace) && map_randomized)
|
||||
return EINVAL;
|
||||
|
||||
if (!validate_mmap_prot(prot, map_stack, map_anonymous))
|
||||
|
@ -186,19 +187,18 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> use
|
|||
Memory::Region* region = nullptr;
|
||||
|
||||
auto range = TRY([&]() -> ErrorOr<Memory::VirtualRange> {
|
||||
if (map_randomized) {
|
||||
if (map_randomized)
|
||||
return address_space().page_directory().range_allocator().try_allocate_randomized(Memory::page_round_up(size), alignment);
|
||||
}
|
||||
|
||||
// If MAP_FIXED is specified, existing mappings that intersect the requested range are removed.
|
||||
if (map_fixed)
|
||||
TRY(address_space().unmap_mmap_range(VirtualAddress(addr), size));
|
||||
|
||||
auto range = address_space().try_allocate_range(VirtualAddress(addr), size, alignment);
|
||||
if (range.is_error()) {
|
||||
if (addr && !map_fixed) {
|
||||
if (addr && !(map_fixed || map_fixed_noreplace)) {
|
||||
// If there's an address but MAP_FIXED wasn't specified, the address is just a hint.
|
||||
range = address_space().try_allocate_range({}, size, alignment);
|
||||
} else if (map_fixed) {
|
||||
// If MAP_FIXED is specified, existing mappings that intersect the requested range are removed.
|
||||
TRY(address_space().unmap_mmap_range(VirtualAddress(addr), size));
|
||||
range = address_space().try_allocate_range(VirtualAddress(addr), size, alignment);
|
||||
}
|
||||
}
|
||||
return range;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue