“Device busy”错误源于文件被进程占用或挂载点限制;需用lsof查占用进程、mount查挂载选项,避免PHP长期持文件句柄,优先将目录移至支持权限的本地ext4分区。

chmod 修改文件权限时提示 “Device busy”
PHP 中调用 chmod() 或通过 shell_exec("chmod ...") 修改文件权限却报 “Device busy”,这通常不是 PHP 本身的问题,而是底层文件系统拒绝操作——最常见原因是该文件正被某个进程(尤其是 Web 服务器或 PHP-FPM 工作进程)以独占方式打开、锁定,或文件位于只读挂载点、NFS/CIFS 等网络文件系统上。
检查文件是否被进程占用(Linux/macOS)
先确认是不是有进程正在读写该文件。在终端执行:
lsof +D /path/to/your/file
或更精准地查具体路径:
lsof /var/www/html/config.php
如果输出中看到 php-fpm、apache2、nginx 或 vim 等进程占着该文件,说明它正被持有句柄——此时 chmod 会被内核拒绝并返回 EBUSY(对应 “Device busy” 错误)。
立即学习“PHP免费学习笔记(深入)”;
- 临时解决:重启对应服务(如
systemctl restart php-fpm),但生产环境慎用 - 根本办法:避免 PHP 进程长期 fopen() 后不 fclose();检查是否有
fopen(..., "a+")或flock()后未释放 - 注意:即使脚本已结束,若使用了 opcache 或 realpath 缓存,也可能延迟释放路径引用
确认挂载选项是否允许权限修改
运行 mount | grep $(df . | tail -1 | awk '{print $1}') 查看当前文件系统挂载参数。若输出含 noexec、nosuid、ro(只读)或 noacl,则 chmod 必然失败。
- NFS 挂载默认常带
nosuid,nodev,noexec,且服务端若配了root_squash,非 root 用户无法改权限 - FAT32/exFAT/NTFS 分区(如通过
ntfs-3g挂载)本身不支持 Unix 权限,chmod会静默忽略或报错 - 容器内挂载的 volume 若用
:ro或 host 路径本身是只读挂载,也会触发此错误
绕过 chmod 的替代方案(当必须修改权限且无法停服务)
如果确认文件只是被读取(非写入锁定),且你有 root 权限,可尝试从外部强制更新权限,避开 PHP 进程上下文:
sudo chown www-data:www-data /var/www/html/cache/ && sudo chmod 755 /var/www/html/cache/
但要注意:
- PHP 脚本里仍不能直接调用
chmod()—— 因为它运行在 www-data 用户下,无权修改自身正访问的目录元数据 - 用
shell_exec()执行带sudo的命令需提前配置免密(visudo加www-data ALL=(ALL) NOPASSWD: /bin/chmod),存在安全风险,不推荐线上使用 - 更稳妥的做法是:把需要动态改权限的目录移到本地 ext4 分区,确保挂载选项为
defaults,并让 PHP 进程只在必要时打开文件、立即关闭
真正卡住的地方往往不在 chmod 语法,而在文件生命周期管理和存储介质特性。别急着加 try-catch,先看 lsof 和 mount。











