From 2e614ae445e9610a879e0ff043b8fda6e5cfe7d9 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Tue, 22 Oct 2024 13:33:44 +0000 Subject: [PATCH 01/12] opcache: support file_cache_read_only (php#16484) --- ext/opcache/ZendAccelerator.c | 36 +++++++++++++++++++++++++++ ext/opcache/ZendAccelerator.h | 1 + ext/opcache/zend_accelerator_module.c | 12 +++++---- ext/opcache/zend_file_cache.c | 4 +++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index e8f7a39a3af91..f1de90a06b6a2 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1411,6 +1411,9 @@ zend_result zend_accel_invalidate(zend_string *filename, bool force) } if (ZCG(accel_directives).file_cache) { + if (ZCG(accel_directives).file_cache_read_only) { + return FAILURE; + } zend_file_cache_invalidate(realpath); } @@ -3300,6 +3303,39 @@ static zend_result accel_post_startup(void) #endif accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals)); } + + /* opcache.file_cache_read_only should only be enabled when all script files are read-only */ + if (ZCG(accel_directives).file_cache_read_only) { + if (!ZCG(accel_directives).file_cache) { + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only is set without a proper setting of opcache.file_cache"); + return SUCCESS; + } + if (ZCG(accel_directives).revalidate_freq != 0) { + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only cannot be enabled when opcache.revalidate_freq is not 0."); + return SUCCESS; + } + if (ZCG(accel_directives).validate_timestamps) { + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only cannot be enabled when opcache.validate_timestamps is enabled."); + return SUCCESS; + } + } else { + /* opcache.file_cache isn't read only, so ensure the directory is writable */ + if ( ZCG(accel_directives).file_cache && +#ifndef ZEND_WIN32 + access(ZCG(accel_directives).file_cache, R_OK | W_OK | X_OK) != 0 +#else + _access(ZCG(accel_directives).file_cache, 06) != 0 +#endif + ) { + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible, writable directory"); + return SUCCESS; + } + } + #if ENABLE_FILE_CACHE_FALLBACK file_cache_fallback: #endif diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 162892bf2c279..3f7eb3bdf008f 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -177,6 +177,7 @@ typedef struct _zend_accel_directives { char *lockfile_path; #endif char *file_cache; + bool file_cache_read_only; bool file_cache_only; bool file_cache_consistency_checks; #if ENABLE_FILE_CACHE_FALLBACK diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2ed8155eff773..f86a7e2aebbdd 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -172,9 +172,9 @@ static ZEND_INI_MH(OnUpdateFileCache) zend_stat(ZSTR_VAL(new_value), &buf) != 0 || !S_ISDIR(buf.st_mode) || #ifndef ZEND_WIN32 - access(ZSTR_VAL(new_value), R_OK | W_OK | X_OK) != 0) { + access(ZSTR_VAL(new_value), R_OK | X_OK) != 0) { #else - _access(ZSTR_VAL(new_value), 06) != 0) { + _access(ZSTR_VAL(new_value), 04) != 0) { #endif zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessible directory.\n"); new_value = NULL; @@ -311,9 +311,10 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) #endif - STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) - STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) - STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) #if ENABLE_FILE_CACHE_FALLBACK STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals) #endif @@ -823,6 +824,7 @@ ZEND_FUNCTION(opcache_get_configuration) #endif add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : ""); + add_assoc_bool(&directives, "opcache.file_cache_read_only", ZCG(accel_directives).file_cache_read_only); add_assoc_bool(&directives, "opcache.file_cache_only", ZCG(accel_directives).file_cache_only); add_assoc_bool(&directives, "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks); #if ENABLE_FILE_CACHE_FALLBACK diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 736d644516a04..cc22c78d8253f 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -1100,6 +1100,10 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) } #endif + if (ZCG(accel_directives).file_cache_read_only) { + return FAILURE; + } + filename = zend_file_cache_get_bin_file_path(script->script.filename); if (zend_file_cache_mkdir(filename, strlen(ZCG(accel_directives).file_cache)) != SUCCESS) { From 9c42cd1dc63329bd8018e482895d29d0709b0f15 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Wed, 23 Oct 2024 10:57:25 +0000 Subject: [PATCH 02/12] opcache: file_cache_read_only code review update (php#16484) --- ext/opcache/ZendAccelerator.c | 39 +++++++++++++++------------ ext/opcache/zend_accelerator_module.c | 15 ++++------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f1de90a06b6a2..cac4722152f95 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3305,35 +3305,40 @@ static zend_result accel_post_startup(void) } /* opcache.file_cache_read_only should only be enabled when all script files are read-only */ + int file_cache_access_mode = 0; + if (ZCG(accel_directives).file_cache_read_only) { if (!ZCG(accel_directives).file_cache) { accel_startup_ok = false; zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only is set without a proper setting of opcache.file_cache"); return SUCCESS; } - if (ZCG(accel_directives).revalidate_freq != 0) { - accel_startup_ok = false; - zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only cannot be enabled when opcache.revalidate_freq is not 0."); - return SUCCESS; - } - if (ZCG(accel_directives).validate_timestamps) { - accel_startup_ok = false; - zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only cannot be enabled when opcache.validate_timestamps is enabled."); - return SUCCESS; - } + + /* opcache.file_cache is read only, so ensure the directory is readable */ +#ifndef ZEND_WIN32 + file_cache_access_mode = R_OK | X_OK; +#else + file_cache_access_mode = 04; // Read access +#endif } else { /* opcache.file_cache isn't read only, so ensure the directory is writable */ - if ( ZCG(accel_directives).file_cache && #ifndef ZEND_WIN32 - access(ZCG(accel_directives).file_cache, R_OK | W_OK | X_OK) != 0 + file_cache_access_mode = R_OK | W_OK | X_OK; #else - _access(ZCG(accel_directives).file_cache, 06) != 0 + file_cache_access_mode = 06; // Read and write access +#endif + } + + if ( ZCG(accel_directives).file_cache && +#ifndef ZEND_WIN32 + access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0 +#else + _access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0 #endif ) { - accel_startup_ok = false; - zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible, writable directory"); - return SUCCESS; - } + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible directory"); + return SUCCESS; } #if ENABLE_FILE_CACHE_FALLBACK diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index f86a7e2aebbdd..65b2494308aa2 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -170,12 +170,7 @@ static ZEND_INI_MH(OnUpdateFileCache) if (!IS_ABSOLUTE_PATH(ZSTR_VAL(new_value), ZSTR_LEN(new_value)) || zend_stat(ZSTR_VAL(new_value), &buf) != 0 || - !S_ISDIR(buf.st_mode) || -#ifndef ZEND_WIN32 - access(ZSTR_VAL(new_value), R_OK | X_OK) != 0) { -#else - _access(ZSTR_VAL(new_value), 04) != 0) { -#endif + !S_ISDIR(buf.st_mode)) { zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessible directory.\n"); new_value = NULL; } @@ -311,10 +306,10 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) #endif - STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) - STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) - STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) - STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) #if ENABLE_FILE_CACHE_FALLBACK STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals) #endif From 1197a969a25775dc12de7301b26bbc928e292e14 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Wed, 23 Oct 2024 12:25:43 +0000 Subject: [PATCH 03/12] opcache: file_cache_read_only code review update 2 (php#16484) --- ext/opcache/ZendAccelerator.c | 16 +++++++++++----- ext/opcache/zend_accelerator_module.c | 22 +--------------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index cac4722152f95..be3e44f8b4b36 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3329,16 +3329,22 @@ static zend_result accel_post_startup(void) #endif } - if ( ZCG(accel_directives).file_cache && + if ( ZCG(accel_directives).file_cache ){ + zend_stat_t buf = {0}; + + if (!IS_ABSOLUTE_PATH(ZCG(accel_directives).file_cache, strlen(ZCG(accel_directives).file_cache)) || + zend_stat(ZCG(accel_directives).file_cache, &buf) != 0 || + !S_ISDIR(buf.st_mode) || #ifndef ZEND_WIN32 access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0 #else _access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0 #endif - ) { - accel_startup_ok = false; - zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible directory"); - return SUCCESS; + ) { + accel_startup_ok = false; + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible directory"); + return SUCCESS; + } } #if ENABLE_FILE_CACHE_FALLBACK diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 65b2494308aa2..bb037981dc1f1 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -160,26 +160,6 @@ static ZEND_INI_MH(OnEnable) } } -static ZEND_INI_MH(OnUpdateFileCache) -{ - if (new_value) { - if (!ZSTR_LEN(new_value)) { - new_value = NULL; - } else { - zend_stat_t buf = {0}; - - if (!IS_ABSOLUTE_PATH(ZSTR_VAL(new_value), ZSTR_LEN(new_value)) || - zend_stat(ZSTR_VAL(new_value), &buf) != 0 || - !S_ISDIR(buf.st_mode)) { - zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessible directory.\n"); - new_value = NULL; - } - } - } - OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); - return SUCCESS; -} - #ifdef HAVE_JIT static ZEND_INI_MH(OnUpdateJit) { @@ -306,7 +286,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) #endif - STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.file_cache, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) From 86e51787d39b2972e26388ddf39c84d9dd56d2ff Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Thu, 24 Oct 2024 13:38:54 +0000 Subject: [PATCH 04/12] opcache: file_cache_read_only code review update 3 (php#16484) --- ext/opcache/zend_accelerator_module.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index bb037981dc1f1..1b62b757b87d2 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -160,6 +160,17 @@ static ZEND_INI_MH(OnEnable) } } +static ZEND_INI_MH(OnUpdateFileCache) +{ + if (new_value) { + if (!ZSTR_LEN(new_value)) { + new_value = NULL; + } + } + OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + return SUCCESS; +} + #ifdef HAVE_JIT static ZEND_INI_MH(OnUpdateJit) { @@ -286,7 +297,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) #endif - STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.file_cache, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) From 8c43a771ac53006ae3f93bff2544c2ba6cc2804b Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Fri, 25 Oct 2024 21:43:58 +0000 Subject: [PATCH 05/12] opcache: file_cache_read_only code review update 4 (php#16484) --- UPGRADING | 4 ++++ ext/opcache/ZendAccelerator.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/UPGRADING b/UPGRADING index 20bc84758744a..cef43332426e3 100644 --- a/UPGRADING +++ b/UPGRADING @@ -105,6 +105,10 @@ PHP 8.5 UPGRADE NOTES readline_callback_handler_install() have been changed to true, rather than bool. +- opcache: + . Introduce opcache.file_cache_read_only to support a read-only + opcache.file_cache directory, for use with read-only Docker containers. + ======================================== 10. New Global Constants ======================================== diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index be3e44f8b4b36..cd4c9150e791d 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3329,7 +3329,7 @@ static zend_result accel_post_startup(void) #endif } - if ( ZCG(accel_directives).file_cache ){ + if ( ZCG(accel_directives).file_cache ) { zend_stat_t buf = {0}; if (!IS_ABSOLUTE_PATH(ZCG(accel_directives).file_cache, strlen(ZCG(accel_directives).file_cache)) || From 8aaa51d7e32cc19237553020c2d7e8e0c331852f Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Tue, 29 Oct 2024 10:53:35 +0000 Subject: [PATCH 06/12] opcache: file_cache_read_only code review update 5 (php#16484) --- UPGRADING | 7 ++++++- ext/opcache/ZendAccelerator.c | 5 ++--- ext/opcache/zend_file_cache.c | 24 ++++++++++++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/UPGRADING b/UPGRADING index cef43332426e3..afeeb664fa2d5 100644 --- a/UPGRADING +++ b/UPGRADING @@ -105,9 +105,14 @@ PHP 8.5 UPGRADE NOTES readline_callback_handler_install() have been changed to true, rather than bool. -- opcache: +- Opcache: . Introduce opcache.file_cache_read_only to support a read-only opcache.file_cache directory, for use with read-only Docker containers. + Best used with `opcache.validate_timestamps=0`, `opcache.revalidate_freq=0` + and `opcache.enable_file_override=1`. + Note: this cache isn't portable between PHP builds, enforced by the + inclusion of the `zend_system_id` both in the directory path, and + each cache file. ======================================== 10. New Global Constants diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index cd4c9150e791d..53b8e283460e6 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1411,10 +1411,9 @@ zend_result zend_accel_invalidate(zend_string *filename, bool force) } if (ZCG(accel_directives).file_cache) { - if (ZCG(accel_directives).file_cache_read_only) { - return FAILURE; + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_invalidate(realpath); } - zend_file_cache_invalidate(realpath); } persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath); diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index cc22c78d8253f..22ecd81c86ca6 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -1847,7 +1847,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (info)\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } efree(filename); return NULL; } @@ -1857,7 +1859,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong header)\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } efree(filename); return NULL; } @@ -1865,7 +1869,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } efree(filename); return NULL; } @@ -1877,7 +1883,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename); } close(fd); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } efree(filename); return NULL; } @@ -1895,7 +1903,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (mem)\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } zend_arena_release(&CG(arena), checkpoint); efree(filename); return NULL; @@ -1909,7 +1919,9 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl if (ZCG(accel_directives).file_cache_consistency_checks && (actual_checksum = zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size)) != info.checksum) { zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s' excepted checksum: 0x%08x actual checksum: 0x%08x\n", filename, info.checksum, actual_checksum); - zend_file_cache_unlink(filename); + if (!ZCG(accel_directives).file_cache_read_only) { + zend_file_cache_unlink(filename); + } zend_arena_release(&CG(arena), checkpoint); efree(filename); return NULL; From 3e1c63b015809a513d98f1f5c7e307af44b3fc07 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Tue, 29 Oct 2024 16:26:29 +0000 Subject: [PATCH 07/12] opcache: file_cache_read_only - debug log when active (php#16484) --- ext/opcache/ZendAccelerator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 53b8e283460e6..dc48d2d21385c 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3307,6 +3307,8 @@ static zend_result accel_post_startup(void) int file_cache_access_mode = 0; if (ZCG(accel_directives).file_cache_read_only) { + zend_accel_error_noreturn(ACCEL_LOG_INFO, "opcache.file_cache is in read-only mode"); + if (!ZCG(accel_directives).file_cache) { accel_startup_ok = false; zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only is set without a proper setting of opcache.file_cache"); From 9510786295b8e1303bf68e77044ad19f7256477e Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Tue, 29 Oct 2024 16:32:14 +0000 Subject: [PATCH 08/12] opcache: file_cache_read_only code review update 6 (php#16484) --- UPGRADING | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/UPGRADING b/UPGRADING index afeeb664fa2d5..2338757e8071f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -108,11 +108,10 @@ PHP 8.5 UPGRADE NOTES - Opcache: . Introduce opcache.file_cache_read_only to support a read-only opcache.file_cache directory, for use with read-only Docker containers. - Best used with `opcache.validate_timestamps=0`, `opcache.revalidate_freq=0` - and `opcache.enable_file_override=1`. - Note: this cache isn't portable between PHP builds, enforced by the - inclusion of the `zend_system_id` both in the directory path, and - each cache file. + Best used with `opcache.validate_timestamps=0`, `opcache.enable_file_override=1` + and `opcache.file_cache_consistency_checks=false`. + Note: A cache generated with a different build of PHP, or different settings + (including which extensions are loaded) may be ignored. ======================================== 10. New Global Constants From c45c69ea6257a7647b873a2d9e4cee70f65686a6 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Wed, 30 Oct 2024 09:51:30 +0000 Subject: [PATCH 09/12] opcache: file_cache_read_only - debug log when active 2 (php#16484) --- ext/opcache/ZendAccelerator.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index dc48d2d21385c..122e1f9814f5f 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -46,6 +46,7 @@ #include "zend_accelerator_util_funcs.h" #include "zend_accelerator_hash.h" #include "zend_file_cache.h" +#include "zend_system_id.h" #include "ext/pcre/php_pcre.h" #include "ext/standard/basic_functions.h" @@ -3307,7 +3308,7 @@ static zend_result accel_post_startup(void) int file_cache_access_mode = 0; if (ZCG(accel_directives).file_cache_read_only) { - zend_accel_error_noreturn(ACCEL_LOG_INFO, "opcache.file_cache is in read-only mode"); + zend_accel_error(ACCEL_LOG_INFO, "opcache.file_cache is in read-only mode"); if (!ZCG(accel_directives).file_cache) { accel_startup_ok = false; @@ -3331,6 +3332,8 @@ static zend_result accel_post_startup(void) } if ( ZCG(accel_directives).file_cache ) { + zend_accel_error(ACCEL_LOG_INFO, "opcache.file_cache running with PHP build ID: %s", zend_system_id); + zend_stat_t buf = {0}; if (!IS_ABSOLUTE_PATH(ZCG(accel_directives).file_cache, strlen(ZCG(accel_directives).file_cache)) || From e5526bd3532ab6dd31b1fdb7d475c5f64ac3483b Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Wed, 30 Oct 2024 14:46:56 +0000 Subject: [PATCH 10/12] opcache: file_cache_read_only - fix unit test for Windows (php#16484) --- ext/opcache/tests/zzz_basic_logging.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/opcache/tests/zzz_basic_logging.phpt b/ext/opcache/tests/zzz_basic_logging.phpt index 7490fadc62ef6..a53c6a8db9de1 100644 --- a/ext/opcache/tests/zzz_basic_logging.phpt +++ b/ext/opcache/tests/zzz_basic_logging.phpt @@ -6,6 +6,7 @@ outputs the correct logging at the highest log_verbosity_level --INI-- opcache.enable=1 opcache.enable_cli=1 +opcache.file_cache= opcache.file_cache_only=0 opcache.error_log= opcache.log_verbosity_level=4 From 112b9d661580bb91bbd0066321f85cbb4324b732 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Wed, 30 Oct 2024 15:48:49 +0000 Subject: [PATCH 11/12] opcache: file_cache_read_only - documentation consistency (php#16484) --- UPGRADING | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/UPGRADING b/UPGRADING index 2338757e8071f..e418cb4097667 100644 --- a/UPGRADING +++ b/UPGRADING @@ -107,11 +107,11 @@ PHP 8.5 UPGRADE NOTES - Opcache: . Introduce opcache.file_cache_read_only to support a read-only - opcache.file_cache directory, for use with read-only Docker containers. + `opcache.file_cache` directory, for use with read-only Docker containers. Best used with `opcache.validate_timestamps=0`, `opcache.enable_file_override=1` - and `opcache.file_cache_consistency_checks=false`. - Note: A cache generated with a different build of PHP, or different settings - (including which extensions are loaded) may be ignored. + and `opcache.file_cache_consistency_checks=0`. + Note: A cache generated with a different build of PHP, a different file path, + or different settings (including which extensions are loaded), may be ignored. ======================================== 10. New Global Constants From 62765b756ba7a6b3cc2c84d80738c65b0b024093 Mon Sep 17 00:00:00 2001 From: Samuel Melrose Date: Tue, 5 Nov 2024 09:49:07 +0000 Subject: [PATCH 12/12] opcache: file_cache_read_only code review update 7 (php#16484) --- ext/opcache/ZendAccelerator.c | 4 +--- ext/opcache/zend_file_cache.c | 4 ++++ php.ini-development | 9 +++++++++ php.ini-production | 9 +++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 122e1f9814f5f..f7f35fab57f0e 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1412,9 +1412,7 @@ zend_result zend_accel_invalidate(zend_string *filename, bool force) } if (ZCG(accel_directives).file_cache) { - if (!ZCG(accel_directives).file_cache_read_only) { - zend_file_cache_invalidate(realpath); - } + zend_file_cache_invalidate(realpath); } persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath); diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 22ecd81c86ca6..fe54c477cea77 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -2013,6 +2013,10 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl void zend_file_cache_invalidate(zend_string *full_path) { + if (ZCG(accel_directives).file_cache_read_only) { + return; + } + char *filename; filename = zend_file_cache_get_bin_file_path(full_path); diff --git a/php.ini-development b/php.ini-development index 5adb11d215697..31353facdb394 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1766,6 +1766,15 @@ ldap.max_links = -1 ; SHM reset. The default "" disables file based caching. ;opcache.file_cache= +; Enables or disables read-only mode for the second level cache directory. +; It should improve performance for read-only containers, +; when the cache is pre-warmed and packaged alongside the application. +; Best used with `opcache.validate_timestamps=0`, `opcache.enable_file_override=1` +; and `opcache.file_cache_consistency_checks=0`. +; Note: A cache generated with a different build of PHP, a different file path, +; or different settings (including which extensions are loaded), may be ignored. +;opcache.file_cache_read_only=0 + ; Enables or disables opcode caching in shared memory. ;opcache.file_cache_only=0 diff --git a/php.ini-production b/php.ini-production index e4ffc1084b13a..e4fbd6e785f86 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1768,6 +1768,15 @@ ldap.max_links = -1 ; SHM reset. The default "" disables file based caching. ;opcache.file_cache= +; Enables or disables read-only mode for the second level cache directory. +; It should improve performance for read-only containers, +; when the cache is pre-warmed and packaged alongside the application. +; Best used with `opcache.validate_timestamps=0`, `opcache.enable_file_override=1` +; and `opcache.file_cache_consistency_checks=0`. +; Note: A cache generated with a different build of PHP, a different file path, +; or different settings (including which extensions are loaded), may be ignored. +;opcache.file_cache_read_only=0 + ; Enables or disables opcode caching in shared memory. ;opcache.file_cache_only=0