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.