Patch accel_get_hugepage_size for opcache Bug #79027
Patch version 2019-12-31 13:32 UTC
Return to Bug #79027 |
Download this patch
Patch Revisions:
Developer: chris@neadwerx.com
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 52276010af..305a0d94ac 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2618,6 +2618,32 @@ static void accel_gen_system_id(void)
# endif
# if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
+/* Validate the system's default hugepage size by checking
+ * /proc/meminfo. If it's larger than our allocation, we risk
+ * grabbing more memory than we would actually want. We'll be verifying this
+ * against our segment addresses in accel_move_code_to_huge_pages.
+ */
+static void accel_get_hugepage_size(unsigned long int * hugepage_size)
+{
+ FILE * fp = fopen( "/proc/meminfo", "r" );
+ char buf[128];
+ unsigned int size;
+ char c;
+
+ if ( fp ) {
+ while ( fgets( buf, sizeof( buf ), fp ) ) {
+ if ( sscanf( buf, "Hugepagesize: %u %c", &size, &c ) == 2 ) {
+ if ( c == 'k' ) {\
+ *hugepage_size = size * 1024L;
+ break;
+ }
+ }
+ }
+
+ fclose( fp );
+ }
+}
+
static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset)
{
void *ret = MAP_FAILED;
@@ -2636,7 +2662,7 @@ static int accel_remap_huge_pages(void *start, size_t size, const char *name, si
memcpy(mem, start, size);
# ifdef MAP_HUGETLB
- ret = mmap(start, size,
+ ret = mmap(start, size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
-1, 0);
@@ -2682,22 +2708,27 @@ static void accel_move_code_to_huge_pages(void)
{
FILE *f;
long unsigned int huge_page_size = 2 * 1024 * 1024;
-
f = fopen("/proc/self/maps", "r");
if (f) {
long unsigned int start, end, offset, inode;
char perm[5], dev[6], name[MAXPATHLEN];
int ret;
-
+ accel_get_hugepage_size(&huge_page_size);
ret = fscanf(f, "%lx-%lx %4s %lx %5s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
if (ret == 7 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
long unsigned int seg_end = (end & ~(huge_page_size-1L));
- if (seg_end > seg_start) {
+ if (seg_end > seg_start && ( seg_end - seg_start ) < huge_page_size) {
zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, name, offset + seg_start - start);
- }
+ } else {
+ if (seg_end > seg_start ) {
+ zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": huge_code_pages: cannot align segment bounds");
+ } else {
+ zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": system default huge page size too large to be utilized by opcache");
+ }
+ }
}
fclose(f);
}
|