BUG #19719: BUG: huge_pages=on shared memory reattached without FILE_MAP_LARGE_PAGES on Windows

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: s-mitsufuji(at)nec(dot)com
Subject: BUG #19719: BUG: huge_pages=on shared memory reattached without FILE_MAP_LARGE_PAGES on Windows
Date: 2026-09-25 04:39:16
Message-ID: 19719-9eea21ac8841c776@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19719
Logged by: Satoshi Mitsufuji
Email address: s-mitsufuji(at)nec(dot)com
PostgreSQL version: 18.6
Operating system: Windows 11
Description:

PostgreSQL version: 18.6 (also affects master and any branch since
large-page support for Windows shared memory was introduced)
OS: Windows 10/11 x86_64, msvc build
huge_pages = on

Description
-----------
On Windows, when huge_pages=on, PGSharedMemoryCreate() (win32_shmem.c)
correctly creates the shared memory section with SEC_LARGE_PAGES and
maps the postmaster's own view with FILE_MAP_LARGE_PAGES:

if ((flProtect & SEC_LARGE_PAGES) != 0)
desiredAccess |= FILE_MAP_LARGE_PAGES;
memAddress = MapViewOfFileEx(hmap2, desiredAccess, 0, 0, 0, NULL);

However, every other backend process re-attaches to the same section
via PGSharedMemoryReAttach(), which calls MapViewOfFileEx() with only
FILE_MAP_READ | FILE_MAP_WRITE -- FILE_MAP_LARGE_PAGES is never
requested there. As a result, only the postmaster's own view of shared
memory is backed by large pages; every backend, walsender, autovacuum
worker, etc. maps the same physical section as ordinary 4KB pages.

Because Windows requires FILE_MAP_LARGE_PAGES on MapViewOfFileEx when
the underlying section was created with SEC_LARGE_PAGES (mirroring the
requirement added for CreateFileMapping in commit fdd8937c, see also
bug #17448), this looks like an oversight in that same fix: the
postmaster side was updated, but PGSharedMemoryReAttach() was not.

Evidence
--------
Using Sysinternals VMMap on the shared memory VA range in both the
postmaster and a backend process (huge_pages=on, shared_buffers=256MB,
segment size 292,864 KB):

Postmaster view of the segment:
Total WS : 292,864 K (100% of the segment, resident immediately)
Locked : 292,864 K
Process Page Table size: ~244-276 K

Backend view of the *same* segment, before fix:
Total WS : 1,668 K (only touched pages faulted in)
Locked : (column not present -- not large-page backed)
Process Page Table size: ~840 K (comparable to a plain
huge_pages=off backend, ~816-840 K)

The backend's page table consumption and lazily-faulted working set
are indistinguishable from a huge_pages=off run, indicating the
backend is using standard 4KB PTEs for this mapping despite
huge_pages=on and despite the section itself being backed by large
pages.

RAMMap's "Large Page" counter does not reflect this at all (stays at
0 K in both configurations), which is presumably why this has not
been noticed via that tool; VMMap's per-VAD Locked/WS accounting is
what exposes it.

Proposed fix
------------
Request FILE_MAP_LARGE_PAGES in PGSharedMemoryReAttach() as well,
falling back to a plain mapping if the section was not created with
SEC_LARGE_PAGES (huge_pages=off, or huge_pages=try that fell back to
normal pages):

--- win32_shmem_originalg.c
+++ win32_shmem_modified_20260922.c
@@ -440,7 +440,17 @@
if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
elog(FATAL, "failed to release reserved memory region
(addr=%p): error code %lu",
UsedShmemSegAddr, GetLastError());

+#ifdef FILE_MAP_LARGE_PAGES
+ /*
+ * Try to reattach with FILE_MAP_LARGE_PAGES first. This will fail
with
+ * ERROR_INVALID_PARAMETER if the segment was not created with
+ * SEC_LARGE_PAGES (i.e. huge_pages was off, or fell back to normal
+ * pages under huge_pages=try). In that case, retry without the
flag.
+ */
+ hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID,
FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_LARGE_PAGES, 0, 0, 0,
UsedShmemSegAddr);
+ if (!hdr)
+ hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID,
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
+#else
hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID,
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
+#endif
if (!hdr)
elog(FATAL, "could not reattach to shared memory (key=%p,
addr=%p): error code %lu",
UsedShmemSegID, UsedShmemSegAddr, GetLastError());

I've tested this patch with both huge_pages=on and huge_pages=off:

- huge_pages=off: server starts normally. The first
MapViewOfFileEx() attempt (with FILE_MAP_LARGE_PAGES) fails as
expected since the section has no SEC_LARGE_PAGES, and the
fallback call succeeds -- no FATAL errors, no crash loop.

- huge_pages=on: backends now show Total WS == segment size and
Locked == segment size for the shared memory VAD in VMMap,
matching the postmaster, instead of the partial/non-locked view
seen before the fix.

Browse pgsql-bugs by date

  From Date Subject
Next Message shihao zhong 2026-09-25 04:59:59 Re: BUG #19699: LIKE with a trailing escape fails to raise SQLSTATE 22025 for empty input
Previous Message shihao zhong 2026-09-25 04:37:21 Re: BUG #19714: pgcrypto pgp_sym_encrypt accepts nonnumeric s2k-mode as mode 0