Resizing ext3-on-LVM-on-dmcrypt file systems, moving disk space from one LV to another

Back in 2008 I wrote a small article about resizing LVM physical volumes. I had to do something similar, but slighly more complicated, recently. My /usr logical volume (LV) was getting full on my laptop disk, thus I wanted to shrink another LV and move some of that space to /usr. Here's one way you can do that.

Requirements: a Live CD containing all required utilities (cryptsetup, LVM tools, resize2fs), I used grml.

Important: If you plan to perform any of these steps, make sure you have recent backups! I take no responsibility for any data loss you might experience. You have been warned!

First, shutdown the laptop and boot using the Live CD. Then, open the dm-crypt device (/dev/hda3 in my case) by entering your passphrase:

  $ cryptsetup luksOpen /dev/hda3 foo

Activate all (newly available) LVM volume groups in that encrypted device:

  $ vgchange -a y

(maybe you also need a vgscan and/or lvscan, not sure)

Check how much free space we have for putting into our /usr LV:

  $ vgdisplay | grep Free
  Free  PE / Size       0 / 0   

OK, so we have none. Thus, we need to shrink another LV (/home, in my case) and put that newly freed space into the /usr LV. In order to do that, we have to check the current size of the /home LV:

  $ mount -t ext3 /dev/vg-whole/lv-home /mnt
  $ df --block-size=1M | grep -C 1 /mnt
  $ umount /mnt

(if you know how to find out the size of an ext3 file system without mounting it, please let me know) Update: See comments for suggestions.

Write down the total amount of 1M chunks of space on the file system (116857 in my case), we'll need that later. Now run 'fsck' on the /home LVM logical volume, which is needed for the 'resize2fs' step afterwards. This will take quite a while.

  $ fsck -f /dev/vg-whole/lv-home

Next step is resizing the ext3 file system in the /home LVM logical volume, making it 1GB smaller than before (of course you must have >= 1 GB of free space on /home for that to work). We use fancy bash calculations to do the math.

Note: I'm not so sure about the sizes here, in my first attempt something went wrong and resize2fs said "filesystem too small" or the like. Maybe I'm confusing the size units from 'df' and 'resize2fs', or the bash calculation goes wrong? Please leave a comment if you know more!

  $ resize2fs /dev/vg-whole/lv-home $((116857-1024))M

Then, we can safely reduce the LV itself. Note: order is very important here, you must shrink the ext3 filesystem first, and then shrink the LV! Doing it the other way around will destroy your filesystem!

  $ lvreduce -L -1G /dev/vg-whole/lv-home

Now that we have 1 GB of free space to spend on LVs, we assign that space to the /usr LVM logical volume like this:

  $ lvextend -L +1G /dev/vg-whole/lv-usr

As usual, we then run 'fsck' on the filesystem in order to be able to use 'resize2fs' to resize it to the biggest possible size (that's the default if resize2fs gets no parameters):

  $ fsck -f /dev/vg-whole/lv-usr
  $ resize2fs /dev/vg-whole/lv-usr

That's it. You can now shutdown the Live CD system and boot into the normal OS with the new space allocations:

  $ vgchange -a n
  $ cryptsetup luksClose foo
  $ halt


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Only possible in offline mode?


i was wondering if it is only possible to resize LVM in a cryptocontainer
if the filesystem is offline?
When i tried to resize it on a running system nothing changes, nor
it does after rebooting.


I run Debian testing 2.6.30-2-686 by the way


resize2fs call

Actually, shouldn't you write down the amount of total blocks of the filesystem you want to resize (and see wether enough space is free to resize it to current size - 1024M)?
What you are doing seems to be: Resize filesystem to amount of free space - 1024M
This will fail if free-1204M is smaller than used.

total blocks

Yes, indeed, I messed up the description (fixed now). You have to subtract 1GB from the total amount of disk space on that file system, of course. Thanks for the comment!

tune2fs -l will work

Looks a bit complicated, but this will return free space in megabytes (actually, already rounded down AFAICT):

  echo `tune2fs -l /dev/xvda1 | grep "Free blocks" | cut -d : -f 2`/1024 | bc


display size and free space of an umounted extX filesystem

this ist my approach:

# tune2fs -l /dev/sda1 | awk '/Block count:/{COUNT=$3} /Free blocks:/{FREE=$3} /Block size:/{SIZE=$3} END{ printf "size: %dMB\nfree: %dMB\n",COUNT*SIZE/1024/1024,FREE*SIZE/1024/1024 }'
size: 9546MB
free: 3108MB


BTW: thanks, nice article!

I've done very similar

I've done very similar thing, but without live CD. The difference in setup was that I didn't use encryption.

There was no need to shut down, because home partition can be unmounted and resized without restarting. The usr partition can be expanded also on the live system if you're running a recent kernel and ext2fs tools.

I'm a bit paranoid on reducing partitions, so I use the following approach to avoid exact calculation. I'm afraid that different programs use different units (i.e. 1000 vs 1024). Make the partition to be reduced a bit smaller than the target size. Then reduce lvm volume to the target size. Finally run resize2fs to extend the partition to fill the lvm volume.

May I say that I love you? I

May I say that I love you?
I really appreciate this article. I need these informations.

thanks a lot.

checking filesystem usage without mounting

Running tune2fs -l on the relevant device should report (among other interesting data) both its block size (in bytes) and how many free blocks it has, which you can multiply to determine free space.

Know the size of an extN filesystem

You could use dumpe2fs. It reports the size in blocks, but this is what you're supposed to feed to resize2fs by default anyway.
For instance:

  # dumpe2fs /dev/hda1 | egrep -i '^free blocks|^block size'
  dumpe2fs 1.41.3 (12-Oct-2008)
  Free blocks:              20434
  Block size:               1024

which means I have ~19M of free space on hda1.

#!/bin/bash blocksize=`tune2f

blocksize=`tune2fs -l $1 |grep 'Block size' | cut -d":" -f2`
freeblocks=`tune2fs -l $1 |grep 'Free blocks' | cut -d":" -f2`
blockcount=`tune2fs -l $1 |grep 'Block count' | cut -d":" -f2`

echo "$(($((${blocksize/ /}*${freeblocks/ /}))/1073741824))GB of $(($((${blocksize/ /}*${blockcount/ /}))/1073741824))GB is free on $1"
echo "That means $(($(($((${blocksize/ /}*${blockcount/ /}))/1073741824))-$(($((${blocksize/ /}*${freeblocks/ /}))/1073741824))))GB is used on the disk you stupid lazy son of a bitch!"

Not sure if it's 100% accurate, but it should be, let me know if it is not. ^^"