Grow a Linux disk after extending a VMDK

Extending the virtual disk is the easy part. This walks the whole chain in the guest: rescan, growpart, pvresize, lvextend and the filesystem step, which is xfs_growfs on RHEL and resize2fs on Ubuntu.

Extending a virtual disk in vSphere takes about fifteen seconds. The part that surprises people is what happens next: the guest reports exactly the same free space it had before, and it keeps reporting it until four more layers are told about the change.

Between the VMDK and the directory that ran out of space sit a SCSI device, a partition, an LVM physical volume, a logical volume and a filesystem. Each has its own idea of how big it is, and each is grown by a different command. Miss one and the extra space stays invisible.

This walks the whole chain on one machine, from the vSphere dialog to df showing the new number, and names what differs between the RHEL family and Debian or Ubuntu, because the final step is not the same command on both.

Applies to: vSphere 7 and 8, with Rocky Linux 9 and Ubuntu Server 22.04 as the guests. The same sequence applies to RHEL, AlmaLinux, Oracle Linux and Debian.


The chain, end to end

Six steps, one per layer. This table is the whole article in short form: if you already know the sequence and only need the commands, work down it.

StepLayerCommand
1The VMDK in vSphereEdit Settings, increase the disk size
2The SCSI device in the guestecho 1 > /sys/class/block/sda/device/rescan
3The partitiongrowpart /dev/sda 2
4The LVM physical volumepvresize /dev/sda2
5The logical volumelvextend -l +100%FREE /dev/mapper/rl-root
6The filesystemxfs_growfs / or resize2fs /dev/mapper/...
Note: Every step runs online. On any current kernel none of this needs a reboot or a maintenance window, and the filesystem stays mounted throughout.

The machine and its starting state

One VM is used throughout: SRV-LNX-01, Rocky Linux 9, a single 60 GB disk with the standard installer layout. Record the starting state before touching anything. When a later step appears to do nothing, this is what you compare against.

# Devices, partitions, sizes and mount points
lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0   60G  0 disk
|-sda1        8:1    0    1G  0 part /boot
`-sda2        8:2    0   59G  0 part
  |-rl-root 253:0    0   55G  0 lvm  /
  `-rl-swap 253:1    0    4G  0 lvm  [SWAP]
# Filesystem type and free space. The T matters - it tells you xfs or ext4,
# which decides the command in step 6.
df -hT /
Filesystem          Type  Size  Used Avail Use% Mounted on
/dev/mapper/rl-root xfs    55G   52G  3.0G  95% /
# Is there any unused space already inside the volume group?
sudo vgs
sudo lvs
VG #PV #LV #SN Attr   VSize   VFree
rl   1   2   0 wz--n- <59.00g      0

LV   VG Attr       LSize
root rl -wi-ao---- <55.00g
swap rl -wi-ao----   4.00g

VFree 0 is the line that matters. Nothing is spare inside the volume group, so the space has to come from outside, which is what the next five steps arrange.

Warning: Note the filesystem type from df -hT now. Rocky, RHEL and AlmaLinux default to xfs, Ubuntu and Debian default to ext4, and step 6 is a different command for each.

Step 1. Extend the VMDK

In the vSphere client, right-click the VM, choose Edit Settings, expand Hard disk 1 and raise the size. 60 becomes 80. Apply, and the task finishes in seconds.

[Screenshot placeholder – vSphere Edit Settings dialog with Hard disk 1 expanded and the size field changed from 60 to 80 GB]

Common mistake: If the size field is greyed out, the VM has a snapshot. A disk cannot be extended while snapshots exist. Delete or consolidate them first, and confirm the datastore has room for the growth before you start.

Nothing has changed inside the guest yet. That is expected, and it is where most people stop and wonder why.

df -hT /
Filesystem          Type  Size  Used Avail Use% Mounted on
/dev/mapper/rl-root xfs    55G   52G  3.0G  95% /

Step 2. Make the guest see the new size

The kernel read the disk geometry at boot and has no reason to look again. Tell it to.

# Rescan just this device. Replace sda with the disk you extended.
echo 1 | sudo tee /sys/class/block/sda/device/rescan

If the disk was added rather than extended, or you are not sure which device it is, rescan every SCSI host instead. Both are safe and both are online operations.

# The three dashes mean "any channel, any target, any LUN"
for h in /sys/class/scsi_host/host*/scan; do echo "- - -" | sudo tee "$h" > /dev/null; done

Confirm the kernel now sees 80 GB. The partition is still the old size, which is correct at this stage.

lsblk /dev/sda
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0   80G  0 disk
|-sda1        8:1    0    1G  0 part /boot
`-sda2        8:2    0   59G  0 part
Result: sda is 80G, sda2 is still 59G. The disk grew, the partition did not. That is exactly what step 3 fixes.
Note: With several disks attached, match the right one before rescanning. lsblk -o NAME,SIZE,MODEL and the disk sizes in Edit Settings are usually enough; lsscsi gives the SCSI address if two disks are the same size.

Step 3. Grow the partition

growpart rewrites the partition table so the last partition uses the new free space. It handles GPT and MBR, and it works on a mounted partition.

# Note the space: the disk and the partition NUMBER are two arguments,
# not /dev/sda2. This is the single most common error with this command.
sudo growpart /dev/sda 2
CHANGED: partition=2 start=2099200 old: size=123731968 end=125831167 new: size=165675007 end=167774207

Check it before going further. If the command is missing, install it: the package is cloud-utils-growpart on the RHEL family and cloud-guest-utils on Debian and Ubuntu.

lsblk /dev/sda
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0   80G  0 disk
|-sda1        8:1    0    1G  0 part /boot
`-sda2        8:2    0   79G  0 part
Warning: NOCHANGE: partition 2 is size ... it cannot be grown means the free space is not directly after that partition. That happens when the partition you are growing is not the last one on the disk, and swap or another partition sits behind it. In that case the free space has to be added as a new partition and a second PV, not by growing this one.

Use the dry run first if you want to see the plan without writing anything.

sudo growpart -N /dev/sda 2

Steps 4 and 5. Grow the LVM layers

LVM stores the physical volume size in its own metadata, so it also has to be told. pvresize reads the partition again and updates it.

sudo pvresize /dev/sda2
Physical volume "/dev/sda2" changed
1 physical volume(s) resized or updated / 0 physical volume(s) not resized

The volume group now has free extents. This is the moment the space becomes usable.

sudo vgs
VG #PV #LV #SN Attr   VSize   VFree
rl   1   2   0 wz--n- <79.00g  20.00g

Now give that free space to the logical volume that needs it. +100%FREE takes everything available; use -L +10G instead when you want to keep some in reserve.

sudo lvextend -l +100%FREE /dev/mapper/rl-root
Size of logical volume rl/root changed from <55.00 GiB to <75.00 GiB.
Logical volume rl/root successfully resized.
Note: lvextend -r grows the filesystem in the same command, for both xfs and ext4: sudo lvextend -r -l +100%FREE /dev/mapper/rl-root. That merges steps 5 and 6 and is what to use once you trust the sequence. The two are kept separate here so you can see which layer does what.
Warning: A volume group or logical volume whose name contains a hyphen appears in /dev/mapper with the hyphen doubled. Ubuntu’s default is /dev/mapper/ubuntu--vg-ubuntu--lv, which is one volume group and one volume, not four names. Copy the path from lsblk rather than typing it.

Step 6. Grow the filesystem, and this is where distributions differ

The logical volume is bigger, the filesystem inside it is not. This last command is the one that differs, and running the wrong one produces an error that reads like a broken system when it is only the wrong tool.

DistributionDefault filesystemCommandArgument
Rocky, RHEL, AlmaLinux, Oraclexfsxfs_growfsthe mount point
Ubuntu, Debianext4resize2fsthe device
SLES, openSUSEbtrfs or xfsbtrfs filesystem resize or xfs_growfsmount point

On the Rocky machine in this walk-through, the filesystem is xfs and the argument is where it is mounted.

# xfs_growfs takes the MOUNT POINT, not the device.
# Passing /dev/mapper/rl-root here fails with "not a mounted XFS filesystem".
sudo xfs_growfs /
data blocks changed from 14417920 to 19660800

On Ubuntu with the default ext4 layout, the same step is the other way round.

# resize2fs takes the DEVICE, not the mount point.
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
Filesystem at /dev/mapper/ubuntu--vg-ubuntu--lv is mounted on /; on-line resizing required
The filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv is now 19660800 (4k) blocks long.
Common mistake: Swapping the two arguments. xfs_growfs /dev/mapper/rl-root and resize2fs / both fail, and neither error says “you used the wrong argument type”. Check df -hT first, then pick the command and the argument from the table above.

Step 6b. Verify

Three commands confirm the whole chain took, from the device up to the filesystem.

lsblk /dev/sda
sudo vgs
df -hT /
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0   80G  0 disk
`-sda2        8:2    0   79G  0 part
  `-rl-root 253:0    0   75G  0 lvm  /

VG #PV #LV #SN Attr   VSize   VFree
rl   1   2   0 wz--n- <79.00g      0

Filesystem          Type  Size  Used Avail Use% Mounted on
/dev/mapper/rl-root xfs    75G   52G   23G  70% /
Result: 95% full became 70% full, with the filesystem mounted the whole time and no reboot. If df still shows the old size, the filesystem step did not run: the earlier layers report their new sizes in lsblk and vgs, so whichever number is still old tells you which step to repeat.

[Screenshot placeholder – terminal showing lsblk and df -hT side by side, before on the left and after on the right]


When there is no LVM

Cloud images and minimal installs often put the filesystem straight on a partition, with no volume group in between. The chain is then four steps instead of six: extend the VMDK, rescan, grow the partition, grow the filesystem.

# Confirm there is no lvm layer - lsblk shows part directly under disk
lsblk /dev/sda

# Rescan and grow the partition exactly as before
echo 1 | sudo tee /sys/class/block/sda/device/rescan
sudo growpart /dev/sda 1

# Then the filesystem, directly on the partition
sudo xfs_growfs /            # RHEL family
sudo resize2fs /dev/sda1     # Debian and Ubuntu
Note: Without LVM there is no pvresize and no lvextend, and there is also no way to add space from a second disk later. That is the practical argument for LVM on a server that may grow again.

What goes wrong

SymptomCauseFix
Disk size field greyed out in vSphereThe VM has snapshotsDelete or consolidate, then extend
lsblk still shows the old disk sizeThe kernel has not rescannedStep 2, then check again
growpart: command not foundPackage not installedRHEL: cloud-utils-growpart. Ubuntu: cloud-guest-utils
NOCHANGE: partition ... cannot be grownFree space is not right after the partitionNot the last partition. Add a new one as a second PV.
lvextend says insufficient free spacepvresize was skippedRun step 4, check vgs
xfs_growfs: not a mounted XFS filesystemA device was passed instead of a mount pointxfs_growfs /
resize2fs: Nothing to do!Wrong device, or already at sizeCopy the path from lsblk
Everything reports the new size except dfStep 6 did not runRun the command for your filesystem
Datastore fills up during the extendThin provisioning caught up with youCheck datastore space before extending

Tips and limitations

  • Growing is online and safe. Shrinking is neither: xfs cannot be shrunk at all, and shrinking ext4 requires unmounting. Plan sizes upward only.
  • Take a backup or a snapshot before the first time you do this on a production VM, and remove the snapshot afterwards so the next extend is not blocked by it.
  • Extending the VMDK consumes datastore space immediately on a thick disk and gradually on a thin one. Check the datastore, not just the guest.
  • lvextend -r does steps 5 and 6 in one command and picks the right filesystem tool for you. Use it once you have done the sequence manually and understand what it is doing.
  • On a machine with several disks, confirm which /dev/sdX matches the VMDK you extended before rescanning. Growing the wrong partition table is not something LVM will warn you about.
  • An MBR disk cannot go past 2 TB. If the disk needs to grow beyond that, it has to be converted to GPT or the space added as a second disk.
  • /boot is usually a plain partition outside LVM, and it is rarely the one that fills up. If it does, the fix is removing old kernels, not resizing.

Official documentation


Related tools

  • PowerCLI Command Builder – build the PowerCLI call when you would rather extend the disk from a script than from the UI.

Related guides