Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log error cause when opcache cannot write to file cache #9258

Merged
merged 4 commits into from
Sep 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions ext/opcache/tests/file_cache_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
File cache error 001
--EXTENSIONS--
opcache
posix
pcntl
--INI--
opcache.enable_cli=1
opcache.file_cache={TMP}
opcache.log_verbosity_level=2
--SKIPIF--
<?php
if (!posix_setrlimit(POSIX_RLIMIT_FSIZE, 1, 1)) die('skip Test requires setrlimit(RLIMIT_FSIZE) to work');
if (ini_parse_quantity(ini_get('opcache.jit_buffer_size')) !== 0) die('skip File cache is disabled when JIT is on');
?>
--FILE--
<?php

// Create new file to ensure that it's not cached accross test runs
$file = tempnam(sys_get_temp_dir(), 'file_cache_error');
register_shutdown_function(function () use ($file) {
unlink($file);
});
file_put_contents($file, '<?php echo "OK";');
touch($file, time() - 3600);

// Some systems will raise SIGXFSZ when RLIMIT_FSIZE is exceeded
if (defined('SIGXFSZ')) {
pcntl_signal(SIGXFSZ, SIG_IGN);
}

// Should cause writing to cache file to fail
var_dump(posix_setrlimit(POSIX_RLIMIT_FSIZE, 1, 1));

// Will attempt to write to cache file, and fail
require $file;
?>
--EXPECTF--
bool(true)
%sWarning opcache cannot write to file %s: %s

OK
49 changes: 41 additions & 8 deletions ext/opcache/zend_file_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1004,23 +1004,56 @@ static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
/**
* Helper function for zend_file_cache_script_store().
*
* @return true on success, false on error
* @return true on success, false on error and errno is set to indicate the cause of the error
*/
static bool zend_file_cache_script_write(int fd, const zend_persistent_script *script, const zend_file_cache_metainfo *info, const void *buf, const zend_string *s)
{
ssize_t written;
const ssize_t total_size = (ssize_t)(sizeof(*info) + script->size + info->str_size);

#ifdef HAVE_SYS_UIO_H
const struct iovec vec[] = {
{ .iov_base = (void *)info, .iov_len = sizeof(*info) },
{ .iov_base = (void *)buf, .iov_len = script->size },
{ .iov_base = (void *)ZSTR_VAL(s), .iov_len = info->str_size },
};

return writev(fd, vec, sizeof(vec) / sizeof(vec[0])) == (ssize_t)(sizeof(*info) + script->size + info->str_size);
written = writev(fd, vec, sizeof(vec) / sizeof(vec[0]));
if (EXPECTED(written == total_size)) {
return true;
}

errno = written == -1 ? errno : EAGAIN;
return false;
#else
return ZEND_LONG_MAX >= (zend_long)(sizeof(*info) + script->size + info->str_size) &&
write(fd, info, sizeof(*info)) == sizeof(*info) &&
write(fd, buf, script->size) == script->size &&
write(fd, ZSTR_VAL(s), info->str_size) == info->str_size;
if (UNEXPECTED(ZEND_LONG_MAX < (zend_long)total_size)) {
# ifdef EFBIG
errno = EFBIG;
# else
errno = ERANGE;
# endif
return false;
}

written = write(fd, info, sizeof(*info));
if (UNEXPECTED(written != sizeof(*info))) {
errno = written == -1 ? errno : EAGAIN;
return false;
}

written = write(fd, buf, script->size);
if (UNEXPECTED(written != script->size)) {
errno = written == -1 ? errno : EAGAIN;
return false;
}

written = write(fd, ZSTR_VAL(s), info->str_size);
if (UNEXPECTED(written != info->str_size)) {
errno = written == -1 ? errno : EAGAIN;
return false;
}

return true;
#endif
}

Expand Down Expand Up @@ -1095,7 +1128,7 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm)
#endif

if (!zend_file_cache_script_write(fd, script, &info, buf, s)) {
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s': %s\n", filename, strerror(errno));
zend_string_release_ex(s, 0);
close(fd);
efree(mem);
Expand All @@ -1107,7 +1140,7 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm)
zend_string_release_ex(s, 0);
efree(mem);
if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s': %s\n", filename, strerror(errno));
}
close(fd);
efree(filename);
Expand Down