最近在用 吃灰树莓派 + 外接硬盘盒 搭建 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 进程也就能正常终止了。