本文没有配图,总结自今天上午的经历,折腾了好久的经验与教训。

想给电脑装另一个Linux系统体验一番,但是装系统的固态盘已经被当前系统(Ubuntu)的根分区给占满了。根分区的利用率比较低,140G的空间,只用了20G多。因此,可以通过缩容根分区,来腾空间给另一个Linux。

通过上网搜索"ext4 根目录 分区 缩容"等信息,看到的大多都是LVM体系下的操作,但我这是个人电脑,不是服务器,我闲得慌我才用LVM。还有的说进救援模式,才能取消挂载根分区,来缩容,但事实上进入救援模式后,根分区也会自行挂载,无法卸载。

最后,只能是通过U盘启动(或者别的方式,总之是启动另一个系统),才能操作这个Ubuntu的根分区。

一个ext4分区的大小,事实上由两个数据构成,其一是分区的超级块(superblock)里面的数据,其二是硬盘的分区表记录的数据。前者称为filesystem size,后者称为physical size。只有当前者小于等于后者的时候,分区才能正常工作。大多数情况下,二者的大小是相同的。

没错,确信是小于等于,我说的,并且实践过

下文为了书写方便,我把filesystem size简称为fs,physical size简称为ps。

通过lsblk、parted、fdisk、cfdisk,看到的(以及能调整的)分区大小,是ps。

resize2fs能调整的,是fs。

扩容的时候,一般是先用parted,调大分区的ps。(此时满足条件fs<=ps,分区还是正常的) 再用resize2fs将fs大小调整为跟ps一致。这时fs=ps,扩容完毕。

但是缩容的时候,就不能这么来了,为了不让分区出问题,顺序得反过来。先缩小fs,再缩小ps。

先用resize2fs查看分区能缩容的最小值,-P参数即是干这个的。

resize2fs -P /dev/{分区}

显示的结果单位不是字节,是块(block)数量。一般一个块是4KB。将这个数据乘以块数量,就能得到能缩容的最小空间大小。

开始缩小fs。确定缩小后的fs大小(即块数量),注意不能小于上面查到的最小值。假设我的分区原本是100G,我要缩容到60G,那么缩容后的块大小就是 60×1024×1024÷4=15728640。

为了防止读者或者以后的自己看不懂,我来捋一捋这个怎么算的。在本机中,一个块大小是4K,这个可能会跟读者的设备有不同,请从实际情况触发。

60(G) × 1024(M/G) ×1024(K/M)=62914560(K) 得到KB的数据量

62914560(K) ÷ 4 (K/block) = 15728640 (block) 得到块的数量

因此可以放心缩容fs

resize2fs -f /dev/{分区} 15728640(上面算得的块数量,但建议再填少一点)

然后缩容ps,使用parted或者cfdisk都行。

为什么上面缩容fs的时候,让块数量填得更少一点呢?因为缩容ps的时候,如果缩容的大小缩得跟fs一样,都是60G,那么完全有可能,ps的块数量变得比fs少了。(尽管只有几个block的差异,但仍然会出问题)

ps缩容完毕后,再用resize2fs,调整fs的大小,跟ps一致。

resize2fs -f /dev/{分区}

至此,缩容完成。

整个过程其实分三步

初始状态,fs=ps

fs |-------------------| 100G

ps |-------------------| 100G

  1. resize2fs缩容fs

fs |----------| 59.9G (总之比60G要小,比可缩容的最小空间要大)

ps |-------------------| 100G

  1. parted, fdisk, cfdisk等缩容ps

fs |----------| 59.9G

ps |-----------| 60G

  1. resize2fs扩容fs到与ps相同

fs |-----------| 60G

ps |-----------| 60G

如果中间操作不慎,使得ps小于fs,导致分区出问题了,可以扩容ps,将分区后面有的(哪怕一点点的)空余空间(或保留空间)都用上。再通过resize2fs扩容fs至于ps相同,回到fs=ps的初始状态。而后再重复上面的缩容操作。