2026-10-03 更新:本文改用 man 手册、内核文档、IETF RFC 与发行版官方文档重写,删去原先的本机测试内容;每种原因都给出可查证的手册依据,并标注了出处。
rm -rf 报 Operation not permitted,chmod 777 也没用,甚至 root 也删不掉——这类问题的排查顺序是有讲究的:先看 inode 标志位,再看挂载与文件系统状态,权限与安全模块排在这两步之后。下面把 10 种常见原因按这个顺序排开,每条都给出 man 手册或内核/官方文档依据。
一、第一步永远是这条命令
lsattr 文件或目录 # 递归查看整个目录树:lsattr -R 目录手册对 lsattr 的说明是:它列出 ext2/ext3/ext4 文件系统上的文件属性,各属性含义见 chattr(1)。这里有个容易误判的点:不可变位不是扩展属性,getfattr 看不到它——它属于 inode flags,由 chattr/lsattr 对应的 ioctl 操作。
二、原因 1:不可变位(chattr +i)
chattr(1) 对 i 的定义是:带 i 属性的文件不能被修改——不能被删除或重命名,不能建立硬链接,大部分元数据不能改,也不能以写模式打开。设置或清除该属性需要 superuser 或 CAP_LINUX_IMMUTABLE 能力。
底层的说法更明确:ioctl_iflags(2) 说明这些 inode flags 通过 FS_IOC_GETFLAGS 与 FS_IOC_SETFLAGS 两个 ioctl 读写,chattr/lsattr 是它们的命令行界面。FS_IOC_SETFLAGS(2const) 的手册页写:调用者的有效 UID 必须等于文件属主或具备 CAP_FOWNER,而设置/清除 a、i 需要 CAP_LINUX_IMMUTABLE——该限制对 root 同样生效。
删除时的报错也有手册依据:unlink(2) 说明,被删除文件带 immutable 或 append-only 标记时返回 EPERM。
chattr +i 文件 # 置为不可变
chattr -i 文件 # 解除(需 root 或 CAP_LINUX_IMMUTABLE)三、原因 2:只允许追加(chattr +a)
chattr(1) 对 a 的定义是:文件只能以追加模式打开写入。它的杀伤力在于目录也能加:FS_IOC_SETFLAGS(2const) 明确写着,FS_APPEND_FL 若施加于目录,会禁止从该目录中删除文件(unlink()、rename() 等),并且"该限制对 superuser 同样生效"。
lsattr -d 目录 # 确认目录本身带 a
chattr -R -a -i 目录 # 递归清除(a 与 i 要分别清)四、原因 3:目标是挂载点
rmdir(2) 说明:目录是挂载点或调用进程的根目录时返回 EBUSY;unlink(2) 的 EBUSY 条目同样列了"它是挂载点"这一情形。要先卸载才能删目录项。
mount(8) 的一句说明解释了为什么这里特别危险:挂载时目录原有内容、属主与模式都会变成不可见,只要文件系统还挂着,这个路径就指向设备上那个文件系统的根——对着挂载点 rm -rf 会清空它背后文件系统的内容,而不是删掉那个空目录。
五、原因 4:文件系统是只读的
unlink(2) 规定目标位于只读文件系统时返回 EROFS。只读可能来自显式挂载选项,也可能来自内核出错后的"保命"行为——ext4(5) 的 errors={continue|remount-ro|panic} 选项就是干这个的:出错时把文件系统重新挂为只读。
mount | grep ' ro,' # 找只读挂载
sudo mount -o remount,rw /挂载点 # 明确恢复可写⚠️ 如果是内核因为 errors=remount-ro 自动改的只读,先查 dmesg 里的文件系统报错,别直接改回可写。
六、原因 5:权限与粘滞位
这一档才是真的权限问题。unlink(2) 给出两种 EACCES:父目录不允许写访问、或路径中某个目录不允许搜索权限。rmdir(2) 同源。
粘滞位是另一个常被忽略的机制:chmod(2) 说明 S_ISVTX(01000)就是 sticky bit,也称 restricted deletion flag(受限删除标志),语义见 unlink(2)。unlink(2) 写明:若包含该文件的目录设置了 sticky bit,而进程的有效 UID 既不是文件属主、也不是目录属主、又不具备 CAP_FOWNER,则返回 EPERM 或 EACCES。chmod(1) 里对应的符号是 t。/tmp 就是典型场景——那是设计如此,不是故障。
七、原因 6:目录非空
rmdir(2):目录含除 . 和 .. 以外的条目时返回 ENOTEMPTY(POSIX.1 也允许用 EEXIST 表示同一情况)。用 rm -r 而不是 rmdir,并注意隐藏文件。
八、原因 7:文件名本身有问题
文件名以 - 开头时会被当成选项。rm(1) 给的正规解法是:
rm -- -foo # 或者
rm ./-foo含空格、换行、通配符的文件名同理,用引号或 -- 隔开;rm(1) 还提醒 --preserve-root 是默认行为(拒绝递归删除 /),只有显式 --no-preserve-root 才会解除。
九、原因 8:文件系统根本不支持这个属性
这是"命令没错、属性没生效"的经典场景,而且报错形态不统一,所以要先确认文件系统支持哪些属性:
chattr(1)明确写着:并非所有标志都被所有文件系统支持或实际使用,需参考btrfs(5)、ext4(5)、mkfs.f2fs(8)、xfs(5)等文件系统专属手册。xfs(5)列出的可设置属性是a、A、d、i、S——不含u与s,所以在 XFS 上设+u/+s不会有效果。ioctl_iflags(2)更直接:FS_SECRM_FL(s,安全删除)与FS_UNRM_FL(u,undeletable)没有被任何文件系统实现(前者因为安全擦除极难,后者因为恢复可以在内核之外实现)。chattr(1)的 BUGS 段还专门说明:c、s、u三个属性在当前 mainline 内核的 ext2/ext3/ext4 上不被遵守,是历史遗留条目。
⚠️ 这里存在一处文档之间的历史不一致:ext4(5) 的属性列表里仍列着 u,而 chattr(1) 的 BUGS 段说它在 mainline ext4 上不生效。引用时把两者一起说明,别只挑一处下结论。
十、原因 9:SELinux / 安全模块拒绝
表现和权限问题一模一样(Permission denied),但权限位与 inode flags 全是干净的。libselinux 的 avc_has_perm(3) 说明:请求的权限被拒绝时返回 -1 且 errno 置为 EACCES;在 permissive 模式下即使被拒绝也返回 0、errno 不变,但仍会写审计消息。也就是说:拒绝不一定报错,但一定会留痕。
Fedora 的官方排障文档给的入口是审计日志:当操作被 SELinux 阻止时,/var/log/audit/audit.log 是第一个该看的地方,并建议用 ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR 这类过滤查询(ausearch(8) 是按消息类型、时间、syscall、可执行文件等条件查询审计日志的工具)。
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent十一、原因 10:删掉了,但空间没回来
rm 成功、空间不降,这不是"没删掉",而是引用计数语义:unlink(2) 说明,如果文件已是最后一个链接但仍有进程打开它,文件会一直存在到引用它的最后一个文件描述符被关闭为止。proc_pid_fd(5) 提供了排查入口:/proc/<pid>/fd/ 下每个打开的文件描述符一条记录,是指向真实文件的符号链接。
sudo ls -l /proc/<pid>/fd | grep deleted # 谁还占着已删除的文件同类还有"正在执行的程序写不进去":open(2) 规定 ETXTBSY 表示 path 指向正在被执行的可执行镜像而请求了写访问(也用于正被内核读取的模块/固件文件、以及正作为 swap 文件使用并指定了 O_TRUNC 的情形)。这种就停掉进程再操作,别删文件。
十二、附:两个环境相关的场景
- 容器 / overlayfs:overlay 为了在不改动下层文件系统的前提下支持
rm/rmdir,必须在上层用 whiteout 与 opaque 目录记录"删除"(内核文档 Overlay Filesystem)。所以容器里"删了但宿主层还在/删不动"是机制使然;Docker 官方文档也说明,把卷挂载到容器内含文件的目录会遮蔽(obscure)原有文件,而且容器里"没有直接办法"移除该挂载以重新显示被遮蔽的文件。 - NFS 等远端文件系统:
unlink(2)的 EBUSY 条目直接点名了 NFS 客户端的 "silly renamed" 无名 inode;Linux NFS 项目文档解释了原因——NFSv3 协议没有表达"删除但仍保留被打开文件"的语义,客户端只能对打开文件的 unlink 采用 silly rename 这一 hack(生成.nfsXXXX临时名)。RFC 1813 里对应的协议错误码是NFS3ERR_ROFS(在只读文件系统上做修改操作)与NFS3ERR_NOTEMPTY。
十三、确诊流程
lsattr(目录用-d/-R)→ 有i/a就先清掉;mount | grep 目标→ 确认是不是挂载点、是否只读;rmdir/unlink报的错对照手册:EPERM(不可变/粘滞位)、EACCES(权限或 SELinux)、EROFS(只读)、EBUSY(挂载点/NFS)、ENOTEMPTY(非空);df/ls -l /proc/<pid>/fd→ 排除"删了但被占用";- 还不行就看审计:
ausearch -m AVC...查安全模块拒绝; - 走到这里还没解决,再去怀疑文件系统的属性支持:
man 5 <fstype>确认该文件系统到底支持哪些属性。
参考来源
- man7.org, chattr(1)(
i/a/s/u定义、文件系统支持、BUGS 段)— https://man7.org/linux/man-pages/man1/chattr.1.html - man7.org, lsattr(1) — https://man7.org/linux/man-pages/man1/lsattr.1.html
- man7.org, ioctl_iflags(2)(inode flags 与两个 ioctl、未实现的标志)— https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
- man7.org, FS_IOC_SETFLAGS(2const)(CAP_LINUX_IMMUTABLE、目录上的 append-only)— https://man7.org/linux/man-pages/man2/FS_IOC_SETFLAGS.2const.html
- man7.org, unlink(2)(EPERM/EACCES/EROFS/EBUSY、粘滞位、最后一个 fd)— https://man7.org/linux/man-pages/man2/unlink.2.html
- man7.org, rmdir(2)(ENOTEMPTY、EBUSY、sticky bit)— https://man7.org/linux/man-pages/man2/rmdir.2.html
- man7.org, rm(1)(
--、--preserve-root)— https://man7.org/linux/man-pages/man1/rm.1.html - man7.org, chmod(1) / chmod(2)(
t与 S_ISVTX)— https://man7.org/linux/man-pages/man1/chmod.1.html ・ https://man7.org/linux/man-pages/man2/chmod.2.html - man7.org, open(2)(ETXTBSY)— https://man7.org/linux/man-pages/man2/open.2.html
- man7.org, mount(8)(挂载点语义、
remount,ro)— https://man7.org/linux/man-pages/man8/mount.8.html - man7.org, ext4(5)(
errors=挂载选项)— https://man7.org/linux/man-pages/man5/ext4.5.html - man7.org, xfs(5)(XFS 支持的属性集合)— https://man7.org/linux/man-pages/man5/xfs.5.html
- man7.org, proc_pid_fd(5) — https://man7.org/linux/man-pages/man5/proc_pid_fd.5.html
- man7.org, ausearch(8) — https://man7.org/linux/man-pages/man8/ausearch.8.html
- man7.org, avc_has_perm(3)(SELinux 拒绝返回 EACCES)— https://man7.org/linux/man-pages/man3/avc_has_perm.3.html
- Fedora Docs, Troubleshooting Problems Related to SELinux — https://docs.fedoraproject.org/en-US/quick-docs/selinux-troubleshooting/
- RFC 1813, NFS Version 3 Protocol Specification(NFS3ERR_ROFS / NFS3ERR_NOTEMPTY)— https://datatracker.ietf.org/doc/html/rfc1813
- Linux NFS, Server-side silly rename — https://wiki.linux-nfs.org/wiki/index.php/Server-side_silly_rename
- Linux Kernel Documentation, Overlay Filesystem(whiteout / opaque)— https://docs.kernel.org/filesystems/overlayfs.html
- Docker Docs, Volumes(挂载遮蔽原文件)— https://docs.docker.com/engine/storage/volumes/