two heads deframentation
source / license: created by siulzz

Shrink LVM root partition without booting to LiveCD

28/10/2018
mDfRg

There are many tutorials in the Internet explaining how to enlarge a working root partition installed on LVM. Whether it’s ext4, xfs or other modern file system, online enlarging works most of the time. Shrinking, however, it’s another deal. XFS does not support it at all, even with unmounted file system. Reducing ext4 partition is possible, but it has to be unmounted first, which in the case of root partition is kind of problematic. If it’s a VM that you resize, then there is no big deal as long as you can ssh to the hypervisor OS. But what if you want to resize the host OS itself? That what happened to me lately and I share here my solution to the problem:

How to resize(shrink) root partition without the need to physically accessing server and boot rescue shell from liveUSB?

Disclamer

The solution given below is not thoroughly tested nor it can work in your particular case. Use at your own risk! And remember: ALWAYS, ALWAYS make backup before messing with system!

BTW: See my little script to automate backup of toor partition on LVM.

TL;DR

The script uses my personal settings, which assumes:

  1. Debian / Ubuntu based distro (although most commands are the same in other distros)
  2. Root partition is on LV root on VG srv
  3. Whole system is in one place (i.e. /boot, /var, /usr, /srv, etc are on the same /dev/srv/root LV)

Pros:

  1. You do not have to physically access the machine to make the transition.
  2. You can shrink, enlarge or even change root to the new filesystem

Cons:

  1. This is not a live resize - the procedure requires at least one reboot, so it’s not suited for enterprise zero-downtime environments.
  2. In order to preserve same paths, two reboots are required
  3. It’s easy to forget about some detail which may lead to unbootable system that you may need to rescue boot anyway, so caution is advised.

Here are the raw commands set in order. It is not a preconfigured script that you can blindly run cause you need to change your values accordingly, especially the grub-install /dev/sdX part.

lvcreate -L 10g -n root2 srv 
mkfs.ext4 /dev/srv/root2
lvcreate -s -L 5g -n root1_snap srv/root
mount /dev/srv/root1_snap /mnt/root1
mount /dev/srv/root2 /mnt/root2 
cd /mnt/root1
rsync -avP ./ /mnt/root2/
cd /mnt/root2/
umount /mnt/root1
lvremove /dev/srv/root1_snap
sed -i -e 's/srv-root/srv-root2/g' etc/fstab 
sed -i -e "s/$(lvdisplay srv/root | grep 'LV UUID' | awk '{print $3; exit}')/$(lvdisplay srv/root2 | grep 'LV UUID' | awk '{print $3; exit}'/g" boot/grub/grub.cfg
for i in /dev /dev/pts /proc /sys /run; do mount -B $i /mnt/root2$i; done
chroot /mnt/root2
grub-install /dev/sdX
update-grub
exit
reboot

What does the script do?

Let’s recreate the steps that we do here.

  1. Create new LV (root2) with the desired size, make filesystem on it and mount it
  2. Create a snapshot of the running system
  3. Rsync the snapshot to root2
  4. Cleanup: unmount and delete snapshot
  5. Change the fstab entries to point to root2
  6. Change the grub.cfg setting to reflect new LV UUID and root location
  7. Chroot to new root2
  8. Reinstall and update grub so it point to the new root2

After reboot, you can additionally:

  1. Rename / delete the old root
  2. Rename the new root2 back to root, BUT in that case you have to remember to:
  3. Change the fstab entries to point to new name (root) again
  4. Change the grub.cfg setting to reflect new root location
  5. Update grub