我有一些桑巴驱动器,每天都有多个用户访问。我已经有代码来识别共享驱动器(从SQL表(并将它们挂载到所有用户都可以访问它们的特殊目录中。
我想知道,如果我从SQL表中删除驱动器(有效地使其脱机(,如何甚至有一种方法可以卸载繁忙的设备?到目前为止,我发现任何形式的umount
都不起作用。
忽略破坏数据的可能性 - 是否可以卸载当前正在读取的设备?
是的!!有一种方法可以立即分离繁忙的设备 - 即使它很忙并且无法强制卸载。您可以稍后清理所有内容:
umount -l /PATH/OF/BUSY-DEVICE
umount -f /PATH/OF/BUSY-NFS (NETWORK-FILE-SYSTEM)
注意/注意事项
- 这些命令可能会中断正在运行的进程,导致数据丢失或损坏打开的文件。访问目标设备/NFS 文件的程序可能会引发错误或在强制卸载后无法正常工作。
- 当在挂载的路径(文件夹/驱动器/设备(本身内时,不要执行上述
umount
命令。首先,您可以使用pwd
命令来验证当前目录路径(不应是挂载的路径(,然后使用cd
命令退出挂载的路径 - 稍后使用上述命令将其卸载。
可能,让我们定位/识别繁忙的进程,终止该进程,然后unmount
桑巴共享/驱动器以最大程度地减少损害:
lsof | grep '<mountpoint of /dev/sda1>'
(或任何安装的设备(pkill target_process
(按名称杀死忙碌的过程|kill PID
|killall target_process
(umount /dev/sda1
(或任何安装的设备(
当您尝试卸载时,请确保您尚未在装载的设备中。
避免umount -l
在撰写本文时,投票最多的答案建议使用 umount -l
.
umount -l
是危险的,或者充其量是不安全的。总结:
- 它实际上不会卸载设备,它只是从命名空间中删除文件系统。可以继续写入打开的文件。
- 它可能导致 btrfs 文件系统损坏
变通/替代
umount -l
的有用行为是通过绝对路径名隐藏文件系统,从而最大限度地减少进一步的moutpoint使用。
通过挂载一个空目录来实现相同的行为,该空目录的权限000
要卸载的目录。
然后,对挂载点下方文件名的任何新访问都将以零权限访问新覆盖的目录 - 从而防止卸载的新阻止程序。
首先尝试remount,ro
要解锁的主要卸载成就是只读重新装载。当您获得remount,ro
徽章时,您就知道:
- 所有挂起的数据都已写入磁盘
- 所有将来的写入尝试都将失败
- 数据处于一致状态,如果您需要从物理上断开设备。
如果有文件打开进行写入,mount -o remount,ro /dev/device
肯定会失败,因此请直接尝试。你可能觉得很幸运,朋克!
如果您不走运,请只关注打开文件进行写入的进程:
lsof +f -- /dev/<devicename> | awk 'NR==1 || $4~/[0-9]+[uw -]/'
然后,您应该能够以只读方式重新装载设备并确保状态一致。
如果此时无法以只读方式重新装载,请调查此处列出的其他一些可能原因。
只读重新挂载成就已解锁 🔓☑
恭喜,挂载点上的数据现在已保持一致,并且受到保护,不会在将来写入。
为什么fuser
不如lsof
为什么不早点使用fuser
?好吧,你可以这样做,但是fuser
对目录而不是设备进行操作,所以如果你想从文件名空间中删除挂载点并仍然使用fuser
,你需要:
- 临时将装载点复制到另一个位置
mount -o bind /media/hdd /mnt
- 隐藏原始挂载点并阻止命名空间:
方法如下:
null_dir=$(sudo mktemp --directory --tmpdir empty.XXXXX")
sudo chmod 000 "$null_dir"
# A request to remount,ro will fail on a `-o bind,ro` duplicate if there are
# still files open for writing on the original as each mounted instance is
# checked. https://unix.stackexchange.com/a/386570/143394
# So, avoid remount, and bind mount instead:
sudo mount -o bind,ro "$original" "$original_duplicate"
# Don't propagate/mirror the empty directory just about hide the original
sudo mount --make-private "$original_duplicate"
# Hide the original mountpoint
sudo mount -o bind,ro "$null_dir" "$original"
然后,您将拥有:
- 隐藏的原始命名空间(无法打开更多文件,问题不会变得更糟(
- 重复绑定挂载的目录(与设备相对(,其上运行
fuser
.
这更复杂[1],但允许您使用:
fuser -vmMkiw <mountpoint>
这将以交互方式要求终止打开文件进行写入的进程。当然,您可以在完全不隐藏挂载点的情况下执行此操作,但上述模仿umount -l
,没有任何危险。
-w
开关仅限于写入进程,-i
是交互式的,因此在只读重新挂载后,如果您赶时间,可以使用:
fuser -vmMk <mountpoint>
终止在挂载点下打开文件的所有剩余进程。
希望此时您可以卸载设备。(如果已绑定装载的模式000
目录,则需要在挂载点上运行umount
两次。
或使用:
fuser -vmMki <mountpoint>
以交互方式终止阻止卸载的剩余只读进程。
该死的,我还target is busy
!打开的文件并不是唯一的卸载阻止程序。请参阅此处和此处以了解其他原因及其补救措施。
即使您有一些潜伏的小鬼阻止您完全卸载设备,您至少已经使您的文件系统处于一致的状态。
然后,您可以使用 lsof +f -- /dev/device
列出包含文件系统的设备上具有打开文件的所有进程,然后终止它们。
[1] 使用mount --move
不那么复杂,但这需要mount --make-private /parent-mount-point
,这有含义。基本上,如果挂载点挂载在/
文件系统下,则希望避免这种情况。
请尝试以下操作,但在运行之前请注意,-k
标志将终止任何使设备保持繁忙的正在运行的进程。
-i
旗fuser
杀人前问。
fuser -kim /address # kill any processes accessing file
unmount /address
在卸载文件系统之前。 我们需要检查是否有任何进程持有或使用文件系统。这就是为什么它显示设备繁忙或文件系统正在使用中。运行以下命令以找出文件系统使用的进程:
fuser -cu /local/mnt/
它将显示有多少进程持有/使用文件系统。
local/mnt: 1725e(root) 5645c(shasankarora)
ps -ef | grep 1725
<--> ps -ef | grep <pid>
kill -9 pid
杀死所有进程,然后您将能够卸载分区/忙碌设备。
使用 exportfs -v 检查导出的 NFS 文件系统。如果找到,请使用 exportfs -d share:/directory 删除。这些不会显示在 fuser/lsof 列表中,并且可能会阻止卸载成功。
万一有人有相同的pb。
我无法卸载 chroot 监狱的挂载点(这里/mnt
(。
以下是我键入的用于调查的命令:
$ umount /mnt
umount: /mnt: target is busy.
$ df -h | grep /mnt
/dev/mapper/VGTout-rootFS 4.8G 976M 3.6G 22% /mnt
$ fuser -vm /mnt/
USER PID ACCESS COMMAND
/mnt: root kernel mount /mnt
$ lsof +f -- /dev/mapper/VGTout-rootFS
$
正如您所注意到的,即使lsof
也不会返回任何内容。
然后我想输入这个:
$ df -ah | grep /mnt
/dev/mapper/VGTout-rootFS 4.8G 976M 3.6G 22% /mnt
dev 2.9G 0 2.9G 0% /mnt/dev
$ umount /mnt/dev
$ umount /mnt
$ df -ah | grep /mnt
$
这是我创建的/dev
绑定/mnt/dev
,以便能够从chroot监狱内部修复我的系统。
卸载后,我的 pb. 现在已经解决了。
查看umount2
:
Linux 2.1.116 添加了 umount2(( 系统调用,它与 umount(( 一样,卸载目标,但允许控制操作行为:
MNT_FORCE(从 Linux 2.1.116 开始(即使繁忙也强制卸载。(仅适用于NFS 挂载。MNT_DETACH(从 Linux 2.4.11 开始(执行延迟卸载:使挂载点不可用于新访问,实际上当挂载点不再繁忙时执行卸载。
MNT_EXPIRE(从 Linux 2.6.8 开始(将挂载点标记为已过期。如果是挂载点当前未在使用中,然后使用此对 umount2(( 的初始调用标志失败并显示错误 EAGAIN,但将装入点标记为过期。只要未访问挂载点,它就会保持过期状态通过任何过程。指定卸载MNT_EXPIRE第二个 umount2(( 调用过期的装入点。不能用任一方式指定此标志MNT_FORCE或MNT_DETACH。
我最近有类似的卸载需求,以便用 gparted 更改它的标签。
/dev/sda1 通过/etc/fstab 挂载为/media/myusername。 当尝试卸载失败时,我研究了该错误。我忘了先卸载带有/dev/hda1 挂载点的双分区拇指驱动器。
我按照建议给了"lsof"一个尝试。
$ sudo lsof | grep /dev/sda1
其输出为:
lsof: 警告: 不能 stat(( fuse.gvfsd-fuse file system/run/user/1000/gvfs
输出信息可能不完整。
lsof:警告:无法 stat(( 融合文件系统/run/user/1000/doc
输出信息可能不完整。
由于 lsof 打了两个保险丝警告,我在/run/user/1000/* 中四处寻找,并猜测可能是打开的文件或挂载点(或两者兼而有之(干扰了事情。
由于挂载点位于/media/中,我再次尝试:
$ sudo lsof | grep /media
相同的两个警告,但这次它返回了其他信息:
bash 4350 我的用户名 CWD DIR 8,21 4096 1048577/媒体
须藤 36302 根 CWD DIR 8,21 4096 1048577/媒体
grep 36303 我的用户名 CWD DIR 8,21 4096 1048577/media
LSOF 36304 根 CWD DIR 8,21 4096 1048577/媒体
LSOF 36305 根 CWD DIR 8,21 4096 1048577/媒体
我仍然挠头,就在这时,我想起了从USB端口伸出的拇指驱动器。也许抓挠有所帮助。
所以我卸载了拇指驱动器分区(卸载一个会自动卸载另一个(,然后 safefly 拔下拇指驱动器。这样做之后,我能够卸载/dev/sda1(上面不再挂载任何东西(,用 gparted 重新标记它,重新安装驱动器和拇指驱动器,没有任何问题。
培根得救了。
提到,如果您使用的是终端并且当前目录位于要卸载的路径内,则会收到错误。
作为补充,在这种情况下,您的lsof | grep path-to-be-unmounted
必须具有以下输出:
bash ... path-to-be-unmounted
sudo fusermount -u -z <mounted path>
注意:不要对路径使用完成,因为这也会冻结终端。
当一切正常时,另一种选择是编辑/etc/fstab
,添加noauto
标志并重新启动机器。设备不会被挂载,当你完成任何操作时,删除标志并重新启动。
利基答案:
如果该设备上有 zfs 池,至少当它是基于文件的池时,lsof
不会显示使用情况。但你可以简单地运行
sudo zpool export mypool
然后卸载。
文件夹中的多个装载
另一个原因可能是主挂载文件夹中的辅助挂载,例如,在您为嵌入式设备处理 SD 卡之后:
# mount /dev/sdb2 /mnt # root partition which contains /boot
# mount /dev/sdb1 /mnt/boot # boot partition
卸载/mnt 将失败:
# umount /mnt
umount: /mnt: target is busy.
首先,我们必须卸载引导文件夹,然后卸载根目录:
# umount /mnt/boot
# umount /mnt
就我而言,我无法卸载挂载到作为 AFP 共享的目录的分区。 (分享到Apple bonjour/avahi mdns世界(我将服务器上的所有登录名都移到了他们的主目录;我将所有远程连接的Mac移动到其他目录。即使使用 umount -f 我仍然无法卸载分区所以我在服务器上重新启动了netatalk守护进程.
(/etc/netatalk/afp.conf 中有股份转让(在 netatalk 重新启动后,umount 在没有 -f 的情况下成功。