du、df 显示硬盘使用情况不一致

du、df 显示硬盘使用情况不一致

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 报告更多可用空间。我认为重新启动也应该这样做,所以我有点困惑。如果这不能解决您的问题,请评论此答案,我会删除它(或调整它)

为什么dudf显示不同的结果:

  • 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),从而dudf准确地匹配它们的数字。

对此要非常小心,因为这可能会使实际使用该文件的任何服务崩溃。

相关内容