Download | Plain Text | No Line Numbers
- This is proof of concept code to invalidate the opcode cache entries using
- fanotify events. This fails because fanotify doesn't support rename events.
- diff --git a/ZendAccelerator.c b/ZendAccelerator.c
- index 4406400..17f7cff 100644
- --- a/ZendAccelerator.c
- +++ b/ZendAccelerator.c
- @@ -29,6 +29,7 @@
- #include "zend_shared_alloc.h"
- #include "zend_accelerator_module.h"
- #include "zend_accelerator_blacklist.h"
- +#include "zend_accelerator_fsmonitor.h"
- #include "zend_list.h"
- #include "zend_execute.h"
- #include "main/SAPI.h"
- @@ -1048,32 +1049,21 @@ static inline char *accel_make_persistent_key(zend_file_handle *file_handle, int
- return accel_make_persistent_key_ex(file_handle, strlen(file_handle->filename), key_len TSRMLS_CC);
- }
-
- -int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC)
- +int zend_accel_invalidate_real(char *filename, int filename_len, zend_bool force TSRMLS_DC)
- {
- - char *realpath;
- zend_persistent_script *persistent_script;
-
- if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
- return FAILURE;
- }
-
- -#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
- - realpath = accel_php_resolve_path(filename, filename_len, ZCG(include_path) TSRMLS_CC);
- -#else
- - realpath = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
- -#endif
- -
- - if (!realpath) {
- - return FAILURE;
- - }
- -
- - persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath, strlen(realpath) + 1);
- + persistent_script = zend_accel_hash_find(&ZCSG(hash), filename, filename_len + 1);
- if (persistent_script && !persistent_script->corrupted) {
- zend_file_handle file_handle;
-
- file_handle.type = ZEND_HANDLE_FILENAME;
- - file_handle.filename = realpath;
- - file_handle.opened_path = realpath;
- + file_handle.filename = filename;
- + file_handle.opened_path = filename;
-
- if (force ||
- !ZCG(accel_directives).validate_timestamps ||
- @@ -1096,11 +1086,34 @@ int zend_accel_invalidate(const char *filename, int filename_len, zend_bool forc
- }
-
- accelerator_shm_read_unlock(TSRMLS_C);
- - efree(realpath);
-
- return SUCCESS;
- }
-
- +int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC)
- +{
- + char *realpath;
- + zend_persistent_script *persistent_script;
- +
- + if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
- + return FAILURE;
- + }
- +
- +#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
- + realpath = accel_php_resolve_path(filename, filename_len, ZCG(include_path) TSRMLS_CC);
- +#else
- + realpath = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
- +#endif
- +
- + if (!realpath) {
- + return FAILURE;
- + }
- +
- + zend_accel_invalidate_real(realpath, strlen(realpath), force);
- +
- + efree(realpath);
- +}
- +
- /* Adds another key for existing cached script */
- static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket TSRMLS_DC)
- {
- @@ -2690,6 +2703,8 @@ static int accel_startup(zend_extension *extension)
- zend_accel_copy_internal_functions(TSRMLS_C);
- #endif
-
- + zend_accel_fsmonitor_startup();
- +
- return SUCCESS;
- }
-
- @@ -2706,6 +2721,8 @@ void accel_shutdown(TSRMLS_D)
- {
- zend_ini_entry *ini_entry;
-
- + zend_accel_fsmonitor_signal();
- +
- zend_accel_blacklist_shutdown(&accel_blacklist);
-
- if (!ZCG(enabled) || !accel_startup_ok) {
- diff --git a/ZendAccelerator.h b/ZendAccelerator.h
- index bba3631..a8bdf96 100644
- --- a/ZendAccelerator.h
- +++ b/ZendAccelerator.h
- @@ -332,6 +332,7 @@ void accel_shutdown(TSRMLS_D);
- void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC);
- void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC);
- int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC);
- +int zend_accel_invalidate_real(char *filename, int filename_len, zend_bool force TSRMLS_DC);
- int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC);
- int accelerator_shm_read_lock(TSRMLS_D);
- void accelerator_shm_read_unlock(TSRMLS_D);
- diff --git a/config.m4 b/config.m4
- index f6e6ca9..fd11e99 100644
- --- a/config.m4
- +++ b/config.m4
- @@ -366,6 +366,7 @@ fi
- PHP_NEW_EXTENSION(opcache,
- ZendAccelerator.c \
- zend_accelerator_blacklist.c \
- + zend_accelerator_fsmonitor.c \
- zend_accelerator_debug.c \
- zend_accelerator_hash.c \
- zend_accelerator_module.c \
- diff --git a/package.xml b/package.xml
- index bdd7891..3852e2c 100644
- --- a/package.xml
- +++ b/package.xml
- @@ -88,6 +88,7 @@
- <file role="src" name="shared_alloc_mmap.c"/>
- <file role="src" name="zend_accelerator_debug.c"/>
- <file role="src" name="zend_accelerator_blacklist.c"/>
- + <file role="src" name="zend_accelerator_fsmonitor.c"/>
- <file role="src" name="shared_alloc_shm.c"/>
- <file role="src" name="zend_accelerator_util_funcs.h"/>
- <file role="src" name="zend_accelerator_module.h"/>
- diff --git a/zend_accelerator_fsmonitor.c b/zend_accelerator_fsmonitor.c
- new file mode 100644
- index 0000000..d66228c
- --- /dev/null
- +++ b/zend_accelerator_fsmonitor.c
- @@ -0,0 +1,182 @@
- +/*
- + +----------------------------------------------------------------------+
- + | Zend OPcache |
- + +----------------------------------------------------------------------+
- + | Copyright (c) 1998-2014 The PHP Group |
- + +----------------------------------------------------------------------+
- + | This source file is subject to version 3.01 of the PHP license, |
- + | that is bundled with this package in the file LICENSE, and is |
- + | available through the world-wide-web at the following url: |
- + | http://www.php.net/license/3_01.txt |
- + | If you did not receive a copy of the PHP license and are unable to |
- + | obtain it through the world-wide-web, please send a note to |
- + | license@php.net so we can mail you a copy immediately. |
- + +----------------------------------------------------------------------+
- +*/
- +
- +#include "main/php.h"
- +#include "main/php_globals.h"
- +#include "ZendAccelerator.h"
- +#include "zend_accelerator_fsmonitor.h"
- +
- +#include <signal.h>
- +#include <fcntl.h>
- +#include <sys/fanotify.h>
- +
- +pid_t fsm_pid = 0;
- +int fsm_fd = -1;
- +
- +static void zend_accel_fsmonitor_shutdown()
- +{
- + zend_accel_error(ACCEL_LOG_DEBUG, "fsmonitor: shutdown");
- + close(fsm_fd);
- +}
- +
- +static void sig_handler(int signo)
- +{
- + int saved_errno = errno;
- + zend_accel_fsmonitor_shutdown();
- + errno = saved_errno;
- +}
- +
- +static int zend_accel_fsmonitor_init_signals()
- +{
- + struct sigaction act;
- +
- + memset(&act, 0, sizeof(act));
- + act.sa_handler = sig_handler;
- + sigfillset(&act.sa_mask);
- +
- + if (sigaction(SIGTERM, &act, 0) < 0) {
- + zend_accel_error(ACCEL_LOG_WARNING, "failed to init signals: sigaction()");
- + return FAILURE;
- + }
- +
- + return SUCCESS;
- +}
- +
- +static int zend_accel_fsmonitor_init()
- +{
- + zend_accel_error(ACCEL_LOG_DEBUG, "fsmonitor: init");
- + fsm_fd = fanotify_init(FAN_CLOEXEC, O_RDONLY | O_LARGEFILE);
- + if (fsm_fd == -1) {
- + zend_accel_error(ACCEL_LOG_WARNING, "Unable to initialize fsmonitor structure");
- + return FAILURE;
- + }
- +
- + //FIXME
- + if (fanotify_mark(fsm_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_MODIFY, -1, "/var/www") == -1) {
- + zend_accel_error(ACCEL_LOG_WARNING, "Unable to watch filesystem");
- + close(fsm_fd);
- + return FAILURE;
- + }
- +
- + return zend_accel_fsmonitor_init_signals();
- +}
- +
- +static void zend_accel_fsmonitor_invalidate(char *filename, int filename_len)
- +{
- + /* only accept .php-files
- + * this is the full path so '.php' is not valid
- + */
- + if (filename_len <= 4 || strcmp(&filename[filename_len - 4], ".php") != 0)
- + return;
- + zend_accel_error(ACCEL_LOG_DEBUG, "file: %s", filename);
- + zend_accel_invalidate_real(filename, filename_len, 1);
- +}
- +
- +static int zend_accel_fsmonitor_read()
- +{
- + const struct fanotify_event_metadata *metadata;
- + struct fanotify_event_metadata buf[200];
- + char procfd_path[PATH_MAX], path[PATH_MAX];
- + ssize_t len, path_len;
- +
- + len = read(fsm_fd, (void *)&buf, sizeof(buf));
- + if (len == -1 && errno != EAGAIN) {
- + zend_accel_error(ACCEL_LOG_ERROR, "Read error: %s", strerror(errno));
- + return FAILURE;
- + }
- +
- + metadata = buf;
- + while (FAN_EVENT_OK(metadata, len)) {
- + if (metadata->vers != FANOTIFY_METADATA_VERSION) {
- + zend_accel_error(ACCEL_LOG_WARNING, "Mismatch of fanotify metadata version");
- + return FAILURE;
- + }
- +
- + /* metadata->fd contains either FAN_NOFD, indicating a
- + * queue overflow, or a file descriptor (a nonnegative
- + * integer). we simply ignore queue overflow.
- + */
- + if (metadata->fd >= 0) {
- + /* retrieve and print pathname of the accessed file */
- + snprintf(procfd_path, sizeof(procfd_path),
- + "/proc/self/fd/%d", metadata->fd);
- + path_len = readlink(procfd_path, path, sizeof(path) - 1);
- + if (path_len == -1) {
- + zend_accel_error(ACCEL_LOG_DEBUG, "readlink error");
- + return FAILURE;
- + }
- +
- + path[path_len] = '\0';
- + zend_accel_fsmonitor_invalidate(path, path_len);
- +
- + close(metadata->fd);
- + }
- +
- + /* advance to next event */
- + metadata = FAN_EVENT_NEXT(metadata, len);
- + }
- +
- + return SUCCESS;
- +}
- +
- +
- +void zend_accel_fsmonitor_startup()
- +{
- + if (fsm_pid > 0)
- + return;
- +
- + fsm_pid = fork();
- + switch (fsm_pid) {
- + case -1: /* error */
- + zend_accel_error(ACCEL_LOG_WARNING, "Unable to start filesystem monitoring process");
- + return;
- +
- + case 0: /* child */
- + if (zend_accel_fsmonitor_init() == SUCCESS) {
- + for(;;) {
- + if (zend_accel_fsmonitor_read() != SUCCESS) {
- + break;
- + }
- + }
- + zend_accel_fsmonitor_shutdown();
- + }
- + exit(0);
- + break;
- +
- + default: /* parent */
- + zend_accel_error(ACCEL_LOG_DEBUG, "I'm the parent. The childs pid is: %ld", fsm_pid);
- + break;
- + }
- +}
- +
- +void zend_accel_fsmonitor_signal()
- +{
- + pid_t w;
- + int status;
- +
- + if (fsm_pid) {
- + zend_accel_error(ACCEL_LOG_DEBUG, "Signaling child %ld", fsm_pid);
- + if (kill(fsm_pid, SIGTERM) == 0) {
- + sleep(1); //FIXME ugly
- + w = waitpid(fsm_pid, &status, WNOHANG | WUNTRACED);
- + if (w > 0 && !WIFEXITED(status) && !WIFSIGNALED(status)) {
- + zend_accel_error(ACCEL_LOG_WARNING, "Need to kill fsmonitor process...");
- + kill(fsm_pid, SIGKILL);
- + }
- + }
- + fsm_pid = 0;
- + }
- +}
- diff --git a/zend_accelerator_fsmonitor.h b/zend_accelerator_fsmonitor.h
- new file mode 100644
- index 0000000..6c292a7
- --- /dev/null
- +++ b/zend_accelerator_fsmonitor.h
- @@ -0,0 +1,23 @@
- +/*
- + +----------------------------------------------------------------------+
- + | Zend OPcache |
- + +----------------------------------------------------------------------+
- + | Copyright (c) 1998-2014 The PHP Group |
- + +----------------------------------------------------------------------+
- + | This source file is subject to version 3.01 of the PHP license, |
- + | that is bundled with this package in the file LICENSE, and is |
- + | available through the world-wide-web at the following url: |
- + | http://www.php.net/license/3_01.txt |
- + | If you did not receive a copy of the PHP license and are unable to |
- + | obtain it through the world-wide-web, please send a note to |
- + | license@php.net so we can mail you a copy immediately. |
- + +----------------------------------------------------------------------+
- +*/
- +
- +#ifndef ZEND_ACCELERATOR_FSMONITOR_H
- +#define ZEND_ACCELERATOR_FSMONTIOR_H
- +
- +void zend_accel_fsmonitor_startup();
- +void zend_accel_fsmonitor_signal();
- +
- +#endif /* ZEND_ACCELERATOR_FSMONITOR_H */
-