From 7c559d785adc90a255aa74a1d362fa074ae14482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ha=C5=82as?= Date: Fri, 4 Sep 2026 23:05:34 +0200 Subject: [PATCH] ext/opcache: drop the pre-emptive munmap before the huge page remap create_segments() reserved requested_size + huge_page_size, unmapped the whole reservation, and only then MAP_FIXED-mapped the huge pages at the aligned address inside it. That munmap is unnecessary: MAP_FIXED replaces the overlapped part of the reservation atomically. It also opens a window in which another thread can map something at that address before the remap runs. Keep the reservation, map the huge pages into it, and release only the head and the tail that are left over. Their sizes always add up to exactly huge_page_size, because the reservation is requested_size + huge_page_size and the mapping is requested_size. When the remap fails the whole reservation is released before falling back to normal pages: the kernel may already have discarded the overlapped part, so the reservation cannot be reused. Suggested by Arnaud Le Blanc in GH-23554. --- ext/opcache/shared_alloc_mmap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 4825da3e4c01..b7ef52ac5d63 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -245,12 +245,18 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_ p = mmap(NULL, requested_size + huge_page_size, flags, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT, fd, 0); if (p != MAP_FAILED) { - munmap(p, requested_size + huge_page_size); + void *reserved = p; p = (void*)(ZEND_MM_ALIGNED_SIZE_EX((ptrdiff_t)p, huge_page_size)); p = mmap(p, requested_size, flags, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT|MAP_HUGETLB|MAP_FIXED, -1, 0); if (p != MAP_FAILED) { + size_t head = (char*)p - (char*)reserved; + if (head != 0) { + munmap(reserved, head); + } + munmap((char*)p + requested_size, huge_page_size - head); goto success; } else { + munmap(reserved, requested_size + huge_page_size); p = mmap(NULL, requested_size, flags, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT, fd, 0); if (p != MAP_FAILED) { goto success;