LVM – Logical Volume Manager

LVM is a logical volume manager for Linux that was first written back in 1998. The goal of LVM is to provide an abstraction layer between the filesystem (Ext2/3/4, XFS, ReiserFS, FAT, NTFS…) and the physical disk it lies on. This howto will give you a quick tour of the LVM architecture, as well as the most common use cases for it.

The LVM Architecture

LVM incorporates three types of objects:

  • PV: Physical Volume, an on-disk partition formatted for LVM
  • VG: Volume Group, a group of PVs in a RAID-0/JBOD fashion
  • LV: Logical Volume, a pseudo block device located in a VG, on which you create a filesystem.

The LVM Architecture

Physical Volumes, or PV, are created on top of regular disk partitions (like /dev/sdb2, for example). Then, those PVs are used to make one or more Volume Groups, or VG. A VG is basically a pool of physical volumes merged together, like in a RAID-0 (or “JBOD“) setup. You can add new PVs to a VG later, to make for additional space.

Once your physical volumes are aggregated into a volume group, you can create Logical Volumes, or LV, in the VG. The LV will reserve space in the VG. You can of course create multiple LV in a single VG. Once a LV has been created, it will expose a new virtual block device under /dev/mapper. This is the block device that will be used to create the filesystem (using mkfs), which is then mounted like a regular filesystem.

Initial setup

We will go through the steps required to mount a filesystem based on an LVM volume. This procedure has been performed on a Debian GNU/Linux 9 (stretch) system, but should work on any Linux 3.2+-based system.

0 – Install the LVM tools

If not already done, you need to install the LVM tools.

Debian users:

% sudo apt-get install lvm2

RHEL-based system users:

% sudo yum install lvm2-cluster

1 – Prepare a physical partition

In this case, we have a virtual machine running with two emulated physical disks: one where the system is installed (/dev/vda), and one that we will use for LVM : /dev/vdb.

root@test-lvm:~# fdisk /dev/vdb

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x38bc0c25.

Command (m for help): p
Disk /dev/vdb: 25 GiB, 26843545600 bytes, 52428800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa5e9965b

We initialize the empty disk with a new primary partition that will be used as a LVM Physical Volume (PV).

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): <strong>p</strong>
Partition number (1-4, default 1):
First sector (2048-52428799, default 2048): <RETURN>
Last sector, +sectors or +size{K,M,G,T,P} (2048-52428799, default 52428799): <RETURN>

Created a new partition 1 of type 'Linux' and of size 25 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

The kernel re-reads the partition table and populates the new block device /dev/vdb1, which is our new primary partition.

2 – Creating the LVM resources

We initialize it for use by LVM with the pvcreate command:

# pvcreate /dev/vdb1
  Physical volume "/dev/vdb1" successfully created.

We can check the attributes of the PV with the pvdisplay command:

# pvdisplay
  --- Physical volume ---
  PV Name               /dev/vdb1
  VG Name               vg-demo
  PV Size               25.00 GiB / not usable 3.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              6399
  Free PE               6399
  Allocated PE          0
  PV UUID               2POxXh-S7Gx-zd6v-RnK0-OFt9-RYb0-SIVBbF

Then, we initialize a new Volume Group (VG) with this PV:

# vgcreate vgdemo /dev/vdb1
  Volume group "vgdemo" successfully created

We can also check its attributes with the vgdisplay command:

# vgdisplay
  --- Volume group ---
  VG Name               vgdemo
  System ID
  Format                lvm2
  Metadata Areas        1
  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                1
  Act PV                1
  VG Size               25.00 GiB
  PE Size               4.00 MiB
  Total PE              6399
  Alloc PE / Size       0 / 0
  Free  PE / Size       6399 / 25.00 GiB
  VG UUID               2Sp2pp-17jB-eNCN-vjQu-YF40-kiUw-9i2Rd9

Two shorter commands (pvs and vgs) are also available to view the status of PVs and VGs:

# pvs
  PV         VG      Fmt  Attr PSize  PFree
  /dev/vdb1  vgdemo  lvm2 a--  25.00g 25.00g
# vgs
  VG      #PV #LV #SN Attr   VSize  VFree
  vgdemo    1   0   0 wz--n- 25.00g 25.00g

As we can see, all the space is still available in the VG, since no Logical Volume (LV) has been created yet. Let’s fix that and create a 10 GiB volume using the lvcreate command:

# lvcreate vgdemo -L10G -n lvtest1
  Logical volume "lvtest1" created.

Here we first specify the VG on which to create our LV, then its size using the -L option, and finally its name using -n. As previously, we can get quick informations about our volumes using the lvs command:

# lvs
  LV          VG      Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lvtest1     vgdemo  -wi-a----- 10.00g

A new block device has been created: /dev/dm-0. A symbolic link also exists in /dev/mapper for easier reference by the system administrator; the naming convention is <vgname>-<lvname>:

# ls -l /dev/mapper
total 0
crw------- 1 root root 10, 236 Aug 1 15:37 control
lrwxrwxrwx 1 root root 7 Aug 1 15:42 vgdemo-lvtest1 -> ../dm-0

As we can see, in the VG, there’s now only 15 GiB left, since we allocated 10 GiB to the new LV.

# vgs
  VG     #PV #LV #SN Attr   VSize  VFree
  vgdemo   1   1   0 wz--n- 25.00g 15.00g

All the steps required to create a logical volume are now done, it’s time to format with a filesystem using mkfs.

3 – Creating and mounting the filesystem

Here at Jaguar Network, we are big fans of XFS, a filesystem developed by SGI in 1993. Most Linux kernels, including the Debian’s one, come with XFS support, but you might need to install userland programs to format it:

# apt-get install xfsprogs

Next, we create the filesystem on the LV block device:

# mkfs.xfs /dev/mapper/vgdemo-lvtest1
meta-data=/dev/mapper/vgdemo-lvtest1 isize=512    agcount=4, agsize=655360 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0, rmapbt=0, reflink=0
data     =                       bsize=4096   blocks=2621440, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

We can now mount it into any directory:

# mount -t xfs /dev/mapper/vgdemo-lvtest1 /mnt/test1

Let’s check the available space:

# df -h /mnt/test1
Filesystem                  Size  Used Avail Use% Mounted on
/dev/mapper/vgdemo-lvtest1   10G   43M   10G   1% /mnt/test1

All is good! In the next tutorial, we’ll show you how to create additional logical volumes, how to extend volume groups with new physical volumes, and lots of interesting things with LVM.