A full data volume is one of the most common production emergencies. With the Logical Volume Manager (LVM) you can add disk space and grow a mounted filesystem without unmounting it or stopping the application. This post explains the layers, then gives a runbook you can rehearse before you need it.
Versions in use on this date. LVM2 2.02.176 on Ubuntu 18.04.3 LTS. ext4 can be grown online; XFS (the CentOS 7 default) can be grown online but never shrunk. ext4 can be shrunk only while unmounted, so plan sizes with growth in mind.
The three layers
flowchart TB
D1[Disk /dev/sdb] --> PV1[Physical volume PV]
D2[New disk /dev/sdc] --> PV2[Physical volume PV]
PV1 --> VG[Volume group vg_data<br/>pool of extents]
PV2 --> VG
VG --> LV1[Logical volume lv_db<br/>mounted at /var/lib/mysql]
VG --> LV2[Logical volume lv_logs<br/>mounted at /var/log]
VG --> FREE[Free extents<br/>available to grow any LV]
LV1 --> FS[Filesystem ext4 or xfs]
A physical volume is a disk or partition given to LVM. A volume group pools one or more PVs. A logical volume is a slice of the pool that holds a filesystem and can be extended later using free space. Growing needs two steps: extend the LV, then grow the filesystem inside it (-r does both).
Read the current state
lsblk -f
sudo pvs; sudo vgs; sudo lvs -a -o +devices
df -hT /var/lib/mysql
sudo vgdisplay vg_data | grep -E 'VG Size|Free'
If VFree in vgs is non-zero, you already have space and can skip straight to extending the LV.
Case 1: free space already in the volume group
sudo lvextend -r -L +20G /dev/vg_data/lv_db # add 20 GB and grow the filesystem
# or use all free space:
sudo lvextend -r -l +100%FREE /dev/vg_data/lv_db
df -hT /var/lib/mysql
Case 2: add a new disk
lsblk # confirm the new device, for example /dev/sdc
sudo pvcreate /dev/sdc
sudo vgextend vg_data /dev/sdc
sudo lvextend -r -l +100%FREE /dev/vg_data/lv_db
Double-check the device name with lsblk before pvcreate; it destroys any signature on the disk.
Case 3: the cloud disk was enlarged
On a virtual machine you often grow the disk in the provider console instead of adding one. The partition and the PV must be told:
sudo apt install cloud-guest-utils # provides growpart
sudo growpart /dev/sdb 1 # grow partition 1 to the new disk size
sudo pvresize /dev/sdb1
sudo lvextend -r -l +100%FREE /dev/vg_data/lv_db
If the filesystem sits directly on the disk without LVM, grow it with sudo resize2fs /dev/sdb (ext4) or sudo xfs_growfs /mountpoint (XFS).
Filesystem commands, when not using -r
sudo resize2fs /dev/vg_data/lv_db # ext4, online
sudo xfs_growfs /var/lib/mysql # XFS takes the mount point
Before and after checklist
- Take a backup or a provider snapshot first; resizing is safe but a typo is not.
- Note current sizes (
lvs,df -h) in the ticket. - Run the commands, then confirm the new size with
df -hand that the application still writes. - Update monitoring thresholds and capacity notes.
Snapshots and moving data
sudo lvcreate --size 5G --snapshot --name db_snap /dev/vg_data/lv_db
sudo lvremove /dev/vg_data/db_snap # remove when finished
sudo pvmove /dev/sdb1 # move extents off a disk before removing it
A snapshot uses copy-on-write space; if it fills up, the snapshot becomes invalid and writes to the origin volume get slow while it exists. Use snapshots for short backup windows, not as long-term history.
Common problems
- No free extents:
vgsshows 0 free; add a disk (Case 2). lvextendworks butdfis unchanged: the filesystem was not grown; runresize2fsorxfs_growfs.- Disk grew but
pvsshows the old size: rungrowpartandpvresize, and rescan withecho 1 | sudo tee /sys/class/block/sdb/device/rescan. - Root volume full: grow it the same way;
/on LVM extends online, which is why many installers use LVM by default.