Mythsman


努力工作,认真生活。


记一次SSH下无法umount磁盘的问题

问题

最近在用 吃灰树莓派 + 外接硬盘盒 搭建 NAS ,由于硬盘默认的文件系统是 NTFS ,出于种种原因(参考这里),Linux 下的写入速度特别慢(我这里的酷鱼1T写入只有33MB/s)。于是我打算把硬盘格式化成 ext4

但是在测完速后准备 umount 当前磁盘(/media/pi/Seagate)时,却发生了报错:

$ dd bs=1M count=256 if=/dev/zero of=/media/pi/Seagate/test conv=fdatasync
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 8.04687 s, 33.4 MB/s

$ sudo umount /media/pi/Seagate
umount: /media/pi/Seagate: target is busy.

非常奇怪,我当前的 pwd 并不在挂载盘下,按理说应该没有进程会访问这个文件夹才对,可是他依然报了设备被占用。之前出现过这个问题时尝试过重新插入磁盘、重启机器等等操作,有时候也能莫名其妙的恢复了,但是这次正好有空,我希望能找到问题的原因。

分析

既然是进程占用了文件资源,那我就先来看下到底是谁:(注意,这里一定要加 sudo  ,否则可能会假装查不到)

$ sudo lsof /media/pi/Seagate/
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sftp-serv 1242   pi    4r   DIR    8,0     4096    5 /media/pi/Seagate
sftp-serv 1242   pi    6r   DIR    8,0     4096    5 /media/pi/Seagate

看上去是一个叫 sftp-serv 啥啥的进程,拿到进程号 1242 ,看下到底是什么:

$ ps -ef|grep 1242 | grep -v grep
pi        1242  1241  0 00:10 ?        00:00:00 /usr/lib/openssh/sftp-server

原来是 sftp-server 进程,但是我并没有手动启这个进程,systemd 下也没有这个服务,那么这个进程是谁拉起的呢?

$ pstree
systemd─┬─agetty
        ...
        ├─ssh-agent
        ├─sshd─┬─sshd───sshd───bash───pstree
        │      └─sshd───sshd───sftp-server

原来是 sshd 拉起的,毕竟我是通过 ssh 登录到机器上的,访问机器上文件的功能应当就是通过 sftp 来实现的。

那么 sftp 为啥需要加载我的这个文件么?难道他会默认拉起所有的文件?我们回头查看下:

 $ sudo lsof |grep sftp
sftp-serv  1242                              pi  cwd       DIR              179,2         4096       1407 /home/pi
sftp-serv  1242                              pi  rtd       DIR              179,2         4096          2 /
sftp-serv  1242                              pi  txt       REG              179,2       105664      13203 /usr/lib/openssh/sftp-server
sftp-serv  1242                              pi  mem       REG              179,2        51640      25196 /usr/lib/aarch64-linux-gnu/libnss_files-2.28.so
sftp-serv  1242                              pi  mem       REG              179,2      1439544      11838 /usr/lib/aarch64-linux-gnu/libc-2.28.so
sftp-serv  1242                              pi  mem       REG              179,2       136992      11834 /usr/lib/aarch64-linux-gnu/ld-2.28.so
sftp-serv  1242                              pi    0r     FIFO               0,11          0t0     300723 pipe
sftp-serv  1242                              pi    1w     FIFO               0,11          0t0     300724 pipe
sftp-serv  1242                              pi    2w     FIFO               0,11          0t0     300725 pipe
sftp-serv  1242                              pi    4r      DIR                8,0         4096          5 /media/pi/Seagate
sftp-serv  1242                              pi    5r      DIR              179,2         4096     260625 /media/pi
sftp-serv  1242                              pi    6r      DIR                8,0         4096          5 /media/pi/Seagate
sftp-serv  1242                              pi    7r      DIR              179,2         4096       1407 /home/pi

看起来 sftp 也只占用了他自己的链接库以及我当前访问的、以及曾经访问过的页面。。。

解决

既然原因找到了,解决起来就很轻松了。看似最简单的方法就是干掉占用文件的进程 sftp-server 。事实上这个方案也的确能 work ,不过 kill 进程这种事情实在不优雅,万一出锅了呢?

最简单的方法其实就是:登出 ssh,再重新登录。毕竟 sftp 进程是依附于当前会话的 sshd 进程,只要退出这个 ssh 进程,sftp 进程也就能正常终止了。