Jan 23, 2011

Shrinking virtual disks with LVM

It is possible that what I am going to tell next can be done in other ways, but I am really sure that it will be very useful for many people. Have you ever thought how to reduce a virtual disk on VMware, KVM, Xen, etc. with a Linux filesystem created inside?

If the virtual disk just contains a filesystem such as ext3, ext4, btrfs, etc., the solution is easy: use any partition tool like GParted, shrink the partition or partitions and copy them to another virtual disk smaller.

But what happens if that virtual disk has a filesystem over a Logical Volume (LV)? The solution is not trivial, since partion tools do not support Logical Volume Management (LVM).

Then I am going to explain my solution. For my tests, I will use a CentOS 5.5 virtual machine under VMware vSphere, with a virtual disk of 64 GB (sda). That virtual disk will have two partitions: sda1 (107 MB) and sda2 (63,88 GB).

[root@centos ~]# fdisk -l

Disco /dev/sda: 68.7 GB, 68719476736 bytes
255 heads, 63 sectors/track, 8354 cylinders
Unidades = cilindros de 16065 * 512 = 8225280 bytes

Disposit. Inicio    Comienzo      Fin      Bloques  Id  Sistema
/dev/sda1   *           1          13      104391   83  Linux
/dev/sda2              14        8354    66999082+  8e  Linux LVM

The second partition (sda2) will have two LVs, LogVol00 (data area) and LogVol01 (swap).

[root@centos ~]# lvs
LV       VG         Attr   LSize  Origin Snap%  Move Log Copy%  Convert
LogVol00 VolGroup00 -wi-ao 62,88G              
LogVol01 VolGroup00 -wi-ao  1,00G

My goal will be to decrease the size of the virtual disk from 64 GB to 19 GB.




In order to be able to resize the ext3 filesystem, LV, VG (Volume Group), PV (Physical Volume) and sda2 partition, you must boot the computer in rescue mode (using for example a Live CD).

boot: linux rescue

During the boot process, we will not mount the existing Linux installation and skip directly to the command shell. Then, we have to activate all known volume groups in the system and check the filesystem to rule out possible errors on it.

sh-3.2# lvm vgchange -a y

sh-3.2# e2fsck -f /dev/VolGroup00/LogVol00

Afterwards, first we must resize the filesystem from 62,88 GB to 16 GB and then, the LV.

sh-3.2# resize2fs /dev/VolGroup00/LogVol00 16G

sh-3.2# lvm lvresize --size 16G /dev/VolGroup00/LogVol00

Because we have reduced the LogVol00 size, now there is a gap between both volumes and it is better that we remove LogVol01 and recreate it again.

sh-3.2# lvm lvremove /dev/VolGroup00/LogVol01

sh-3.2# lvm lvcreate --size 1G --name LogVol01 VolGroup00

sh-3.2# mkswap /dev/VolGroup00/LogVol01

Next step is to decrease the size of the PV. We need 16 GB for the data area and 1 GB for the swap.

sh-3.2# lvm pvresize /dev/sda2 --setphysicalvolumesize 17G
/dev/sda2: cannot resize to 511 extens as 544 are allocated.
0 physical volume(s) resized / 1 physical volume(s) not resized

We can see that we must fit correctly that space... it is easy, a simple rule of three (17*544/511).

sh-3.2# lvm pvresize /dev/sda2 --setphysicalvolumesize 17.03G
Physical volume "/dev/sda2" changed
1 physical volume(s) resized / 0 physical volume(s) not resized

And finally, we have to resize that sda2 partition. To calculate the end sector, first we must take a look at the partition map in sectors (one sector is 512 bytes), get the starting point of the sda2 partition (208845s), add it the size of the PV (35651584s) and also add a security margin of around 64 MB (131072s).

sh-3.2# lvm pvs --units s
PV         VG         Fmt  Attr PSize     PFree
/dev/sda2  VolGroup00 lvm2 a-   35651584S    0S

sh-3.2# parted /dev/sda unit s print
Disk /dev/sda: 134217727s
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start    End         Size        Type     File system  Flags
1      63s      208844s     208782s     primary  ext3         boot
2      208845s  134207009s  133998165s  primary               lvm

Now we can resize the partition: 208845 + 35651584 + 131072 = 35991501.

sh-3.2# parted /dev/sda rm 2

sh-3.2# parted /dev/sda mkpart primary 208845s 35991501s

sh-3.2# parted /dev/sda set 2 lvm on

sh-3.2# parted /dev/sda print
Disk /dev/sda: 68.7GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
1      32.3kB  107MB   107MB   primary  ext3         boot
2      107MB   18.4GB  18.3GB  primary               lvm

It is necessary check again the filesystem to see that all is right.

sh-3.2# e2fsck -f /dev/VolGroup00/LogVol00

Now we have to add a second virtual disk (19 GB) to the system and copy the data from sda to sdb.

sh-3.2# dd if=/dev/sda of=/dev/sdb bs=1M &

When the task is complete, we must turn off the virtual machine, delete the first virtual disk (64 GB) and put the second (19 GB) as primary for the next boot.




Then we will finish starting the virtual machine.


2 comments:

  1. Hi,

    Your post has saved me for a lot of work. Thank you!

    I've took a look on your blog and I really appreciate your work.

    Keep doing it!

    ReplyDelete
  2. I am pleased that it has been useful for you.

    ReplyDelete