diff options
Diffstat (limited to 'src/backend/port/sysv_shmem.c')
-rw-r--r-- | src/backend/port/sysv_shmem.c | 62 |
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; |