释放被文件系统吃掉的 5% 磁盘空间

使用 ext 文件系统存储数据的同学也许发现,200 G 的分区只能用 190 G,2000 GB 的分区只能用 1900 GB。这 5% 磁盘空间到哪里去了?有的同学认为这是 1000 进制与 1024 进制的区别,但事实并非如此。

$ df /mnt/sdb/
Filesystem      1K-blocks       Used Available Use% Mounted on
/dev/sdb       1922860936 1839798972         0 100% /mnt/sdb

上面这块标称 2 T 的磁盘可用空间为 0,看起来是满了。试着创建一个目录,发现没有空间了。

$ mkdir hello
mkdir: cannot create directory `hello': No space left on device

但 sudo mkdir hello 竟然能成功!这是怎么回事呢?答案在 ext 文件系统的 “预留空间” 里。

很久很久以前,磁盘没有分区的概念,只有一个文件系统,系统数据和用户数据都放在上面。这就带来一个问题,如果有的用户塞满了磁盘,那么系统日志就无法写入,有可能连远程登录都不工作了。为了避免低权限用户占满磁盘、干扰系统运行,ext 文件系统为 root 用户预留了 5% 磁盘空间,也就是当磁盘使用量达到 95% 以上时,普通用户就不能写入新数据了,只有 root 可以写入新数据,这样就能保证以 root 身份运行的系统服务能正常写入日志。

时过境迁,现在的 PC 和服务器上系统数据和用户数据大多存储在不同的分区里,而且用户数据分区往往动辄上百 G 甚至上 T,在用户数据分区为 root 预留 5% 的磁盘空间不仅没有必要,而且会造成极大的浪费。可惜的是,我所见过的 GNU/Linux 发行版的安装程序都没有考虑到这一点,而是仍然使用默认参数格式化分区。

如何看到这些预留磁盘空间呢?假设 ext 文件系统的分区是 /dev/sdb:

$ sudo tune2fs -l /dev/sdb | grep -i 'block count'
Block count:              488378646
Reserved block count:     24418932
一个 block 一般是 4 KB,可以看到 Block count 与 df 显示的 1K-blocks 数吻合。而 Reserved block count 恰好占了 5%。 要把这些被文件系统吃掉的磁盘空间释放出来(即让 root 以外的用户也能使用),一条命令,实时生效:
sudo tune2fs -m 0 /dev/sdb

然后磁盘瞬间就 “多出来” 了几十 G 空间…… 当您的数据分区快满的时候,不妨试试 tune2fs -m 0,尝尝磁盘利用率瞬间降低 5% 的感觉。

$ df -l /mnt/sdb/
Filesystem      1K-blocks       Used Available Use% Mounted on
/dev/sdb       1922860936 1839798968  83061968  96% /mnt/sdb

另外需要注意,ext 文件系统中的 inode 数量也是有限的,每个目录和文件都要占一个 inode,有时磁盘空间没满,但 inode 满了,也是无法新建文件的。可以用 df -i 或 tune2fs -l 查看 inode 的使用情况:

$ df -i /mnt/sdb/
Filesystem        Inodes    IUsed    IFree IUse% Mounted on
/dev/sdb       122101760 41070990 81030770   34% /mnt/sdb