Friday, January 22, 2010

How to resize (grow) a Xen VM partition

I was faced with a situation whereby a partition on a Xen VM was running out of space. Luckily, there was space available on the Xen host (i.e., Dom0). Also, the partition was at the end of the virtual disk, which simplifies things. So below are the steps I took to resize the partition.

NB: This assumes a Xen host (Dom0) is not running Logical Volume Management, and the VM (DomU) has an ext3 filesystem.

First of all, stop the VM and take a backup. This is in case anything goes wrong! You will need somewhere with enough space to copy the VM .img file, taking into consideration that the partition that you copy to, may well need free space to create the larger partition :-)

Once the VM has been stopped and the backup made, it's time to add the extra space to our VM. There are several HOWTOs on this, but what worked for me was to just concatenate a file onto the VM image. When creating a VM initially, the filesystem is built on a file in the same way. Using 'dd' is easy for this.

If we can add another 10GB to the partition, dd a file onto the end of the existing image:

Assuming a VM image called 'mc3.img', do:

dd if=/dev/zero bs=1G count=10 >> /path/to/mc3.img

NB: Be very careful to make sure you have '>>'

Now the filesystem needs to be expanded onto this image. Use 'losetup' to associate the file with a device.

'losetup -f' to search for the first free loopback device

Assuming this is '/dev/loop3', associate it with the image file

'losetup /dev/loop3 /path/to/mc3.img'

You will be able to see the old partitions if you run an 'fdisk -l' on /dev/loop3.

# fdisk -l /dev/loop0

Disk /dev/loop0: 19.1 GB, 19126026240 bytes
255 heads, 63 sectors/track, 2325 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 * 1 522 4192933+ 83 Linux
/dev/loop0p2 523 783 2096482+ 82 Linux swap / Solaris
/dev/loop0p3 784 1019 1895670 83 Linux

However, the partition device nodes don't actually exist for us to be able to operate on them:

[root@xen001 vm]# fsck /dev/loop0p3
fsck 1.39 (29-May-2006)
e2fsck 1.39 (29-May-2006)
fsck.ext2: No such file or directory while trying to open /dev/loop0p3

The superblock could not be read or does not describe a correct ext2
filesystem. If the device is valid and it really contains an ext2
filesystem (and not swap or ufs or something else), then the superblock
is corrupt, and you might try running e2fsck with an alternate superblock:
e2fsck -b 8193

So use 'kpartx' to create devices in /dev/mapper. List them:

[root@xen001 vm]# kpartx -l /dev/loop0
loop0p1 : 0 8385867 /dev/loop0 63
loop0p2 : 0 4192965 /dev/loop0 8385930
loop0p3 : 0 3791340 /dev/loop0 12578895
[root@xen001 vm]# kpartx -av /dev/loop0
add map loop0p1 : 0 8385867 linear /dev/loop0 63
add map loop0p2 : 0 4192965 linear /dev/loop0 8385930
add map loop0p3 : 0 3791340 linear /dev/loop0 12578895
[root@xen001 vm]# ls -l /dev/mapper/
total 0
crw------- 1 root root 10, 62 Jan 18 12:12 control
brw-r----- 1 root disk 253, 0 Jan 22 14:36 loop0p1
brw-r----- 1 root disk 253, 1 Jan 22 14:36 loop0p2
brw-r----- 1 root disk 253, 2 Jan 22 14:36 loop0p3
[root@xen001 vm]#

We need to delete the existing partition (in our case, partition 3, /dev/mapper/loop0p3), and then recreate it to take advantage of the extra space:

[root@xen001 vm]# fdisk /dev/loop0

The number of cylinders for this disk is set to 2325.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): p

Disk /dev/loop0: 19.1 GB, 19126026240 bytes
255 heads, 63 sectors/track, 2325 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 * 1 522 4192933+ 83 Linux
/dev/loop0p2 523 783 2096482+ 82 Linux swap / Solaris
/dev/loop0p3 784 1019 1895670 83 Linux

Command (m for help): d
Partition number (1-4): 3

Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 3
First cylinder (784-2325, default 784):
Using default value 784
Last cylinder or +size or +sizeM or +sizeK (784-2325, default 2325):
Using default value 2325

Command (m for help): p

Disk /dev/loop0: 19.1 GB, 19126026240 bytes
255 heads, 63 sectors/track, 2325 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 * 1 522 4192933+ 83 Linux
/dev/loop0p2 523 783 2096482+ 82 Linux swap / Solaris
/dev/loop0p3 784 2325 12386115 83 Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.
[root@xen001 vm]#

Note how the 'End' cylinder has changed from 1019 to 2325

Now, resize filesystem (resize2fs supports resizing ext3 in 2.6.x kernels):

root@xen001 vm]# resize2fs /dev/mapper/loop0p3
resize2fs 1.39 (29-May-2006)
Resizing the filesystem on /dev/mapper/loop0p3 to 3096528 (4k) blocks.
The filesystem on /dev/mapper/loop0p3 is now 3096528 blocks long.

Fsck it:

[root@xen001 vm]# e2fsck -f /dev/mapper/loop0p3
e2fsck 1.39 (29-May-2006)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/u01: 9474/3003520 files (17.4% non-contiguous), 527247/3096528 blocks
[root@xen001 vm]#

Remove it from device mapper:

[root@xen001 vm]# kpartx -d /dev/loop0

Detach it from loop device:

[root@xen001 vm]# losetup -d /dev/loop0

Start up the VM:

[root@xen001 vm]# xm create mc3
Using config file "/etc/xen/mc3".
Started domain mc3
[root@xen001 vm]#

And you're done