aboutsummaryrefslogtreecommitdiff
path: root/src/backend/port/sysv_shmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/port/sysv_shmem.c')
-rw-r--r--src/backend/port/sysv_shmem.c62
1 files changed, 45 insertions, 17 deletions
diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 198a6985bf3..203555822d9 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -32,6 +32,7 @@
#endif
#include "miscadmin.h"
+#include "port/pg_bitutils.h"
#include "portability/mem.h"
#include "storage/dsm.h"
#include "storage/fd.h"
@@ -448,7 +449,7 @@ PGSharedMemoryAttach(IpcMemoryId shmId,
#ifdef MAP_HUGETLB
/*
- * Identify the huge page size to use.
+ * Identify the huge page size to use, and compute the related mmap flags.
*
* Some Linux kernel versions have a bug causing mmap() to fail on requests
* that are not a multiple of the hugepage size. Versions without that bug
@@ -464,25 +465,13 @@ 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 or assumed) page size into *hugepagesize,
+ * Returns the (real, assumed or config provided) page size into *hugepagesize,
* and the hugepage-related mmap flags to use into *mmap_flags.
- *
- * Currently *mmap_flags is always just MAP_HUGETLB. Someday, on systems
- * that support it, we might OR in additional bits to specify a particular
- * non-default huge page size.
*/
static void
GetHugePageSize(Size *hugepagesize, int *mmap_flags)
{
- /*
- * If we fail to find out the system's default huge page size, assume it
- * is 2MB. This will work fine when the actual size is less. If it's
- * more, we might get mmap() or munmap() failures due to unaligned
- * requests; but at this writing, there are no reports of any non-Linux
- * systems being picky about that.
- */
- *hugepagesize = 2 * 1024 * 1024;
- *mmap_flags = MAP_HUGETLB;
+ Size default_hugepagesize = 0;
/*
* System-dependent code to find out the default huge page size.
@@ -491,6 +480,7 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
* nnnn kB". Ignore any failures, falling back to the preset default.
*/
#ifdef __linux__
+
{
FILE *fp = AllocateFile("/proc/meminfo", "r");
char buf[128];
@@ -505,7 +495,7 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
{
if (ch == 'k')
{
- *hugepagesize = sz * (Size) 1024;
+ default_hugepagesize = sz * (Size) 1024;
break;
}
/* We could accept other units besides kB, if needed */
@@ -515,6 +505,44 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
}
}
#endif /* __linux__ */
+
+ if (huge_page_size != 0)
+ {
+ /* If huge page size is requested explicitly, use that. */
+ *hugepagesize = (Size) huge_page_size * 1024;
+ }
+ else if (default_hugepagesize != 0)
+ {
+ /* Otherwise use the system default, if we have it. */
+ *hugepagesize = default_hugepagesize;
+ }
+ else
+ {
+ /*
+ * If we fail to find out the system's default huge page size, or no
+ * huge page size is requested explicitly, assume it is 2MB. This will
+ * work fine when the actual size is less. If it's more, we might get
+ * mmap() or munmap() failures due to unaligned requests; but at this
+ * writing, there are no reports of any non-Linux systems being picky
+ * about that.
+ */
+ *hugepagesize = 2 * 1024 * 1024;
+ }
+
+ *mmap_flags = MAP_HUGETLB;
+
+ /*
+ * On recent enough Linux, also include the explicit page size, if
+ * necessary.
+ */
+#if defined(MAP_HUGE_MASK) && defined(MAP_HUGE_SHIFT)
+ if (*hugepagesize != default_hugepagesize)
+ {
+ int shift = pg_ceil_log2_64(*hugepagesize);
+
+ *mmap_flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
+ }
+#endif
}
#endif /* MAP_HUGETLB */
@@ -583,7 +611,7 @@ CreateAnonymousSegment(Size *size)
"(currently %zu bytes), reduce PostgreSQL's shared "
"memory usage, perhaps by reducing shared_buffers or "
"max_connections.",
- *size) : 0));
+ allocsize) : 0));
}
*size = allocsize;