From 457a02a974f7077916e86fe0cdfc3e3a8fd26804 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Fri, 30 Oct 2026 11:56:27 +0530
Subject: [PATCH v20261030 2/2] Record the main shared memory segment's page
 size

pg_get_shmem_pagesize() currently determines the page size independently
of the code that creates the main shared memory segment. This duplicates
platform-specific logic and allows the two implementations to diverge.
For example, before the previous commit, on Windows it returned zero
when large pages are in use, because GetHugePageSize() is a stub on that
platform. The only current caller of pg_get_shmem_pagesize() rejects
unsupported NUMA configurations before reaching this code, so it does
not encounter the problem on Windows.

Record the page size in the shared memory header when creating the
segment, and have pg_get_shmem_pagesize() return that value. Record the
size used by the successful allocation, including ordinary-page fallback
when huge_pages=try. The value remains constant for the mapping's
lifetime and is initialized anew if shared memory is recreated.

This also avoids repeated page-size discovery. In particular, on Linux,
each call with huge pages enabled previously opened and scanned
/proc/meminfo.

The proposed resizable shared memory support will need the page size
during shared structure resizing, using this reliable, inexpensive
function more.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: TBD
Discussion: https://postgr.es/m/<message-id-TBD>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 src/backend/port/sysv_shmem.c   | 12 +++++++++---
 src/backend/port/win32_shmem.c  |  9 +++++++++
 src/backend/storage/ipc/shmem.c | 27 +++++----------------------
 src/include/storage/pg_shmem.h  |  2 ++
 4 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 2e3886cf9fe..0605e6e3772 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -594,10 +594,10 @@ check_huge_page_size(int *newval, void **extra, GucSource source)
  *
  * Pass the requested size in *size.  This function will modify *size to the
  * actual size of the allocation, if it ends up allocating a segment that is
- * larger than requested.
+ * larger than requested.  The memory page size used is returned in *page_size.
  */
 static void *
-CreateAnonymousSegment(Size *size)
+CreateAnonymousSegment(Size *size, Size *page_size)
 {
 	Size		allocsize = *size;
 	void	   *ptr = MAP_FAILED;
@@ -624,6 +624,8 @@ CreateAnonymousSegment(Size *size)
 		ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
 				   mmap_flags | huge_mmap_flags, -1, 0);
 		mmap_errno = errno;
+		if (ptr != MAP_FAILED)
+			*page_size = hugepagesize;
 		if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED)
 			elog(DEBUG1, "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m",
 				 allocsize);
@@ -648,6 +650,7 @@ CreateAnonymousSegment(Size *size)
 		ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
 				   mmap_flags, -1, 0);
 		mmap_errno = errno;
+		*page_size = sysconf(_SC_PAGESIZE);
 	}
 
 	if (ptr == MAP_FAILED)
@@ -707,6 +710,7 @@ PGSharedMemoryCreate(Size size,
 	PGShmemHeader *hdr;
 	struct stat statbuf;
 	Size		sysvsize;
+	Size		page_size;
 
 	/*
 	 * We use the data directory's ID info (inode and device numbers) to
@@ -738,7 +742,7 @@ PGSharedMemoryCreate(Size size,
 
 	if (shared_memory_type == SHMEM_TYPE_MMAP)
 	{
-		AnonymousShmem = CreateAnonymousSegment(&size);
+		AnonymousShmem = CreateAnonymousSegment(&size, &page_size);
 		AnonymousShmemSize = size;
 
 		/* Register on-exit routine to unmap the anonymous segment */
@@ -750,6 +754,7 @@ PGSharedMemoryCreate(Size size,
 	else
 	{
 		sysvsize = size;
+		page_size = sysconf(_SC_PAGESIZE);
 
 		/* huge pages are only available with mmap */
 		SetConfigOption("huge_pages_status", "off",
@@ -855,6 +860,7 @@ PGSharedMemoryCreate(Size size,
 	 * Initialize space allocation status for segment.
 	 */
 	hdr->totalsize = size;
+	hdr->page_size = page_size;
 	hdr->content_offset = MAXALIGN(sizeof(PGShmemHeader));
 	*shim = hdr;
 
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index 794e4fcb2ad..e842adce7e0 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -391,6 +391,15 @@ retry:
 	hdr->totalsize = size;
 	hdr->content_offset = MAXALIGN(sizeof(PGShmemHeader));
 	hdr->dsm_control = 0;
+	if (flProtect & SEC_LARGE_PAGES)
+		hdr->page_size = largePageSize;
+	else
+	{
+		SYSTEM_INFO sysinfo;
+
+		GetSystemInfo(&sysinfo);
+		hdr->page_size = sysinfo.dwPageSize;
+	}
 
 	/* Save info for possible future use */
 	UsedShmemSegAddr = memAddress;
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 2d944e21ab8..2b8681a7cd9 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -1367,36 +1367,19 @@ pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
 }
 
 /*
- * Determine the memory page size used for the shared memory segment.
+ * Return the memory page size used to create the main shared memory segment.
  *
- * If the shared segment was allocated using huge pages, returns the size of
- * a huge page. Otherwise returns the size of regular memory page.
+ * This function avoids exposing the ShmemSegHdr structure directly.
  *
  * This should be used only after shared memory has been initialized.
  */
 Size
 pg_get_shmem_pagesize(void)
 {
-	Size		os_page_size;
-#ifdef WIN32
-	SYSTEM_INFO sysinfo;
-
-	GetSystemInfo(&sysinfo);
-	os_page_size = sysinfo.dwPageSize;
-#else
-	os_page_size = sysconf(_SC_PAGESIZE);
-#endif
-
-	Assert(huge_pages_status != HUGE_PAGES_UNKNOWN);
-
-	if (huge_pages_status == HUGE_PAGES_ON)
-#ifdef WIN32
-		os_page_size = GetLargePageMinimum();
-#else
-		GetHugePageSize(&os_page_size, NULL);
-#endif
+	Assert(ShmemSegHdr != NULL);
+	Assert(ShmemSegHdr->page_size > 0);
 
-	return os_page_size;
+	return ShmemSegHdr->page_size;
 }
 
 Datum
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index 10c7b065861..ef2c87a97de 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -39,6 +39,8 @@ typedef struct PGShmemHeader	/* standard header for all Postgres shmem */
 	dev_t		device;			/* device data directory is on */
 	ino_t		inode;			/* inode number of data directory */
 #endif
+	Size		page_size;		/* size of each memory page backing this
+								 * segment. */
 } PGShmemHeader;
 
 /* GUC variables */
-- 
2.34.1

