The Complete Beginner's Guide to LVM in Linux

This is a complete beginner's guide to LVM (Logical Volume Manager) in Linux.

In this tutorial, you'll learn the concept of LVM, its components and why you should be using it.

I won't be limited to just the theoretical explanation. I'll also show hands-on examples for creating and managing LVMs in Linux.

In short, I'm going to give you all the necessary information that you'd need to start working with LVM in the real world.

What is LVM in Linux?

LVM stands for Logical Volume Manager. A mechanism that provides an alternative method of managing storage systems than the traditional partition-based one. In LVM, instead of creating partitions, you create logical volumes, and then you can just as easily mount those volumes in your filesystem as you'd a disk partition.

💡
One exception to the previous statement is that you can not use logical volumes for /boot. That is because GRUB (the most common bootloader for Linux) can't read from logical volumes. The well-known alternative to GRUB, systemd-boot on the other hand reads only vfat filesystems, so that's not going to work either.

Components of LVM

There are three main components to LVM:

  1. Physical Volumes
  2. Volume Groups
  3. Logical Volumes

Although the list consists of three components, only two of them are direct counterparts to the partitioning system. The following table logs that.

Disk Partitioning System LVM
Partitions Logical Volumes
Disks Volume Groups

Physical volumes do not have any direct counterpart, but I'll talk about that soon.

Why use LVM?

The main advantage of LVM is how easy it is to resize a logical volume or volume group. It abstracts away all the ugly parts (partitions, raw disks) and leaves us with a central storage pool to work with.

If you've ever experienced the horror of partition resizing, you'd wanna use LVM.

Lab preparation for hands-on

This article is not just theory. I'll be showing actual command examples along the way and the best way to learn something is to work with it, hands-on. For that, I recommend you use a virtual machine.

To help you with that I already have prepared a simple Vagrantfile that you can use to spin up a very light virtual machine with VirtualBox. This virtual machine has three additional disks that you and I can use for the command examples below.

Create a directory somewhere in your filesystem and save the following in a file there, named Vagrantfile.

Vagrant.configure "2" do |config|
    config.vm.box = "ubuntu/focal64"
    config.vm.hostname = "lvm"
    3.times {|i| config.vm.disk :disk, size: "5GB", name: "drive-#{i}"}
    config.vm.provider :virtualbox do |machine|
        machine.memory = 1024
        machine.cpus = 1
        machine.customize ["modifyvm", :id, "--cpuexecutioncap", "50"]
    end
end

# vi: set ft=ruby

Or if you'd like, you can use wget or curl to download the file from my gist.

wget https://gist.githubusercontent.com/debdutdeb/98ed1b6aef36885d07ce8247188dfd5e/raw/524259da5dfa2d8750883d01c8159829729e224d/Vagrantfile

Make sure you have Vagrant and VirtualBox installed.

Once the Vagrantfile is in place, set the environment variable VAGRANT_EXPERIMENTAL to disks.

export VAGRANT_EXPERIMENTAL=disks

Finally, start the virtual machine using the following command (make sure you're in the same directory as the Vagrantfile):

vagrant up

Once the machine is running, you can use vagrant ssh to SSH into it and run the example commands from this article.

Remember to run vagrant destroy from the same directory as the Vagrantfile after you're done.

Installing LVM

Before you can use any of the commands, you need to install the lvm2 package. This should be preinstalled in most of the modern distributions, especially the Ubuntu-based ones. But still, I had to mention this before moving forward. To install lvm2, consult your distribution's documentation.

Hands-on with LVM

For this hands-on walk-through, I've built a virtual machine with 40G root storage (unimportant) and three external disks of size 5G. The size of these disks are arbitrary.

vagrant@lvm:~$ lsblk -o name,size,fstype
NAME    SIZE FSTYPE
loop0  55.5M squashfs
loop1  32.3M squashfs
loop2  70.4M squashfs
sda      40G 
└─sda1   40G ext4
sdb      10M iso9660
sdc       5G 
sdd       5G 
sde       5G

As you can see the devices I'm going to use are sdc, sdd and sde.

Remember I told you there are three main components to LVM?

  1. Physical Volumes
  2. Volume Groups
  3. Logical Volumes

It is time to see them one by one.

1. Physical Volumes

The very first thing you need to know about LVM, is physical volumes. Physical volumes are the raw materials or building blocks that are used to achieve the abstraction that is logical volumes. In simpler words, physical volumes are the logical unit of an LVM system.

A physical volume can be anything, a raw disk, or a disk partition. Creating and initializing a physical volume are the same thing. Both mean you're just preparing the building blocks (i.e. partitions, disks) for further operations. This will become clearer in moment.

Utilities: All utilities that manage physical volumes start with the letters pv for Physical Volume. E.g. pvcreate, pvchange, pvs, pvdisplay etc.

🚧
Anything mentioned after this box is destructive, unless you're using a virtual environment or a server on the cloud where no important data is stored or can be reached by accident, I advise you to stop right now.

Creating physical volumes

You can create a physical volume using a raw non-partitioned disk or the partitions themselves.

As I previously mentioned I have three external drives attached to my virtual machine, let's start with /dev/sdc.

We use the pvcreate command to create a physical volume. Just pass the device name to it and nothing else.

sudo pvcreate /dev/sdc

You should see something like this:-

vagrant@lvm:~$ sudo pvcreate /dev/sdc
  Physical volume "/dev/sdc" successfully created.

Next I'll be partitioning /dev/sdd into equal parts. Use any tool, cfdisk, parted, fdisk etc, there are many tools to achieve this job.

vagrant@lvm:~$ lsblk -o name,size,fstype | grep sdd
sdd       5G 
├─sdd1  2.5G 
└─sdd2  2.5G

You can now quickly create two more physical volumes out of these two partitions in one single step, pass both of these devices to pvcreate at once.

sudo pvcreate /dev/sdd1 /dev/sdd2

Take a look:-

vagrant@lvm:~$ sudo pvcreate /dev/sdd1 /dev/sdd2
  Physical volume "/dev/sdd1" successfully created.
  Physical volume "/dev/sdd2" successfully created.

Listing the available physical volumes

There are three commands that you can use to get the list of the available physical volumes, pvscan, pvs and pvdisplay. You generally don't need to pass anything to these commands.

pvscan:-

vagrant@lvm:~$ sudo pvscan
  PV /dev/sdc                       lvm2 [5.00 GiB]
  PV /dev/sdd1                      lvm2 [2.50 GiB]
  PV /dev/sdd2                      lvm2 [<2.50 GiB]
  Total: 3 [<10.00 GiB] / in use: 0 [0   ] / in no VG: 3 [<10.00 GiB]

pvs:-

vagrant@lvm:~$ sudo pvs
  PV         VG Fmt  Attr PSize  PFree 
  /dev/sdc      lvm2 ---   5.00g  5.00g
  /dev/sdd1     lvm2 ---   2.50g  2.50g
  /dev/sdd2     lvm2 ---  <2.50g <2.50g

pvdisplay:-

vagrant@lvm:~$ sudo pvdisplay
  "/dev/sdc" is a new physical volume of "5.00 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdc
  VG Name               
  PV Size               5.00 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               SzSkdD-xKYa-4y7P-teyU-481p-uiQ8-qieMJJ
   
  "/dev/sdd1" is a new physical volume of "2.50 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdd1
  VG Name               
  PV Size               2.50 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               553Iy4-JJ21-LfIw-udtO-j9Cd-7gFS-iXXFVS
   
  "/dev/sdd2" is a new physical volume of "<2.50 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdd2
  VG Name               
  PV Size               <2.50 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               bf7ghn-QkPm-EUdp-GdyW-shMG-5sMn-VhNtYB

As you can see along with just listing the physical volumes these commands also give you a ton of other information about these volumes.

Removing a physical volume

You can remove a physical volume with the pvremove command. Just like pvcreate, just pass the devices (that are initialized as physical volumes) to pvremove command.

For demonstration, I'll remove /dev/sdd2 from the list.

sudo pvremove /dev/sdd2

The output should be identical to this:-

vagrant@lvm:~$ sudo pvremove /dev/sdd2
  Labels on physical volume "/dev/sdd2" successfully wiped.

Now list the physical volumes with sudo pvs

vagrant@lvm:~$ sudo pvs
  PV         VG Fmt  Attr PSize PFree
  /dev/sdc      lvm2 ---  5.00g 5.00g
  /dev/sdd1     lvm2 ---  2.50g 2.50g

/dev/sdd2 is no more here.

2. Volume Groups

Volume groups are collections of physical volumes. It is the next level of abstraction in LVM. Volume groups are the storage pool that combines the storage capacity of multiple raw storage devices.

Utilities: All volume group utility names start with vg, stands for Volume Group, e.g. vgcreate, vgs, vgrename etc.

Creating volume groups

Volume groups are created using the vgcreate command. The first argument to vgcreate is the name you want to give this volume group, and the rest are the list of the physical volumes that are going to back the storage pool.

sudo vgcreate lvm_tutorial /dev/sdc /dev/sdd1

Example:-

vagrant@lvm:~$ sudo vgcreate lvm_tutorial /dev/sdc /dev/sdd1
  Volume group "lvm_tutorial" successfully created

Listing the volume groups

Listing volume groups is similar to listing physical volumes, you can use different commands with varying levels of verbosity, vgdisplay, vgscan and vgs.

I personally prefer the vgs command, sudo vgs

vagrant@lvm:~$ sudo vgs
  VG           #PV #LV #SN Attr   VSize VFree
  lvm_tutorial   2   0   0 wz--n- 7.49g 7.49g

vgscan:-

vagrant@lvm:~$ sudo vgscan
  Found volume group "lvm_tutorial" using metadata type lvm2

vgdisplay:-

vagrant@lvm:~$ sudo vgdisplay 
  --- Volume group ---
  VG Name               lvm_tutorial
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               7.49 GiB
  PE Size               4.00 MiB
  Total PE              1918
  Alloc PE / Size       0 / 0   
  Free  PE / Size       1918 / 7.49 GiB
  VG UUID               LYVE9P-vY0G-OAW6-an8q-yfBx-rrB1-YU61m1

Listing the physical volumes attached to a volume group

You can list all the physical volumes that are connected to a specific volume group by using the following command:-

sudo pvdisplay -S vgname=<volume_group_name> -C -o pv_name

Example:-

vagrant@lvm:~$ sudo pvdisplay -S vgname=lvm_tutorial -C -o pv_name
  PV        
  /dev/sdc  
  /dev/sdd1

You can also get the count of physical volumes.

sudo vgdisplay -S vgname=<volume_group_name> -C -o pv_count

Example:-

vagrant@lvm:~$ sudo vgdisplay -S vgname=lvm_tutorial -C -o pv_count
  #PV
    3

Extending a volume group

Extending a volume group means adding additional physical volumes to a volume group. To do so the vgextend command is used. The syntax is simple:-

vgextend <volume_group> <physical_volume1> <physical_volume2> ....

Let's extend our lvm_tutorial volume by /dev/sdd2.

sudo vgextend lvm_tutorial /dev/sdd2

Focus on the output:-

vagrant@lvm:~$ sudo vgextend lvm_tutorial /dev/sdd2
  Physical volume "/dev/sdd2" successfully created.
  Volume group "lvm_tutorial" successfully extended

In the physical volume section we ended up with removing /dev/sdd2 as a physical volume, but a partition or raw disk must be initialized as a physical volume otherwise LVM won't be able to manage it as part of a volume group. So vgextend readies /dev/sdd2 before adding it to the volume group.

Now list the physical volumes attached to this volume group, just to be sure.

sudo pvdisplay -S vgname=lvm_tutorial -C -o pv_name

Output:-

vagrant@lvm:~$ sudo pvdisplay -S vgname=lvm_tutorial -C -o pv_name
  PV        
  /dev/sdc  
  /dev/sdd1 
  /dev/sdd2

/dev/sdd2 is now in the list as expected.

Reducing a volume group

Just like extending a volume group means adding another physical volume, reducing it means removing one or more physical volumes.

We use the vgreduce command to do this. The general syntax is as follows:-

vgreduce <vgname> <physical_volume1> <physical_volume2> ....

Let's remove the physical volumes /dev/sdc and /dev/sdd1.

sudo vgreduce lvm_tutorial /dev/sdc /dev/sdd1

Example:-

vagrant@lvm:~$ sudo vgreduce lvm_tutorial /dev/sdc /dev/sdd1
  Removed "/dev/sdc" from volume group "lvm_tutorial"
  Removed "/dev/sdd1" from volume group "lvm_tutorial"
🚧
If a volume group has any active logical volumes, you won't be able to reduce it like this.

List the physical volumes again.

sudo pvdisplay -S vgname=lvm_tutorial -C -o pv_name

Output:-

vagrant@lvm:~$ sudo pvdisplay -S vgname=lvm_tutorial -C -o pv_name
  PV        
  /dev/sdd2

Those two physical volumes are gone.

Now for the sake of the rest of this article, add those two physical volumes back.

sudo vgextend lvm_tutorial /dev/sdc /dev/sdd1

Removing a volume group

You can remove a logical volume with the vgremove command.

sudo vgremove lvm_tutorial

Don't run this command right now, otherwise you'd have to recreate the volume group. If you want to test it out, run it at the very end of this article.

3. Logical Volumes

This is what you're going to mostly work with. A logical volume is like a partition, but instead of sitting on top of a raw disk, it sits on top of a volume group. You can,

  • Format a logical volume with whichever filesystem you want.
  • Mount it anywhere in the filesystem you want.

In this section you'll be learning,

  • How to create logical volumes.
  • Common operations on a logical volume.
  • Resizing a logical volume.
  • Removing a logical volume.

Utilities: All volume group utility names start with lv, stands for Logical Volume. e.g. lvcreate, lvs, lvreduce etc.vgcreate, vgs, vgrename etc.

Creating logical volumes

Logical volumes are created using the lvcreate command. The commonly used syntax looks as follows,

sudo lvcreate -L <size> -n <lvname> <vgname>

Let me break it down for you:-

  • The -L option is for the size of the new logical volume, you can use any integer with "GB", "MB" or "KB" at the end. E.g. "1GB".
  • The -n option is for naming this logical volume.
  • Finally you need to pass it the name of the volume group this logical volume will be a part of. So while providing the logical volume with a size, make sure the volume group has the space available.

Run the following command on the virtual machine:-

sudo lvcreate -L 5GB -n lv1 lvm_tutorial

Example output:-

vagrant@lvm:~$ sudo lvcreate -L 5GB -n lv1 lvm_tutorial
  Logical volume "lv1" created.

Common operations on a logical volume

As I previously said, you can put a filesystem on a logical volume as well as mount it anywhere on the filesystem.

Once created you can find the logical volume in /dev/<vgname>/<lvname> path. For example in our case the volume is going to be in /dev/lvm_tutorial/lv1.

vagrant@lvm:~$ ls -l /dev/lvm_tutorial/lv1 
lrwxrwxrwx 1 root root 7 May 17 02:09 /dev/lvm_tutorial/lv1 -> ../dm-0

Now you can use it like any partition. Format it with ext4,

sudo mkfs.ext4 /dev/lvm_tutorial/lv1

Mount it at some place in your current directory structure like /mnt,

sudo mount -t ext4 /dev/lvm_tutorial/lv1 /mnt

Resizing a logical volume

You can extend a logical volume using lvextend command and reduce its size using lvreduce command. Or you can use the single command lvresize to accomplish both tasks.

First let's see if the volume group has any space left in it or not.

sudo vgs -S vgname=lvm_tutorial -o vg_free

Output:-

vagrant@lvm:~$ sudo vgs -S vgname=lvm_tutorial -o vg_free
  VFree 
  <4.99g

According to the output, I have some space left, so let's increase the volume size by 2GB.

Remember the logical volume is still mounted at /mnt.

vagrant@lvm:~$ mount | grep '/mnt'
/dev/mapper/lvm_tutorial-lv1 on /mnt type ext4 (rw,relatime)

Use the following command to resize the volume:-

sudo lvresize -L +2GB lvm_tutorial/lv1

The general syntax is something like this:-

lvresize -L [+|-][Size] <vgname>/<lvname>

The symbol + or - after -L depends on whether you're trying to increase the size of the volume or decrease it respectively.

After the volume size has increased, the filesystem must be resized as well. For ext4, the command to use is resize2fs.

sudo resize2fs /dev/lvm_tutorial/lv1

Output:-

vagrant@lvm:~$ sudo resize2fs /dev/lvm_tutorial/lv1
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/lvm_tutorial/lv1 is mounted on /mnt; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/lvm_tutorial/lv1 is now 1835008 (4k) blocks long.
💡
Not all filesystems support hot resizing, Ext4 and XFS are one of the supported ones. I recommend you stick to these.

Reducing a logical volume is a slightly more complicated task and I'm not going to talk about that here in this article. I'm reducing the size of this volume by 1GB.

How to Resize LVM Partition Inside an Extended Partition
Resizing a logical volume in Linux is not very difficult but it can be tricky if the root is under an extended partition.

Removing a logical volume

You remove a logical volume with the lvremove command. The command syntax is as follows:-

lvremove <vgname>/<lvname>

Run this command on the virtual machine:-

sudo lvremove lvm_tutorial/lv1

Output:-

vagrant@lvm:~$ sudo lvremove lvm_tutorial/lv1
Do you really want to remove and DISCARD active logical volume lvm_tutorial/lv1? [y/n]: y
  Logical volume "lv1" successfully removed

Conclusion

There are a multitude of other operations doable on logical volumes, physical volumes and volume groups, but it's not possible to write all that into a single article.

I've left you with one more disk /dev/sde in the virtual machine. Use it, practice some of the commands from this article, create a new volume group, extend an existing one, just practice.

I hope this article was helpful for you, if you'd like to see more on this in the future, let me know in the comment section down below.