rm: cannot remove 'filename': Device or resource busy的解决方法

今天删除备份的时候出现了 rm: cannot remove ‘filename’: Device or resource busy 的报错,本文记录了原因与解决方法。

查看挂载情况

1
df -h


发现要rm的目录中挂载了一个数据盘。于是对其进行umount ,这时提示

1
2
3
4
5
6
7
8
umount: filename: target is busy
```

### 用 fuser 终止进程
在通过参数指定挂载点时,fuser 命令的 -k 选项会自动地终止找到的进程。当然,必须作为root执行 fuser 命令,才能终止属于其他用户的进程。
命令格式为
``` bash
fuser -k filename

使用df -h再次查看挂载情况

确认无误后,再次执行

1
rm -rf filename

完成删除。

拓展

参考资料:@竹影青瞳
  umount 命令的标准 Linux 版本包含一个延迟卸载选项 -l,它有助于卸载正在使用的文件系统。这个命令需要 Linux 内核 2.4.11 或更高版本,目前这通常没问题。执行 umount -l /name/of/file system 可以让指定的文件系统与系统的目录层次结构脱离,让新进程不能使用这个文件系统,然后当正在访问它的所有进程都终止时卸载它。这很方便,但是当需要马上卸载文件系统时它并不合适。
  如果需要马上卸载文件系统,而文件系统报告忙碌,还有其他办法。如果您是系统的惟一用户,那么只需终止阻止文件系统卸载的进程。这需要查看所有窗口,寻找 并终止正在写这个分区或使用它作为当前工作目录的暂停的进程或后台进程。但是,在有许多本地用户和远程用户的多用户系统上,这种方法是不实际的。幸运的 是,开放源码社区提供了一些命令,可以轻松地识别并终止这些进程。

用 lsof 寻找打开的文件

lsof (list open files) 命令列出特定的文件系统、目录或设备上所有打开的文件以及与它们相关联的进程。在大多数 UNIX 和类 UNIX 系统上都可以使用 lsof 命令。

  在默认情况下,lsof 命令列出当前打开的所有文件、共享库和目录,并提供尽可能多的相关信息。即使在负载很轻的系统上,这个命令的输出也非常长,因此通常通过命令行参数指定一 个目录名,或者使用管道筛选它的输出。例如,假设希望卸载挂载在 /opt2目录上的文件系统。为了查看与 /opt2 目录相关联的所有进程,应该执行下面所示的命令。

  需要终止所有这些进程,然后才能卸载 /opt2 分区。因为这个列表中的进程都不能写任何文件,所以可以使用 kill 命令并指定第二列中列出的进程 ID (PID) 以终止它们,然后就可以顺利地卸载分区。注意,PID 23402 与最后两行相关联 — 第一行表示 more 命令以 /opt2 作为当前工作目录 (cwd),第二行表示 more 命令打开了 /opt2/resume.txt 文件。
  lsof 命令还有许多选项,可以帮助您识别不同类型的文件系统上打开的文件和目录、打开了网络套接字的进程、正在使用特定的库的进程等等。lsof 命令的缺点是,必须联系用户并要求他们终止某些进程,或者自己手工终止它们。fuser 命令更复杂,但是更强大,在作为根用户运行时可以替您执行许多进程终止工作。

用 fuser 寻找用户进程

  fuser (find user processes) 命令也是一个开放源码应用程序,可以帮助您识别阻止文件系统卸载的进程。fuser 命令寻找与作为命令行参数指定的文件、目录或文件系统相关联的进程。本文主要关注对文件系统挂载点使用 fuser。关于 fuser 命令的更多信息,请参见它的在线参考信息。fuser 命令要求系统支持 /proc 文件系统。因此,在所有 Linux 发行版和 FreeBSD 系统上都可以使用它。关于获得 fuser 命令的源代码的方法请参见 网络。
  与 lsof 命令一样,作为命令行参数提供文件系统挂载点名称是使用 fuser 命令识别阻止文件系统卸载的进程的最简单方法:

1
fuser filename

fuser 命令的输出指出正在使用指定挂载点的进程的 PID。每个 PID 后面有一个字母,它表示与 PID 相关联的进程以什么方式使用指定的挂载点。最常见的字母是前面示例所示的 c,这表示指定的进程使用此文件系统上的一个目录作为当前工作目录。
但是,fuser 命令的默认输出不便于最终用户使用,即使按 Linux 标准来看也是如此。fuser 命令提供一个 -v 选项,它在 fuser 命令的输出中增加一些与标准 ps 命令相似的输出,如下面所示:

然后,可以使用标准的 kill 命令手工终止指定的进程,或者像下一节中解释的,使用 fuser 命令的一些高级功能自动地终止它们。