我有一个 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)。
或者是其他东西。
请告诉我这是否对您有帮助。