LVM, from physical volume to a filesystem that grows
Domain 1 names LVM and this guide builds the whole stack: two devices into physical volumes, a volume group, a logical volume with a filesystem on it - then grows it while it is mounted, runs out of space on purpose, adds the second device, and spans the volume across both, with the data checksummed before and after.
System Management Guide 17 of 28 Intermediate
- OSUbuntu 26.04 LTS
- Kernel7.0.0-30-generic
- systemd259
- Mandatory access controlAppArmor on Ubuntu, SELinux enforcing on Alma
- TimeAbout 26 min
- Firewallufw / nftables 1.1.6 - firewalld / nftables 1.1.5
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| LPLUS-A01 | 192.168.0.73 | Ubuntu 26.04 LTS | Debian-family host - apt, ufw, netplan, AppArmor | 2 Core | 4 GB | 50 GB |
This guide includes
Use this when a filesystem is filling and downtime is not an option. This matters because growing a volume and growing the filesystem inside it are two separate operations - doing only the first leaves df reporting the old size and looks like the resize failed.
- building the three layers in order and reading what each costs
- putting a filesystem on a logical volume and mounting it
- growing the volume while it stays mounted, and finding the filesystem unchanged
- resizing the filesystem, with the data proved identical by checksum
- running out of extents, adding a second device, and spanning the volume across both
Before you start
- a-disk-a-filesystem-and-a-mount-that-survives
-
Two devices to build on
What the machine already has, before anything is added.
bash Example session for n in 1 2; do sudo truncate -s 512M /var/tmp/lvm$n.img; done; for n in 1 2; do sudo losetup -f --show /var/tmp/lvm$n.img; done | sudo tee /tmp/lvm.devs; lsblk $(head -1 /tmp/lvm.devs) $(tail -1 /tmp/lvm.devs) -o NAME,SIZE,TYPE/dev/loop0/dev/loop1NAME SIZE TYPEloop0 512M looploop1 512M loopsudo pvs; sudo vgs; sudo lvs; echo "--- exit $? : nothing yet, and the commands still answer" PV VG Fmt Attr PSize PFree /dev/sda3 ubuntu-vg lvm2 a-- <48.00g 0 VG #PV #LV #SN Attr VSize VFree ubuntu-vg 1 1 0 wz--n- <48.00g 0 LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert ubuntu-lv ubuntu-vg -wi-ao---- <48.00g--- exit 0 : nothing yet, and the commands still answerExpected result
/dev/loop0and/dev/loop1at 512M each - and the existingubuntu-vgon/dev/sda3, which the three reporting commands answer for even before anything new exists.Success conditionYou can read a machine's LVM layout before changing it.
-
Physical volume, then volume group
Two layers before anything is usable, and what each costs.
bash Example session sudo pvcreate $(head -1 /tmp/lvm.devs) && sudo pvs -o pv_name,pv_size,pv_free,vg_name Physical volume "/dev/loop0" successfully created. PV PSize PFree VG /dev/loop0 512.00m 512.00m /dev/sda3 <48.00g 0 ubuntu-vgsudo vgcreate lplusvg $(head -1 /tmp/lvm.devs) && sudo vgs -o vg_name,pv_count,vg_size,vg_free,vg_extent_size Volume group "lplusvg" successfully created VG #PV VSize VFree Ext lplusvg 1 508.00m 508.00m 4.00m ubuntu-vg 1 <48.00g 0 4.00mExpected result
Physical volume "/dev/loop0" successfully createdwith 512.00m free - then a volume group of 508.00m with an extent size of 4.00m.Success conditionYou can build the two layers under a logical volume and read their sizes.
-
A logical volume, a filesystem, a mount
The layer you can finally write to.
bash Example session sudo lvcreate -L 200M -n data lplusvg && sudo lvs -o lv_name,vg_name,lv_size,lv_path Logical volume "data" created. LV VG LSize Path data lplusvg 200.00m /dev/lplusvg/data ubuntu-lv ubuntu-vg <48.00g /dev/ubuntu-vg/ubuntu-lvsudo mkfs.ext4 -q /dev/lplusvg/data && sudo mkdir -p /mnt/lplus && sudo mount /dev/lplusvg/data /mnt/lplus && df -h /mnt/lplus | tail -1; sudo dd if=/dev/urandom of=/mnt/lplus/payload.bin bs=1M count=60 status=none && sudo md5sum /mnt/lplus/payload.bin | cut -c1-32/dev/mapper/lplusvg-data 172M 152K 158M 1% /mnt/lpluseb2af2b557e9bc6b4cddaab2058d7c2aExpected resultA 200.00m volume at
/dev/lplusvg/data, mounted as 172M with 158M available - and 60 MB of random data written, with an md5 beginningeb2af2b5.Success conditionYou have a filesystem on LVM with data on it you can verify later.
-
Growing it while it stays mounted
The volume grows. The filesystem does not.
bash Example session sudo lvextend -L +150M /dev/lplusvg/data && df -h /mnt/lplus | tail -1; echo "--- the volume grew and the filesystem did not" Rounding size to boundary between physical extents: 152.00 MiB. Size of logical volume lplusvg/data changed from 200.00 MiB (50 extents) to 352.00 MiB (88 extents). Logical volume lplusvg/data successfully resized./dev/mapper/lplusvg-data 172M 61M 98M 39% /mnt/lplus--- the volume grew and the filesystem did notsudo resize2fs /dev/lplusvg/data 2>&1 | tail -1; df -h /mnt/lplus | tail -1; sudo md5sum /mnt/lplus/payload.bin | cut -c1-32; echo "--- and the data is unchanged" /dev/mapper/lplusvg-data 318M 61M 240M 21% /mnt/lpluseb2af2b557e9bc6b4cddaab2058d7c2a--- and the data is unchangedExpected result
Rounding size to boundary between physical extents: 152.00 MiB, the volume going from 50 to 88 extents - anddfstill reporting 172M. Afterresize2fs, 318M, with the same md5.Success conditionYou can grow a mounted filesystem and prove the data survived.
-
Running out of room, and adding the second device
A refusal, then a bigger pool, then one command that does both jobs.
bash Example session sudo lvextend -L +400M /dev/lplusvg/data 2>&1 | tail -1; echo "--- exit $? : the group has no more extents" Insufficient free space: 100 extents needed, but only 39 available--- exit 0 : the group has no more extentssudo pvcreate $(tail -1 /tmp/lvm.devs) > /dev/null && sudo vgextend lplusvg $(tail -1 /tmp/lvm.devs) && sudo vgs -o vg_name,pv_count,vg_size,vg_free Volume group "lplusvg" successfully extended VG #PV VSize VFree lplusvg 2 1016.00m 664.00m ubuntu-vg 1 <48.00g 0sudo lvextend -r -L +400M /dev/lplusvg/data 2>&1 | tail -2; df -h /mnt/lplus | tail -1; echo "--- -r resized the filesystem in the same command" Extended file system ext4 on lplusvg/data. Logical volume lplusvg/data successfully resized./dev/mapper/lplusvg-data 699M 61M 610M 9% /mnt/lplus--- -r resized the filesystem in the same commandsudo lvs -o lv_name,lv_size,seg_count,devices --noheadings; echo "--- and the volume now spans both devices" data 752.00m 2 /dev/loop0(0) data 752.00m 2 /dev/loop1(0) ubuntu-lv <48.00g 1 /dev/sda3(0)--- and the volume now spans both devicesExpected result
Insufficient free space: 100 extents needed, but only 39 available- then a group of 2 PVs and 1016.00m,Extended file system ext4and 699M mounted, with the volume showing 2 segments across loop0 and loop1.Success conditionYou can extend a volume group and let a volume span more than one device.
-
Putting the machine back
The three layers removed in the order they were built, reversed.
bash Example session sudo umount /mnt/lplus && sudo lvremove -f lplusvg > /dev/null && sudo vgremove -f lplusvg > /dev/null && sudo pvremove -f $(head -1 /tmp/lvm.devs) $(tail -1 /tmp/lvm.devs) > /dev/null; sudo pvs; sudo vgs; echo "--- exit $? : no physical volumes, no groups" PV VG Fmt Attr PSize PFree /dev/sda3 ubuntu-vg lvm2 a-- <48.00g 0 VG #PV #LV #SN Attr VSize VFree ubuntu-vg 1 1 0 wz--n- <48.00g 0--- exit 0 : no physical volumes, no groupsfor d in $(cat /tmp/lvm.devs); do sudo losetup -d $d; done; sudo rm -f /var/tmp/lvm1.img /var/tmp/lvm2.img /tmp/lvm.devs; sudo rmdir /mnt/lplus; losetup -a | wc -l; echo "loop devices left"0loop devices leftExpected resultOnly
ubuntu-vgon/dev/sda3left inpvsandvgs, and 0 loop devices.Success conditionThe machine's own LVM layout is exactly as it was.
Troubleshooting
lvextendsucceeded anddfstill shows the old size.Why: The volume and the filesystem are separate. Growing the volume does not tell the filesystem there is more room.
Fix:
resize2fs /dev/vg/lvfor ext4 orxfs_growfs /mountpointfor xfs - or uselvextend -r, which does both in one command.lvextendfails with insufficient free space although the disk is not full.Why: The VOLUME GROUP has no free extents. The disk's spare space is not in the group until it is added.
Fix:
vgs -o vg_freeshows what the group has. Add capacity withpvcreateon a new device thenvgextend <vg> <device>. Use-l +100%FREEto take everything available without arithmetic.A volume is a different size from the one requested.
Why: Space is allocated in whole extents - 4 MiB by default - so a request is rounded up, and LVM prints that it has done so.
Fix:Read the rounding message, and size in extents with
-lwhen the exact figure matters.vgs -o vg_extent_sizeshows the unit.A logical volume disappears after a reboot or a disk change.
Why: A physical volume is missing, so the group cannot be activated - and a linear volume spanning two devices needs both.
Fix:
pvsandvgsshow what is visible;vgdisplaynames a missing PV. Reattach it andvgchange -ay <vg>. LVM is not redundancy: for that, put RAID underneath it.