codeblog code is freedom — patching my itch


kvm disk image filesystem growth notes

Filed under: Blogging,Debian,Ubuntu,Ubuntu-Server — kees @ 12:14 pm

Here are my notes on growing a KVM disk image’s root filesystem. I had a few 4G partitions that really needed to be bigger. This shows how to get a report on the sizes of the disk images, convert them to raw, work on the partition tables, grow the root filesystem, and rebuild the swap partition with the original UUID. With some work, it could probably become fully scripted, but since the partition layout may not always be the same from VM to VM, the “fdisk” step needs human interaction to delete and rebuild the partition table. Note that the method below also maintains the sparseness of the images.

# Look for files to change
for i in /vmware/*/*{vmdk,qcow2}; do qemu-img info $i; done

# Pick one...
cd dir...

ORIG_TYPE=$(echo $ORIG | awk -F. '{print $NF}')
TARGET_BASE=$(basename "$ORIG" ."$ORIG_TYPE")

qemu-img convert -f "$ORIG_TYPE" "$ORIG" -O raw "$TARGET_RAW"

trunc "$TARGET_RAW" "$SIZE"

sudo kpartx -a "$TARGET_RAW"
SWAP_PART=$(for i in /dev/mapper/loop0p*; do sudo vol_id $i | \
    grep -q ^ID_FS_TYPE=swap && echo $i; done | head -n 1)
UUID=$(sudo vol_id "$SWAP_PART" | grep ^ID_FS_UUID= | cut -d= -f2)
sudo kpartx -d "$TARGET_RAW"

# use losetup otherwise fdisk doesn't know cylinder count
sudo losetup /dev/loop0 "$TARGET_RAW"
# FIXME: Need to automate fdisk (detect swap partition size, etc)
# I'm deleting the swap and growing the root partition, then re-adding swap
sudo fdisk /dev/loop0
sudo losetup -d /dev/loop0

sudo kpartx -a "$TARGET_RAW"
sudo e2fsck -f /dev/mapper/loop0p1
sudo resize2fs /dev/mapper/loop0p1
sudo mkswap -U "$UUID" "$SWAP_PART"
sudo kpartx -d "$TARGET_RAW"

qemu-img convert -f raw "$TARGET_RAW" -O "$TARGET_TYPE" "$TARGET"
# FIXME: change disk image path
sudo vi /etc/libvirt/qemu/THING
# FIXME: have the daemon notice the file change
sudo /etc/init.d/libvirt-bin restart
if [ "$ORIG" != "$TARGET" ]; then rm "$ORIG"; fi

The “trunc” command above is based on my network backups post, but is now a general script I use:

# Copyright (C) 2006-2008 Kees Cook <>, License: GPLv3
use strict;
use warnings;

my $filename = $ARGV[0];
die "Need valid size also\n" unless ($ARGV[1] =~ /^(\d+)([KMG])$/);
my $size       = $1 + 0;
my $multiplier = $2;

$size *= 1024 if $multiplier =~ /^[KMG]$/;
$size *= 1024 if $multiplier =~ /^[MG]$/;
$size *= 1024 if $multiplier =~ /^[G]$/;

#die "Not trunc'ing existing file\n" if (-e $filename);
die "$filename: $!\n" if (!open(FILE,">>$filename"));
die "seek: $!\n" if (!(seek(FILE,$size,0)));
die "truncate: $!\n" if (!(truncate(FILE,$size)));
die "close: $!\n" if (!(close(FILE)));

© 2008, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.
Creative Commons License


  1. You might think about using virsh to redefine the specific virtual machine image instead of restarting libvirt and all your virtual machines. Something along the lines of:

    sudo virsh
    define /etc/libvirt/qemu/64bit-Ubuntu-7.10-desktop.xml

    Comment by Brian Murray — 12/17/2008 @ 4:27 pm

  2. I used your instructions with a Windows XP virtual machines with an NTFS filesystem and there were a couple of things I needed to do differently.

    When using fdisk, ‘sudo fdisk /dev/loop0’, I had to delete the existing partition. Create a new partition of the same type, 7 for NTFS, but larger. Make the partition active / bootable – I forgot that and had a moment of panic!

    After mounting the partition, ‘sudo kpartx -a windows-xp.img’, I used ntfsresize to resize the parition. The commmand looked like ‘sudo ntfsresize –size 20G /dev/mapper/loop0p1’.

    That’s it, thanks for the help!

    Comment by Brian Murray — 12/18/2008 @ 8:10 am

Leave a Reply

Your email address will not be published. Required fields are marked *

Powered by WordPress