TL;DR

With the disk already enlarged on the hypervisor side (qm resize 100 scsi0 +50G on Proxmox, Edit disk on VMware, your cloud console):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 1. Make the kernel see the new size (virtio-scsi/SATA; virtio-blk detects it alone)
echo 1 > /sys/class/block/sda/device/rescan
lsblk /dev/sda

# 2. Enlarge the partition (package cloud-guest-utils on Debian/Ubuntu, cloud-utils-growpart on RHEL)
growpart /dev/sda 3

# 3a. With LVM: PV, LV and filesystem
pvresize /dev/sda3
lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv      # -r: resize2fs or xfs_growfs depending on the fs

# 3b. Without LVM
resize2fs /dev/sda3        # ext4
xfs_growfs /               # xfs: takes the mount point

No reboot. df -h / confirms.

Before starting

  • Snapshot or backup on the hypervisor. Growing is safe; picking the wrong partition is not.
  • Look at the layout: lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS. It shows the partition number, whether LVM sits underneath, and which filesystem you are dealing with.
  • Names: virtio-blk is /dev/vda; virtio-scsi and SATA, /dev/sda; NVMe, /dev/nvme0n1 with partitions p1, p2… (growpart /dev/nvme0n1 1).
  • Sometimes the space is already there: Ubuntu Server creates the LV using only part of the VG. If vgs shows a large VFree, jump straight to lvextend.

1. Make the kernel see the new disk

BusWhat to do
virtio-blk (vda)Nothing: dmesg | tail shows [vda] new size: …
virtio-scsi, SATA, IDE (sda)echo 1 > /sys/class/block/sda/device/rescan
New disk (not grown)echo "- - -" > /sys/class/scsi_host/host0/scan
NVMe in the cloudUsually shows up on its own within a minute; if not, echo 1 > /sys/class/nvme/nvme0/rescan_controller

lsblk must show the new size on the disk before moving on; otherwise growpart will say NOCHANGE.

2. growpart

1
2
growpart /dev/sda 3
# CHANGED: partition=3 start=4198400 old: size=… end=… new: size=… end=…

growpart stretches the partition to the end of the disk, moves the GPT backup header, and tells the kernel about the new table even with the partition mounted (it uses partx --update). It only works on the last partition; if a swap partition sits behind the root, remove it first (swapoff, delete it with fdisk, recreate it at the end).

Without growpart: parted /dev/sda resizepart 3 100% does the same with a confirmation prompt.

3a. LVM

1
2
3
4
pvresize /dev/sda3                                  # the PV fills the now-larger partition
vgs                                                 # VFree > 0
lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv   # all the space
lvextend -r -L +20G /dev/ubuntu-vg/ubuntu-lv        # or only part of it

-r calls resize2fs or xfs_growfs depending on what lives in the LV. Without -r, do it yourself: resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv or xfs_growfs /.

3b. Without LVM

1
2
3
resize2fs /dev/sda3                 # ext4: online
xfs_growfs /                        # xfs: online, on the mount point
btrfs filesystem resize max /       # btrfs

Raspberry Pi and SD cards

Same script with other names (Fedora ARM image with LVM):

1
2
3
4
growpart /dev/mmcblk0 3
pvresize /dev/mmcblk0p3
lvextend -l +100%FREE /dev/fedora/root
xfs_growfs -d /

Traps

  • growpart: NOCHANGE: the kernel has not seen the new size yet. Back to step 1.
  • growpart fails in a non-English locale (it parses sfdisk output): LC_ALL=C growpart /dev/sda 3.
  • GPT PMBR size mismatch in fdisk -l after growing the disk: the GPT backup header stayed where the old disk ended. growpart moves it; if you did it by hand, sgdisk -e /dev/sda.
  • The partition is not the last one. Swap or /home behind the root: either move those, or add a new disk and join it to the VG (pvcreate /dev/sdb && vgextend ubuntu-vg /dev/sdb), which in LVM is faster than reordering partitions.
  • Shrinking is another story: ext4 only unmounted; XFS never. Think about it before handing out 2 TB “just in case”.
  • Windows grows from Disk Management → Extend Volume; none of this applies.

See also