Virtualization

KVM Storage Pools and Volumes: Attach and Expand a Disk

Create a libvirt storage pool and qcow2 volume, attach it to a running KVM guest, format it, then expand the active disk and ext4 filesystem safely.

By InventiveHQ Team

Part of the InventiveHQ KVM virtualization series. Complete Episodes 1–3 first so demo-ubuntu01 exists and is running.

The operating-system disk is only one part of a virtual machine. Databases, application data, backups, and logs often belong on separate volumes with their own capacity and lifecycle. Libvirt storage pools give those volumes a consistent management layer without hiding the underlying files or devices.

In this episode we create a directory-backed pool named tutorial-data, allocate a 5 GiB qcow2 volume, attach it to the running guest as vdb, format and mount it, then expand it to 8 GiB without stopping the VM.

Lab verified July 2026 · libvirt 12.0.0 · QEMU 10.2.1 · online ext4 expansion

Use the command builder to review storage and domain inspection commands before changing disk definitions.

Finished storage layout

ResourceValue
Pool nametutorial-data
Pool typeDirectory
Pool target/var/lib/libvirt/tutorial-data
Volumedemo-data01.qcow2
Initial capacity5 GiB
Final capacity8 GiB
Guest targetvdb using virtio
Filesystemext4 labeled demo-data
Guest mount/srv/demo-data
ScopeLive and persistent attachment

1. Inventory before creating storage

Set the system connection and inspect existing resources:

export LIBVIRT_DEFAULT_URI=qemu:///system
VM=demo-ubuntu01

virsh uri
virsh pool-list --all
virsh domblklist "$VM" --details

Refuse to reuse names or paths that already exist:

virsh pool-info tutorial-data 2>/dev/null && {
  echo "tutorial-data already exists; inspect it first"
  exit 1
}

sudo test ! -e /var/lib/libvirt/tutorial-data/demo-data01.qcow2

domblklist --details is especially important. A guest target such as vdb must not already point to another disk.

2. Define a persistent directory pool

Create the backing directory:

sudo mkdir -p /var/lib/libvirt/tutorial-data

Define, build, start, and enable the pool at boot:

virsh pool-define-as \
  tutorial-data \
  dir \
  --target /var/lib/libvirt/tutorial-data

virsh pool-build tutorial-data
virsh pool-start tutorial-data
virsh pool-autostart tutorial-data
virsh pool-info tutorial-data

pool-define-as creates a persistent definition. That differs from pool-create-as, which creates a transient pool that disappears from libvirt after it stops.

The pool reports the capacity and free space of the filesystem containing its target directory. It does not reserve all of that capacity for one guest.

3. Create a qcow2 volume

Create the initial 5 GiB volume:

virsh vol-create-as \
  tutorial-data \
  demo-data01.qcow2 \
  5GiB \
  --format qcow2

Inspect both the logical capacity and current allocation:

virsh vol-info \
  --pool tutorial-data \
  demo-data01.qcow2

virsh vol-path \
  --pool tutorial-data \
  demo-data01.qcow2

A new sparse qcow2 volume can have 5 GiB of guest-visible capacity while consuming only a few hundred KiB on the host.

4. Attach the disk live and persistently

Save the volume path and attach it as the next virtio disk:

DATA_DISK=$(virsh vol-path \
  --pool tutorial-data \
  demo-data01.qcow2)

virsh attach-disk \
  "$VM" \
  "$DATA_DISK" \
  vdb \
  --targetbus virtio \
  --subdriver qcow2 \
  --live \
  --config

Verify the result rather than assuming the target name:

virsh domblklist "$VM" --details
virsh domblkinfo "$VM" vdb
virsh dumpxml "$VM" --inactive > "${VM}-with-data-disk.xml"

--live changes the running guest. --config updates its persistent definition so the disk returns after reboot.

5. Identify and format the new device inside Ubuntu

Connect to the guest and inventory block devices:

lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS
sudo blkid /dev/vdb || true

Stop if vdb already contains a filesystem or data you did not create. Formatting the wrong target is irreversible.

For this empty tutorial volume, create ext4 directly on the whole device:

sudo mkfs.ext4 -L demo-data /dev/vdb
sudo mkdir -p /srv/demo-data
sudo mount /dev/vdb /srv/demo-data

echo "InventiveHQ KVM storage lab" | \
  sudo tee /srv/demo-data/README.txt

df -hT /srv/demo-data
sudo cat /srv/demo-data/README.txt

The validated 5 GiB device produced an approximately 4.9 GiB ext4 filesystem after filesystem metadata and reserved space.

For a durable production mount, use the filesystem UUID in /etc/fstab, test it with mount -a, and retain console access before rebooting. Device names such as vdb can change when hardware definitions change.

6. Expand an attached active disk

An intuitive first attempt is:

virsh vol-resize \
  --pool tutorial-data \
  demo-data01.qcow2 \
  8GiB

In the running lab this failed safely because QEMU held the qcow2 write lock:

qemu-img: Could not open 'demo-data01.qcow2':
Failed to get "write" lock

For the disk attached to the active domain, resize the domain block device:

virsh blockresize "$VM" vdb 8GiB
virsh domblkinfo "$VM" vdb
virsh vol-info \
  --pool tutorial-data \
  demo-data01.qcow2

Both commands then reported 8 GiB capacity.

7. Grow the ext4 filesystem online

Inside the guest, confirm that the kernel sees the larger block device:

lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS /dev/vdb

Because this tutorial put ext4 directly on /dev/vdb, grow it online:

sudo resize2fs /dev/vdb
df -hT /srv/demo-data
sudo cat /srv/demo-data/README.txt

The mounted filesystem grew from approximately 4.9 GiB to 7.8 GiB, and the validation file remained intact.

If your disk contains a partition table, grow the correct partition before the filesystem. LVM, XFS, encrypted volumes, and other layouts require their own tools and ordering.

Verification checklist

# On the KVM host
virsh pool-info tutorial-data
virsh vol-info --pool tutorial-data demo-data01.qcow2
virsh domblklist demo-ubuntu01 --details
virsh domblkinfo demo-ubuntu01 vdb

# Inside the guest
lsblk -f /dev/vdb
findmnt /srv/demo-data
df -hT /srv/demo-data
sudo cat /srv/demo-data/README.txt

The episode is complete only when the pool is persistent and autostarting, the disk exists in both live and inactive domain definitions, the filesystem is 8 GiB-class, and its data remains readable.

Safe detach procedure

Do not detach a mounted filesystem. If the disk must be removed later:

# Inside the guest
sudo sync
sudo umount /srv/demo-data

# On the host
virsh detach-disk demo-ubuntu01 vdb --live --config
virsh domblklist demo-ubuntu01 --details

Detaching a device does not necessarily delete its storage volume. Confirm backups and dependencies before virsh vol-delete.

Official references

Continue to Episode 5: Create a custom KVM NAT network with static DHCP.

Frequently Asked Questions

What is a libvirt storage pool?

A storage pool is a libvirt-managed source of storage such as a directory, filesystem, logical-volume group, block device, or network service. Volumes are the individual disk images or devices created or discovered inside that pool.

How do I attach a qcow2 disk to a running KVM VM?

Create or identify the volume, then run virsh attach-disk with the domain, volume path, guest target such as vdb, target bus, format, and both --live and --config. Verify the live and persistent definitions before formatting anything inside the guest.

Why did virsh vol-resize fail with a write-lock error?

QEMU holds the write lock while a qcow2 volume is attached to a running guest. In the validated lab, vol-resize was rejected for that reason. Use virsh blockresize for the active domain device, then grow the partition or filesystem inside the guest. Use vol-resize for an inactive or unattached volume workflow.

Does expanding a qcow2 image automatically grow the filesystem?

No. The virtual block device becomes larger, but the guest partition and filesystem remain their old size until expanded separately. This lab formats the entire vdb device with ext4, so resize2fs can grow it online without a partition step.

Can I shrink a KVM qcow2 disk with these commands?

Do not treat shrinking as the reverse of expansion. Filesystems, partitions, and image formats have different shrink constraints, and getting the order wrong destroys data. This guide covers expansion only.

Need help from an IT & cybersecurity partner?

InventiveHQ helps businesses secure, modernize, and run their technology. Let's talk about your goals.

Get in touch