From 65145d500725db28c27abf1a4a73c535675abd1a Mon Sep 17 00:00:00 2001
From: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Date: Mon, 27 Oct 2025 10:10:32 +0100
Subject: Extract HugePages_Free value in GetHugePageSize

Currently, GetHugePageSize only extracts the huge page size from
/proc/meminfo. This patch adds the extraction of HugePages_Free which
will be necessary to auto-tune shared_buffers.
---
 src/backend/port/sysv_shmem.c   | 23 ++++++++++++++++-------
 src/backend/port/win32_shmem.c  |  4 +++-
 src/backend/storage/ipc/ipci.c  |  2 +-
 src/backend/storage/ipc/shmem.c |  2 +-
 src/include/storage/pg_shmem.h  |  2 +-
 5 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index de491897118..09a02271a15 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -470,18 +470,19 @@ PGSharedMemoryAttach(IpcMemoryId shmId,
  * hugepage sizes, we might want to think about more invasive strategies,
  * such as increasing shared_buffers to absorb the extra space.
  *
- * Returns the (real, assumed or config provided) page size into
- * *hugepagesize, and the hugepage-related mmap flags to use into
- * *mmap_flags if requested by the caller.  If huge pages are not supported,
- * *hugepagesize and *mmap_flags are set to 0.
+ * Returns the (real, assumed or config provided) page size into *hugepagesize,
+ * the amount of free huge pages into *hugepagefree, and the hugepage-related
+ * mmap flags to use into *mmap_flags if requested by the caller.  If huge pages
+ * are not supported, *hugepagesize, *hugepagefree and *mmap_flags are set to 0.
  */
 void
-GetHugePageSize(Size *hugepagesize, int *mmap_flags)
+GetHugePageSize(Size *hugepagesize, Size *hugepagefree, int *mmap_flags)
 {
 #ifdef MAP_HUGETLB
 
 	Size		default_hugepagesize = 0;
 	Size		hugepagesize_local = 0;
+	Size		hugepagefree_local = 0;
 	int			mmap_flags_local = 0;
 
 	/*
@@ -502,7 +503,11 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
 		{
 			while (fgets(buf, sizeof(buf), fp))
 			{
-				if (sscanf(buf, "Hugepagesize: %u %c", &sz, &ch) == 2)
+				if (sscanf(buf, "HugePages_Free: %u", &sz) == 1)
+				{
+					hugepagefree_local = sz;
+				}
+				else if (sscanf(buf, "Hugepagesize: %u %c", &sz, &ch) == 2)
 				{
 					if (ch == 'k')
 					{
@@ -560,11 +565,15 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
 		*mmap_flags = mmap_flags_local;
 	if (hugepagesize)
 		*hugepagesize = hugepagesize_local;
+	if (hugepagefree)
+		*hugepagefree = hugepagefree_local * hugepagesize_local;
 
 #else
 
 	if (hugepagesize)
 		*hugepagesize = 0;
+	if (hugepagefree)
+		*hugepagefree = 0;
 	if (mmap_flags)
 		*mmap_flags = 0;
 
@@ -614,7 +623,7 @@ CreateAnonymousSegment(Size *size)
 		Size		hugepagesize;
 		int			mmap_flags;
 
-		GetHugePageSize(&hugepagesize, &mmap_flags);
+		GetHugePageSize(&hugepagesize, NULL, &mmap_flags);
 
 		if (allocsize % hugepagesize != 0)
 			allocsize += hugepagesize - (allocsize % hugepagesize);
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index 7cb8b4c9b60..9402aa5da28 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -627,10 +627,12 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
  * use GetLargePageMinimum() instead.
  */
 void
-GetHugePageSize(Size *hugepagesize, int *mmap_flags)
+GetHugePageSize(Size *hugepagesize, Size *hugepagefree, int *mmap_flags)
 {
 	if (hugepagesize)
 		*hugepagesize = 0;
+	if (hugepagefree)
+		*hugepagefree = 0;
 	if (mmap_flags)
 		*mmap_flags = 0;
 }
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 88e52664ebe..a4f182a9081 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -358,7 +358,7 @@ InitializeShmemGUCs(void)
 	/*
 	 * Calculate the number of huge pages required.
 	 */
-	GetHugePageSize(&hp_size, NULL);
+	GetHugePageSize(&hp_size, NULL, NULL);
 	if (hp_size != 0)
 	{
 		Size		hp_required;
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index d2f4710f141..0972e9c16a4 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -746,7 +746,7 @@ pg_get_shmem_pagesize(void)
 	Assert(huge_pages_status != HUGE_PAGES_UNKNOWN);
 
 	if (huge_pages_status == HUGE_PAGES_ON)
-		GetHugePageSize(&os_page_size, NULL);
+		GetHugePageSize(&os_page_size, NULL, NULL);
 
 	return os_page_size;
 }
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index 3aeada554b2..7b6efc9f306 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -89,6 +89,6 @@ extern PGShmemHeader *PGSharedMemoryCreate(Size size,
 										   PGShmemHeader **shim);
 extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2);
 extern void PGSharedMemoryDetach(void);
-extern void GetHugePageSize(Size *hugepagesize, int *mmap_flags);
+extern void GetHugePageSize(Size *hugepagesize, Size *hugepagefree, int *mmap_flags);
 
 #endif							/* PG_SHMEM_H */
-- 
2.52.0

