假设:已删除但仍打开的文件

假设:已删除但仍打开的文件

我有一个 2TB (1.8T) WD M.2 硬盘,似乎缺少了几百 GB 的存储空间,但我找不到它在哪里,也不知道是什么占用了它。我的三星 SATA SSD 也出现了这种情况,所以我认为这与硬盘本身无关。这是这两个硬盘上唯一的分区。

df说我正在使用 1.3T 的数据

trever@server:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             32G     0   32G   0% /dev
tmpfs           6.3G  5.7M  6.3G   1% /run
/dev/nvme0n1p2  1.8T  1.3T  477G  73% /

磁盘使用情况分析器 (baobab) 表示我使用了约 850GB 的空间,这似乎比我的预期更准确。我以 root 身份运行它 ( sudo baobab),并让它扫描根驱动器/,结果如下

在此处输入图片描述

然后系统监视器还显示我正在使用 1.4T,这很好,我知道可能存在一些四舍五入和/或如何计算磁盘空间。

800-900GB 的存储空间对我来说更有意义,我检查了预留空间等内容:

trever@server:~$ sudo tune2fs -l /dev/sda1 | grep -i "block count"
[sudo] password for trever: 
Block count:              976754176
Reserved block count:     48837708

/var/logs我也检查了(20GB)和(380MB)的大小/var/cache/apt/archives/,但仍然不知道这几百GB丢失到了哪里。

对于什么可以占用这个空间还有其他建议吗?

更新:随着时间的推移,越来越多的空间似乎消失了。我现在的情况如下:

trever@server:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             32G     0   32G   0% /dev
tmpfs           6.3G  5.3M  6.3G   1% /run
/dev/nvme0n1p2  1.8T  1.6T  157G  92% /

以下是我可以解释的:

root@server:~# du -cha --max-depth=1 --exclude=/Volumes/* / | grep -E "M|G"
42M /scripts
du: cannot access '/proc/44457': No such file or directory
du: cannot access '/proc/44535': No such file or directory
du: cannot access '/proc/44586/task/44586/fd/4': No such file or directory
du: cannot access '/proc/44586/task/44586/fdinfo/4': No such file or directory
du: cannot access '/proc/44586/fd/3': No such file or directory
du: cannot access '/proc/44586/fdinfo/3': No such file or directory
94G /var
du: cannot access '/run/user/1000/gvfs': Permission denied
5.3M    /run
2.1G    /swapfile
183M    /boot
14M /etc
538G    /docker
202G    /home
8.9G    /usr
6.0G    /snap
1.8G    /root
852G    /
852G    total

我已经做了fsck,看起来不错。我不知道是什么神奇地占用了我的空间,但这很令人担忧。

答案1

假设:已删除但仍打开的文件

根据目前提供的信息,并暗示存在大量与 docker 相关的文件,我怀疑这是由已删除但仍打开的文件引起的,即由程序创建的文件,然后程序删除文件系统路径,同时保持文件描述符仍然打开。

这可能是 Docker 在文件系统上活动的结果。

解决方案原理

  • 揭示仍然被进程引用的已删除文件(方法见下文)。
  • 最好透露进程名称和/或 ID,以便您了解正在发生的事情。
  • 关闭这些进程,观察空间是否被释放。
  • 如果其他方法都失败了,就重启机器。如果空间释放了,则与假设一致。

如何披露信息

以下命令将通过查找并显示哪个文件使用了哪个空间来测试假设。

初见

为了进行基本了解,您可以发出以下命令:

lsof -n | egrep -w "deleted|^COMMAND"

但这也会列出许多不占用任何实际存储空间的仅内存中的伪文件。

例子:

COMMAND       PID     TID TASKCMD              USER   FD      TYPE             DEVICE   SIZE/OFF       NODE NAME
Xorg         1183                              root   78u      REG                0,1          4       2058 /memfd:xshmfence (deleted)
Xorg         1183                              root   85u      REG                0,1          4       7182 /memfd:xshmfence (deleted)
Xorg         1183                              root   92u      REG                0,1          4       7137 /memfd:xshmfence (deleted)
Xorg         1183                              root   94u      REG                0,1          4       7870 /memfd:xshmfence (deleted)

过滤的简单列表

这将进行过滤并主要显示真实文件:

lsof -F "sn" -lnPX -M | sed -n 's|^n/|/|p' | grep deleted | egrep -v '^/(dev/shm|memfd:|proc)' | LC_ALL=C sort -n | uniq

例子:

/tmp/#someinodenumber (deleted)

完整信息,包含大小、流程和任务名称

这更有趣:它将列出所有文件以及它们占用的空间(以字节为单位)等等。

首先,缓慢的部分,收集数据

# You may want to run this part as root to make sure all is reported
lsof -F "ctsupMin" -lnPX -M >|/tmp/lfosoutput 

然后进行处理和格式化以获得漂亮的显示,完成并按大小递增排序

# Can be run as regular user, no need for root
{ echo "SIZE^UID^PID^PROCESS NAME^TASK NAME^INODE^PATH"
</tmp/lfosoutput \
python3 -c $'import sys ; f={}
def g(c): return f.get(c,"(unknown)")
for line in sys.stdin:
 c=line[0] ; r=line[1:].rstrip() ; f[c]=r
 if c=="n" and f["t"]=="REG" \
    and "(deleted)" in f["n"] \
    and not f["n"].startswith("/memfd:") \
    and not f["n"].startswith("/dev/shm") :
  print(f'\''{g("s")}^{g("u")}^{g("p")}^\"{g("c")}\"^\"{g("M")}\"^{g("i")}^{g("n")}'\'')
  f={}' \
| LC_ALL=C sort -n | uniq
echo "SIZE^UID^PID^PROCESS NAME^TASK NAME^INODE^PATH"
} | column -t -s '^'

示例输出:Firefox 使用的一个 36 MB 的文件

SIZE       UID        PID        PROCESS NAME       TASK NAME          INODE     PATH
36012032   1234       12345      "Isolated Web Co"  "StyleThread#2"    1234567   /tmp/mozilla-temp-12345 (deleted)
SIZE       UID        PID        PROCESS NAME       TASK NAME          INODE     PATH

(实际上这样的句子还有很多,这只是其中一个例子。)

通过创建一个脚本来测试它是否确实揭示了此类文件

在另一个终端中,复制粘贴以下内容:

# Run python interactive interpreter
python3
# Now in Python
n="/tmp/whatever_file_name_you_want"
f=open(n,mode='a')
import os
os.unlink(n)
f.write("some sentence")
f.flush()
# Don't exit now or the file will really disappear

在第一个终端中,您可以运行上述两个步骤(缓慢的 lsof 然后是格式化部分)。只要上面的 python 进程处于活动状态,就会报告此行:

SIZE  UID   PID      PROCESS NAME  TASK NAME  INODE    PATH
13    1000  1387343  "python3"     "gdbus"    1308894  /tmp/whatever_file_name_you_want (deleted)
SIZE  UID   PID      PROCESS NAME  TASK NAME  INODE    PATH

然后你可以退出上面的python解释器(按Control-D或输入exit(0))。如果您运行两个部分(缓慢的 lsof 然后是格式化部分),您将发现测试文件不再出现。

上面的脚本可以修改为写入大量数据(例如数百 GB),使用常用工具,您将看到只有在创建进程关闭文件描述符后,空间才会真正释放。结束进程足以确保文件描述符已关闭。

回到你的案子

运行此命令,您很可能会看到进程名称、任务名称和文件。要么是一些大文件(如 Docker 从网络获取的镜像),要么是大量小文件(再次来自 Docker)。

或者是其他东西。

请告诉我这是否对您有帮助。

相关内容