Ubuntu 20.04
1T 内置硬盘
5T Seagate Basic 外置 USB 硬盘
昨天,我将一个非常大的 postgres 数据库移至外部 USB 驱动器,然后从主硬盘驱动器中删除了数据库目录。从那时起,df 命令显示我的 1T 内置驱动器只剩下 31G 的可用空间。du 命令与此相反。
编辑:当我移动数据库时,我实际上关闭了它,备份了它并升级了 postgres 的版本。然后我在 USB 驱动器上创建了一个新数据库并将备份恢复到其中。最后,系统向我发出了磁盘空间不足的警告,但新数据库似乎包含所有数据。
这是我运行时看到的内容du
(不包括外部 USB 驱动器)。它显示已使用 322G 空间,这与我的预期非常接近。
$ sudo du -sh --exclude=/media /
du: cannot access '/run/user/1000/doc': Permission denied
du: cannot access '/run/user/1000/gvfs': Permission denied
du: cannot access '/proc/4833/task/4833/fd/4': No such file or directory
du: cannot access '/proc/4833/task/4833/fdinfo/4': No such file or directory
du: cannot access '/proc/4833/fd/3': No such file or directory
du: cannot access '/proc/4833/fdinfo/3': No such file or directory
322G /
但是,当我运行 时df
,该驱动器上的主分区显示 839G 已使用,只有 31G 可用。我认为这不对。我尝试拔下外部 USB 驱动器,但没有任何变化。我还尝试重新启动系统,但这也没有任何变化。
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 916G 839G 31G 97% /
我也运行了lsof | grep '(deleted)'
,它返回了很多文件,其中一些似乎列出了多次,但我不知道如何永久删除它们。
lsof 命令显示的文件大多与 Brave 浏览器相关。我没有看到任何看起来像 postgres 文件的文件。不过,我收到了以下警告:
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
lsof: WARNING: can't stat() fuse file system /run/user/1000/doc
Output information may be incomplete.
有什么办法可以解决这个问题,而又不会严重锁定系统以至于我需要重新格式化驱动器?
答案1
显然,您从未重新启动该进程(可能是 PostgreSQL 服务器),甚至没有重新启动整个机器。
请注意
- 在同一个文件系统内移动文件,因为这只会移动目录链接。
- 跨文件系统或物理磁盘移动文件,因为这涉及复制和删除。
如果删除了一个文件,那么实际上只是删除了它的目录条目(指向文件数据的链接)。正确的说法是未链接,因为 libc 中的函数被调用unlink
,因为这是真正发生的情况。
如果仍有进程打开了该文件(指向该文件的文件句柄),则该进程仍会占用该文件所占用的磁盘空间。只要存在这种情况,磁盘空间就尚未释放,因此会显示df
一个值,就好像该文件仍然存在一样,但实际上du
已经看不到该文件了,因为该文件实际上已不再列在目录中。
一旦所有进程关闭该文件,也会df
显示释放的磁盘空间。
归根结底,如何彻底删除这些文件?确保打开这些文件的进程关闭它们(通过结束进程)。
答案2
需要考虑的一点是:确保 root 和用户的垃圾箱是空的。
从上到下,所有与 du、df 和文件锁相关的不同元素,以及如何清除它们以使 df 报告更多可用空间。我认为重新启动也应该这样做,所以我有点困惑。如果这不能解决您的问题,请评论此答案,我会删除它(或调整它)
为什么du
并df
显示不同的结果:
du
用于估计文件空间使用情况——文件系统上特定目录或文件下使用的空间。
df
用于显示调用用户具有适当读取权限的文件系统的可用磁盘空间量。删除一个文件后,该文件所占用的磁盘空间会慢慢释放,该命令的结果
du
不包含删除文件的大小,但df
由于删除文件所占用的磁盘空间不会立即释放,因此命令的结果中包含删除文件的大小。所以删除文件后,直到磁盘空间释放为止,
df
和的结果是不同的。du
正如您所知,您可以获得已删除但仍由应用程序打开的文件列表(我添加了 COMMAND,以便您可以更轻松地搜索)(添加一个| grep postgres
以过滤 postgres):
lsof | egrep "deleted|COMMAND"
一些例子:
COMMAND PID TID TASKCMD FD TYPE DEVI
CE SIZE/OFF NODE NAME
pipewire 35916 24u REG 0
,1 2312 7234 /memfd:pipewire-memfd (deleted)
pipewire 35916 27u REG 0
,1 2312 7235 /memfd:pipewire-memfd (deleted)
pipewire 35916 30u REG 0
,1 2312 67 /memfd:pipewire-memfd (deleted)
pipewire 35916 35944 pipewire 24u REG 0
,1 2312 7234 /memfd:pipewire-memfd (deleted)
pipewire 35916 35944 pipewire 27u REG
(这些是 chrome 临时文件)
如果在你的情况下有一个指向 postgres 的文件,请记下 PID 并执行(以 35916 为例):
ls -l /proc/35916/fd | grep deleted
例子:
lrwx------ 1 rinzwind rinzwind 64 apr 30 20:41 24 -> /memfd:pipewire-memfd (deleted)
lrwx------ 1 rinzwind rinzwind 64 apr 30 20:41 27 -> /memfd:pipewire-memfd (deleted)
lrwx------ 1 rinzwind rinzwind 64 apr 30 20:41 30 -> /memfd:pipewire-memfd (deleted)
如果您看到大文件,您可以执行以下操作(再次:将数字更改为显示的数字):
> /proc/35916/fd/30
在这种情况下,与“30”相关的内存数据将被释放(这里是 64kb),从而du
更df
准确地匹配它们的数字。
对此要非常小心,因为这可能会使实际使用该文件的任何服务崩溃。