1. Overview
When we need more storage space than originally planned for, it’s LVM to the rescue.
The Linux kernel’s Logical Volume Manager lets us abstract our disk partitioning. Instead of assigning our storage volumes to partitions written to a physical disk’s partition table, we flexibly apportion out space as needed. And we don’t draw upon one disk at a time, but instead, use a storage pool. That means we can grow or shrink our /usr or /var volumes if we run out of space.
In this tutorial, we’ll add a new physical disk to our storage pool (a.k.a., volume group) and use the added storage to grow our existing filesystem.
2. The Situation
Let’s say we’ve been working with Ubuntu Server 20.04 LTS. By default, our server’s storage has been partitioned into a traditional 1GB partition for /boot, and most of the rest assigned to an LVM volume group.
We can look at it with lsblk:
# lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT /dev/vda
NAME SIZE TYPE FSTYPE MOUNTPOINT
vda 25G disk
├─vda1 1M part
├─vda2 1G part ext4 /boot
└─vda3 24G part LVM2_member
└─ubuntu--vg-ubuntu--lv 20G lvm ext4 /
From this output, we see that /dev/vd3 has 24G, but only 20G has been assigned to the logical volume mounted at the root. This gives us wiggle room in an “out of space” emergency. Another reason to keep around unallocated space: LVM snapshots, handy for backing up from a consistent state.
Let’s see what our filesystem looks like with a traditional tool like df:
# df -hT -text4
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 20G 6.2G 13G 34% /
/dev/vda2 ext4 976M 107M 803M 12% /boot
The logical volume with the long name looks just like a block device or partition to Linux.
Now, what if it started to fill up?
3. Physical, Grouped, and Logical
In the bad old days of simple partitions, we’d have to copy everything to a larger one in order to add more storage space. We would probably have to take our server offline that whole time.
When we use LVM, we can switch our logical volumes between any physical drives. We can safely resize any logical volumes and then their filesystems.
Linux’s LVM system contains three levels: physical volumes, volume groups, and logical volumes. The lvm command lets us work with the system as a whole.
But each of these levels can be created, inspected, modified, etc. with a suite of commands:
- pv commands manipulate physical volumes
- vg commands manipulate volume groups
- lv commands manipulate logical volumes
3.1. Inspecting Our Logical Volumes
Let’s look at our storage with the LVM tools.
Using pvdisplay, we see the old-style hard drive partition, which has been marked as an LVM Physical Volume:
# pvdisplay
--- Physical volume ---
PV Name /dev/vda3
VG Name ubuntu-vg
PV Size <24.00 GiB / not usable 0
Allocatable yes
PE Size 4.00 MiB
Total PE 6143
Free PE 1023
Allocated PE 5120
PV UUID qYYC7J-VjMf-niyu-m9C3-KU1n-bys8-1cA0GO
We also note it’s a member of the ubuntu-vg Volume Group.
PE stands for Physical Extent. Extents are a way filesystems measure block devices: a starting block and a length in blocks.
Using vgdisplay, we’d see some similar information. We can verify that our Volume Group only includes our one Physical Volume (the drive partition /dev/vda3):
# vgdisplay | grep PV
Max PV 0
Cur PV 1
Act PV 1
We’d like to add another PV to our VG. Then we can let our Logical Volume know about it.
Right now, lvdisplay tells us its name, the VG it uses, and how much storage has been set aside:
# lvdisplay ubuntu-lv
--- Logical volume ---
LV Path /dev/ubuntu-vg/ubuntu-lv
LV Name ubuntu-lv
VG Name ubuntu-vg
LV UUID QsSEyX-tpie-TBuw-sI6w-g6jN-Tp60-da7xjP
LV Write Access read/write
LV Creation host, time ubuntu-server, 2021-08-22 01:13:58 +0000
LV Status available
# open 1
LV Size 20.00 GiB
Current LE 5120
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:0
3.2. Adding Storage
So say we’ve added another hard disk drive. We might want to use a RAID for faster and/or more reliable storage. But for now, let’s just add more. Growing our storage by tacking on another drive like this is called Linear Mode.
First, we tag our new hard drive for use with LVM. Since this is the physical level, we’ll use a pv command, pvcreate:
# pvcreate /dev/vdd
Physical volume "/dev/vdd" successfully created.
# pvdisplay
--- Physical volume ---
PV Name /dev/vda3
VG Name ubuntu-vg
PV Size <24.00 GiB / not usable 0
Allocatable yes
PE Size 4.00 MiB
Total PE 6143
Free PE 1023
Allocated PE 5120
PV UUID qYYC7J-VjMf-niyu-m9C3-KU1n-bys8-1cA0GO
"/dev/vdd" is a new physical volume of "25.00 GiB"
--- NEW Physical volume ---
PV Name /dev/vdd
VG Name
PV Size 25.00 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID LYx1BE-udTE-imd2-1Ujx-ibph-kZyE-x9nWln
We notice that pvdisplay thoughtfully tells us our PV is “NEW” and not yet attached to any Volume Groups.
We’ll next add our Physical Volume, /dev/vdd, to our Volume Group, ubuntu-vg.
We’ll use the LVM command vgextend:
# vgextend ubuntu-vg /dev/vdd
Volume group "ubuntu-vg" successfully extended
# vgdisplay ubuntu-vg
--- Volume group ---
VG Name ubuntu-vg
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 3
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 2
Act PV 2
VG Size 48.99 GiB
PE Size 4.00 MiB
Total PE 12542
Alloc PE / Size 5120 / 20.00 GiB
Free PE / Size 7422 / 28.99 GiB
VG UUID oLnK3Q-OHRI-sMbw-72IM-qj2J-rJCj-olnalT
Finally, we can resize our Logical Volume, ubuntu-lv. Right now, it has 20GiB. Let’s add 95% of the available free space, saving the rest.
We’ll do that with lvresize:
# lvresize --extents +95%FREE --resizefs ubuntu-vg/ubuntu-lv
Size of logical volume ubuntu-vg/ubuntu-lv changed from 20.00 GiB (5120 extents) to 47.54 GiB (12171 extents).
Logical volume ubuntu-vg/ubuntu-lv successfully resized.
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/mapper/ubuntu--vg-ubuntu--lv is mounted on /; on-line resizing required
old_desc_blocks = 3, new_desc_blocks = 6
The filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv is now 12463104 (4k) blocks long.
We use the extents option, or -l, to claim a percentage of the space. We could also have used –size, or its alias -L, to specify a hard number, like 20G or an amount to add on, like +10G:
# lvresize --size +10G --resizefs ubuntu-vg/ubuntu-lv
The –resizefs option automatically expands your ext or XFS filesystem to fit its new space. We could do this as a separate step with filesystem-specific resizing tools, but it’s convenient to do it all at once.
Let’s check our disk space out using non-LVM tools:
# df -hT -text4
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 47G 6.2G 39G 14% /
/dev/vda2 ext4 976M 107M 803M 12% /boot
And there’s our additional available space.
3.3. Further Considerations
Using linear mode, combining multiple disks like this, increases our risk of data loss due to hardware failure. A RAID can help.
There are two approaches. Both are viable. We can choose the one that seems most straightforward.
One is to create a Linux RAID device with mdraid. Then we can treat it like any Physical Volume, add it to a Volume Group, and so on.
Another is to use lvm’s built-in RAID commands.
Both these methods use the same RAID software under the hood. So it’s really a matter of how we prefer to organize our storage.
Archlinux includes excellent details on their wiki.
4. Conclusion
The Logical Volume Manager gives us much more storage flexibility compared to using bare hard drive partitions.
In this tutorial, we’ve expanded our root volume. We were able to do this because it was created using the LVM. That meant we could tag a new Physical Volume for use by LVM, add it to a Volume Group, and then deploy that storage wherever we wanted.
There are many other ways to use LVM. But knowing we can add space as needed can be a lifesaver.