Reducing the size of your root partition. (tummy.com, ltd. Journal Entry)
tummy.com: we do linux

Monday July 30, 2007 at 14:41
Subject: Reducing the size of your root partition.
Keywords: ext2, ext3, resize, Technical
Posted by: Sean Reifschneider

I recently had a system that is quite a long distance from me that I needed to reduce the root file-system size on. To make matters worse, the IP KVM is having more than a few issues, so booting into rescue mode was not really an option. I wanted to just put "e2fsck" and "resize2fs" into the init scripts, but the system init scripts are called after the partition is mounted. Here's what I did...

resize2fs can increase the size of a mounted partition, but not reduce it. Shrinking a file-system must be done while the file-system is unmounted. This is pretty common restriction.

The initrd is run extremely early on in the boot process, and is responsible for the initial mounting of the root partition. This can be modified to run the file-system resize before mounting the partition. However, there are a few tricks.

First of all, I first set up a staging system that mimics the remote system, and ran all of my testing on that. My first attempts didn't quite work out, though none of them left the system dead in the water.

The first thing you have to do is make a backup copy of the initrd, and then extract the initrd so you can make changes to it:

[root@trac1 ~]# cp /boot/initrd-2.6.18-8.1.8.el5.img \
   /boot/initrd-2.6.18-8.1.8.el5.img.orig
[root@trac1 ~]# cd /tmp
[root@trac1 tmp]# mkdir init
[root@trac1 tmp]# cd init
[root@trac1 init]# gunzip </boot/initrd-2.6.18-8.1.8.el5.img | cpio -id
cpio: : No such file or directory
14968 blocks
[root@trac1 init]# cp /sbin/e2fsck bin
[root@trac1 init]#

The last step copies "e2fsck" into the "bin" directory.

You will also need "resize2fs", but there are a couple of problems with the system resize2fs. First of all, it is not built static. Worst though, it is unhappy running from the initrd because it can't find out of the file-system you are trying to resize is mounted. I grabbed the SRPM for resize2fs and made a modified resize2fs that's built static and skips the mounted partition check (available for download).

Once you have that extracted, you need to look at the "init" file in the top level directory. You will need to insert some lines after the "mkrootdev" command, before the "Mounting root filesystem" line. The device you use should be the same as that used in the "mkrootdev" line, and probably will be different from here:

[...]
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro /dev/vg00/sys_root
#  ADD THE FOLLOWING LINES
echo Resizing root device.
e2fsck -fy /dev/vg00/sys_root
resize2fs -p /dev/vg00/sys_root 20G
echo sleeping...
sleep 30
#  END OF ADDED LINES
echo Mounting root filesystem.
mount /sysroot
[...]

In this case we are asking for the file-system to be resized down to 20GB. Change "20G" to whatever you would like. The "sleep" command will make it easier to see any output if it errors out.

Now, re-create the initrd file with the following command:

find ./ | cpio -H newc -o | \
      gzip -9 >/boot/initrd-2.6.18-8.1.8.el5.img

Use the correct name of the initrd file which you backed up above. Note that this will overwrite the existing initrd file.

Now reboot, and during the boot it should run an fsck, then run the resize.

After the system boots the root device should be around the size you specified in the resize2fs above. You will need to move the .orig initrd file back over the one that you created above, or it will run the fsck and resize on every subsequent reboot.

Finally, resize the partition the file-system is on. If this was a regular partition, you will probably have to delete it and create it smaller. If it's an LVM as above, you can just use "lvreduce" to shrink it. I always shrink the partition to well above the size of the file-system, then use the online ext2 resize to increase it back up. This way I never have to worry about incorrect math resulting in the end of the file-system getting cut off. In my example above, I then resized the partition to 22GB, then ran "resize2fs /dev/vg00/sys_root" and it will figure out the real partition size and expand the file-system to fill the partition.

Note that if you are using a real partition you probably want to reboot after changing the partition size but before telling ext2resize to expand the file-system. Unlike with LVM, the kernel may still have an idea of the size of the partition which is much larger than it is after a reboot.
(Post Reply)

Comment
Pierfrancesco Marsiaj
Subject: You rock!
Thank you for your post about shrinking root partition. Indeed you saved me from driving 600 km to the place where the server I maintain is. It worked pretty straightforwardly on a Centos 5 with root on LVM.

Great post, great suggestion, very clever. I was about to give up, after almost 10 minutes the machine didn't respond to ping yet. The fact is that I resized from 250Gb to 20Gb and that took a while...

Thanks again!
Pierfrancesco

Comment
Skeeter
Subject: Awesome!
This worked great..! I was a little worried to run this on my server that's far far away in another land, but it worked perfectly.

I originally tried this on my Fedora 8 box, but it was saying invalid partition size. It worked fine on my CentOS5 server.

Thanks!

Comment
Eric Z
Subject: Segmentation fault on resize2fs
very good idea, but on kernel 2.4 resize2fs doesn't work

[root@linux root]# ./resize2fs
FATAL: kernel too old
Segmentation fault
Comment
Jay
Subject: Excellent :)
Excellent work :) Saved me a lot o heartache!

FYI this is pretty robust, the my DC noc noticed my server down, and rebooted it midway through the process, upon reboot they noticed my rather obvious comments (added to init) spewing across the screen about resizing in progress, and contacted me to see what was going on! The process completed no problem :)

Do you happen to have a patch for resize2fs? I'd like to make a few binaries for various systems I have which have ridiculously large / filesystems.

Cheers!