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.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.