PHP scandir()访问CIFS挂载点失效,需重启php-fpm,求解决办法
问题背景
配置初期运行完全正常,但当CIFS主机因补丁更新、断电等原因离线后,尽管操作系统仍可正常访问该CIFS共享,PHP却无法访问挂载点内的文件,必须重启php-fpm才能恢复。
报错信息:
Warning: scandir(repository/Some Series/Some Title): failed to open dir: No such file or directory in /var/www/audiobooks/libraries/bookScan.php on line 169
Linux服务器挂载点信息:
//10.68.x.x/Media/Audiobooks on /var/www/audiobooks/repository type cifs (rw,relatime,vers=default,cache=strict,username=xxxxxx,domain=/,uid=48,forceuid,gid=996,forcegid,addr=10.68.x.x,file_mode=0755,dir_mode=0775,soft,nounix,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
相关PHP代码:
public function getBookFiles($book) { $path = $book["path"]; $files = scandir($path); $files = array_diff($files,array('..','.')); return $files; }
补充说明:故障期间操作系统访问文件无异常,仅PHP无法访问,重启php-fpm可临时解决问题。
根本原因
PHP-FPM的工作进程会缓存文件系统的元数据(比如目录结构、文件存在状态),当CIFS共享离线后重新挂载,这些进程并没有主动刷新缓存,仍然保留着共享离线时的无效状态,导致无法识别重新挂载后的文件系统。
无需重启PHP-FPM的解决办法
1. 代码层面强制刷新文件系统缓存
直接在PHP代码中加入clearstatcache()函数,清除PHP缓存的文件状态信息,确保每次获取目录时都是最新的文件系统状态。修改你的getBookFiles方法:
public function getBookFiles($book) { $path = $book["path"]; // 仅清除指定路径的缓存,比全局清除更高效 clearstatcache(true, $path); $files = scandir($path); $files = array_diff($files,array('..','.')); return $files; }
这个方法是最直接的应用层解决方案,不需要修改系统配置或操作服务,适合快速修复问题。
2. 调整CIFS挂载参数降低缓存影响
当前挂载参数中的cache=strict和actimeo=1可能加剧了缓存问题,你可以尝试调整缓存相关参数:
- 将
cache=strict改为cache=none:禁用客户端缓存,强制每次访问都从CIFS服务器获取最新数据 - 调小
actimeo值为actimeo=0:设置文件属性缓存超时时间为0,让系统更快刷新缓存
修改/etc/fstab中的挂载条目后,执行以下命令重新挂载生效:
mount -o remount /var/www/audiobooks/repository
注意:禁用缓存可能会带来轻微的性能损耗,需要根据业务场景权衡。
3. 优雅重启单个PHP-FPM工作进程
如果不想重启整个PHP-FPM服务,可以向单个工作进程发送SIGUSR1信号,让它优雅退出并重启,既刷新了缓存又不会中断正在处理的请求:
# 列出所有PHP-FPM工作进程的PID ps aux | grep php-fpm | grep -v master # 逐个发送SIGUSR1信号 kill -USR1 <进程PID>
或者用自动化命令批量处理:
pkill -USR1 -f php-fpm
4. 重置OPcache(如果启用)
如果你的PHP启用了OPcache(默认可能开启),虽然它主要缓存脚本,但偶尔也会间接影响文件系统感知。可以在代码中添加重置逻辑:
if (function_exists('opcache_reset')) { opcache_reset(); }
这个方法建议配合
clearstatcache()一起使用,效果更稳定。
总结
最推荐第一种代码层面的解决方案,它直接从根源解决了PHP进程缓存无效文件状态的问题,无需系统级操作。如果代码修改有困难,可以优先尝试调整CIFS挂载参数或优雅重启单个PHP-FPM进程。
内容的提问来源于stack exchange,提问作者Daniel Widrick

