Skip to main content
RunBook Academy

LinuxLXXVI · Virtualisation and LinuxGuest operations

Growing a guest online - disk, filesystem, memory and CPU

Intermediate⏱ ~18 minlsblkgrowpartlsmemchcpu

What you'll learn

  • Make a guest see a virtual disk that has been enlarged on the hypervisor
  • Execute the full grow chain from device to filesystem, and identify where it stops
  • Bring hot-added memory and CPUs into service, and explain when they will not be used
  • State what cannot be done online, and why shrinking is a different operation entirely

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11

Not yet marked complete on this device.

Growing a VM is presented as a hypervisor operation: change a number in the VM configuration and the guest is bigger. The hypervisor half is genuinely that easy. The guest half is a chain of four or five separate steps, each of which reports success independently, and the reason resize tickets get reopened is that the chain stops partway and nothing says so.

The principle behind all of it: the hypervisor changes the virtual hardware, and the guest keeps using the numbers it already has until something makes it look again.

Disk: the chain, end to end

  1. Enlarge the virtual disk on the hypervisor.
  2. Make the guest kernel see the new device size.
  3. Grow the partition, and make the kernel re-read the partition table.
  4. Grow the LVM physical volume and logical volume, if LVM is in use.
  5. Grow the filesystem.

Step 1 is where the change is made and steps 2 to 5 are where it is delivered. Each has its own failure.

Step 2: rescan the device

Whether you need to do anything depends on the bus:

# What am I working with?
lsblk -o NAME,TYPE,TRAN,SIZE,MOUNTPOINTS

# SCSI, SAS, and virtio-scsi: ask the device to rescan
echo 1 | sudo tee /sys/block/sda/device/rescan

# Confirm the kernel now agrees with the hypervisor
lsblk -o NAME,SIZE /dev/sda

A virtio-blk device (/dev/vdX) signals its own size change through a configuration-change interrupt, so the kernel usually picks it up with no action. A SCSI device - which includes virtio-scsi, VMware paravirtual SCSI, and anything emulated - does not, and needs the rescan write above.

If lsblk still shows the old size, nothing later in the chain can work, and the error you get from growpart will be about there being no free space rather than about the rescan.

Step 3: grow the partition

sudo growpart --dry-run /dev/sda 2
sudo growpart /dev/sda 2
sudo partx -u /dev/sda
lsblk -o NAME,SIZE /dev/sda

Note the space: growpart /dev/sda 2, disk and partition number as separate arguments. --dry-run reports what it would do without doing it, and it is worth running first because a partition number typo is how you resize the wrong partition.

growpart attempts the kernel partition-table update itself via partx --update, and partx -u afterwards is a cheap confirmation. Older advice says partprobe; on a disk with a mounted partition partprobe can return EBUSY while partx -u succeeds, so prefer partx.

Steps 4 and 5: LVM and the filesystem

# LVM: grow the PV to fill the enlarged partition, then the LV
sudo pvresize /dev/sda2
sudo vgs; sudo pvs
sudo lvextend -r -l +100%FREE /dev/mapper/vg0-root

# No LVM: grow the filesystem directly
sudo resize2fs /dev/sda2          # ext4, online grow supported
sudo xfs_growfs /                 # XFS takes the MOUNT POINT, not the device

Three details that account for most of the confusion here:

  • lvextend -r (--resizefs) grows the filesystem in the same command. Without -r, the LV is bigger and df is unchanged, which is the single most common “the resize did not work” report.
  • xfs_growfs takes a mount point. Passing it a device path fails with an error that reads like the device is wrong. resize2fs takes a device. They are opposites and it catches everyone once.
  • Both grow online, on a mounted filesystem, including the root filesystem. That is normal and supported.

Memory hotplug

Two different mechanisms are often confused:

Ballooning changes how much of the guest’s already configured memory it may use. Covered in the overview lesson; the total never exceeds what the VM was given.

Hotplug adds new memory blocks to the guest, up to the maximum memory the VM was configured to allow. The blocks arrive as entries under /sys/devices/system/memory/, and whether they are usable depends on one file:

Read-only / Safeauto_online_blocks decides whether hot-added memory is usable
$ lsmem --summary; cat /sys/devices/system/memory/auto_online_blocks
Memory block size:                128M
Total online memory:               48G
Total offline memory:               0B
online

Illustrative output

If auto_online_blocks reads offline, hot-added blocks appear in lsmem as offline and contribute nothing. free and /proc/meminfo do not count them, and the guest keeps running under memory pressure with the memory sitting there unused - a resize that appears to have been applied on the hypervisor and had no effect at all.

lsmem                        # STATE column: online or offline
sudo chmem -e 4G             # bring 4G of offline memory online
lsmem --summary

The durable fix is the kernel parameter memhp_default_state=online on the kernel command line, or the distribution’s udev rule that onlines new blocks. Set it in the image rather than fixing it per host.

Removal is not symmetrical

Memory can only be taken away if the blocks are movable and nothing unmovable is allocated in them. lsmem shows this in its REMOVABLE column, and the honest summary is that growing a guest is routine and shrinking it is unreliable and should be planned as a reboot.

CPU hotplug

lscpu -e                     # per-CPU list, with an ONLINE column
sudo chcpu -e 8-11           # bring vCPUs 8 to 11 online
sudo chcpu -d 11             # take vCPU 11 offline

Newly added vCPUs may come up offline depending on the distribution’s udev rules, which is what chcpu -e is for. chcpu -r triggers a rescan for newly added CPUs where the platform needs it. CPU 0 generally cannot be offlined - there is no online file for it on most builds, which is why chcpu -d 0 fails in a way that looks like a permission problem.

What you cannot do online

Validation after any resize

lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS
df -h; df -i
sudo pvs; sudo vgs; sudo lvs
lsmem --summary
lscpu -e | tail -5
findmnt --verify

findmnt --verify checks /etc/fstab against reality, which catches the other way a resize goes wrong: a device path that changed during the work and an fstab entry that still names the old one, discovered at the next reboot rather than now.

Knowledge check

Knowledge check · 4 questions

  1. Q1. A virtual disk was enlarged on the hypervisor, but `lsblk` in the guest still shows the old size. The disk is a virtio-scsi device. What is missing?

  2. Q2. Growing an ext4 or XFS root filesystem requires unmounting it, so it needs a maintenance window.

  3. Q3. Which of these commonly cause a resize where every command reported success and `df` did not change? Select all that apply.

  4. Q4. Four vCPUs were hot-added and brought online with chcpu -e. nproc reports the new count and application throughput is unchanged. Why?

Passing score: 75%. Answers are checked in this browser.