Linux - LVM

Logical Volume Manager

Overview

Physical Volume

A physical volume is a block device that has to be marked as such to take part in Logical Volume Management. This is the first step in setting up a volume group which we use to create logical volumes which can be used as 'regular' disks.

The physical volume does not have to be a full disk, it can be a partition of a disk. In fact it can be any blockdevice.

# pvcreate <BLOCK_DEVICE>

# pvs

  PV         VG Fmt  Attr PSize  PFree

  /dev/sda3  cl lvm2 a--  18.41g    0 

# pvdisplay

  --- Physical volume ---

  PV Name               /dev/sda3

  VG Name               cl

  PV Size               18.41 GiB / not usable 2.00 MiB

  Allocatable           yes (but full)

  PE Size               4.00 MiB

  Total PE              4713

  Free PE               0

  Allocated PE          4713

  PV UUID               zaP4cW-tjgV-Wggs-RHmg-RZlh-PifQ-J1ULI4

Discovering physical volumes

In order to discover block devices on your system you could use

# cat /proc/partitions

# fdisk -l

# lsblk      # tree view

# lsblk -l   # list view

# fdisk -l

Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 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: gpt

Disk identifier: 1729418E-F806-434E-94DD-F9FE8948E3B4


Device       Start      End  Sectors  Size Type

/dev/sda1     2048  1230847  1228800  600M EFI System

/dev/sda2  1230848  3327999  2097152    1G Linux filesystem

/dev/sda3  3328000 41940991 38612992 18.4G Linux LVM



Disk /dev/mapper/cl-root: 16.4 GiB, 17620271104 bytes, 34414592 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



Disk /dev/mapper/cl-swap: 2 GiB, 2147483648 bytes, 4194304 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


# cat /proc/partitions 

major minor  #blocks  name


  11        0    1048575 sr0

   8        0   20971520 sda

   8        1     614400 sda1

   8        2    1048576 sda2

   8        3   19306496 sda3

 253        0   17207296 dm-0

 253        1    2097152 dm-1

# lsblk

NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT

sda           8:0    0   20G  0 disk 

├─sda1        8:1    0  600M  0 part /boot/efi

├─sda2        8:2    0    1G  0 part /boot

└─sda3        8:3    0 18.4G  0 part 

  ├─cl-root 253:0    0 16.4G  0 lvm  /

  └─cl-swap 253:1    0    2G  0 lvm  [SWAP]

sr0          11:0    1 1024M  0 rom  

# lsblk -l

NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT

sda       8:0    0   20G  0 disk 

sda1      8:1    0  600M  0 part /boot/efi

sda2      8:2    0    1G  0 part /boot

sda3      8:3    0 18.4G  0 part 

sr0      11:0    1 1024M  0 rom  

cl-root 253:0    0 16.4G  0 lvm  /

cl-swap 253:1    0    2G  0 lvm  [SWAP]


Volume Group (VG)

Now that we have physical volumes available we can create volume groups. We can think of a volume group as a pool of available storage space that we can use to create logical volumes (virtual disks). 

# lsblk

# pvcreate /dev/sda /dev/sdb /dev/sdc

# vgcreate bigdisk /dev/sda /dev/sdb /dev/sdc

# vgs

# vgdisplay

Let's mark the block devices as physical volumes.

# pvcreate /dev/loop0 /dev/loop1 /dev/loop2

  Physical volume "/dev/loop0" successfully created.

  Physical volume "/dev/loop1" successfully created.

  Physical volume "/dev/loop2" successfully created.

# pvs

  PV         VG   Fmt  Attr PSize  PFree 

  /dev/loop0 pool lvm2 a--  96.00m 96.00m

  /dev/loop1 pool lvm2 a--  96.00m 96.00m

  /dev/loop2 pool lvm2 a--  96.00m 96.00m

# pvdisplay

 --- Physical volume ---

  PV Name               /dev/loop0

  VG Name               pool

  PV Size               100.00 MiB / not usable 4.00 MiB

  Allocatable           yes 

  PE Size               4.00 MiB

  Total PE              24

  Free PE               24

  Allocated PE          0

  PV UUID               t6JwEn-1YhG-MHBo-Atco-TNfF-bhPz-Sp4umx

   

  --- Physical volume ---

  PV Name               /dev/loop1

  VG Name               pool

  PV Size               100.00 MiB / not usable 4.00 MiB

  Allocatable           yes 

  PE Size               4.00 MiB

  Total PE              24

  Free PE               24

  Allocated PE          0

  PV UUID               xXKauA-Ka73-mIt1-eQCP-vLym-BcqN-mufQBS

   

  --- Physical volume ---

  PV Name               /dev/loop2

  VG Name               pool

  PV Size               100.00 MiB / not usable 4.00 MiB

  Allocatable           yes 

  PE Size               4.00 MiB

  Total PE              24

  Free PE               24

  Allocated PE          0

  PV UUID               fZcFEl-Jlrf-NEQS-JEwv-LE1e-4OaK-zx6Uis


Now that we have physical volumes we can create volume groups. Let's create a volume group named pool consisting of all three block devices we created previously.

# vgcreate pool /dev/loop0 /dev/loop1 /dev/loop2

  Volume group "pool" successfully created

Logical Volume (LV)

Snapshots

Creating a snapshot

When creating a snapshot we actually create a new volume which gets marked as a snapshot volume and it has to reference an existing volume. You have to make sure there is enough space in your volume group to create the snapshot volume (just like a 'regular' logical volume).

# lvs

# lvcreate -s -n <NAME_OF_SNAPSHOT_VOLUME> -L <MAX_SIZE_OF_SNAPSHOT_VOLUME> <LVM_DEVICE_TO_TAKE_SNAPSHOT_OF>


# lvcreate -s -n centos8_snapshot -L 1G /dev/vms/centos8

  Using default stripesize 64.00 KiB.

  Logical volume "centos8_snapshot" created.

# lvs

 LV                VG   Attr        LSize   Pool Origin    Data%  Meta%  Move Log Cpy%Sync Convert

 centos8           vms  owi-aos---  20.00g  

 centos8_snapshot  vms  swi-a-s---   1.00g       centos8   0.00

Resizing Logical Volumes

Extending Logical Volumes

# lvextend -L+30M -r /dev/pool/data

  Rounding size to boundary between physical extents: 32.00 MiB.

Phase 1 - find and verify superblock...

Phase 2 - using internal log

        - zero log...

        - scan filesystem freespace and inode maps...

        - found root inode chunk

Phase 3 - for each AG...

        - scan (but don't clear) agi unlinked lists...

        - process known inodes and perform inode discovery...

        - agno = 0

        - agno = 1

        - agno = 2

        - agno = 3

        - process newly discovered inodes...

Phase 4 - check for duplicate blocks...

        - setting up duplicate extent list...

        - check for inodes claiming duplicate blocks...

        - agno = 0

        - agno = 1

        - agno = 2

        - agno = 3

No modify flag set, skipping phase 5

Phase 6 - check inode connectivity...

        - traversing filesystem ...

        - traversal finished ...

        - moving disconnected inodes to lost+found ...

Phase 7 - verify link counts...

No modify flag set, skipping filesystem flush and exiting.

  Size of logical volume pool/data changed from 152.00 MiB (38 extents) to 184.00 MiB (46 extents).

  Logical volume pool/data successfully resized.

meta-data=/dev/mapper/pool-data  isize=512    agcount=4, agsize=9728 blks

         =                       sectsz=512   attr=2, projid32bit=1

         =                       crc=1        finobt=1, sparse=1, rmapbt=0

         =                       reflink=1

data     =                       bsize=4096   blocks=38912, imaxpct=25

         =                       sunit=0      swidth=0 blks

naming   =version 2              bsize=4096   ascii-ci=0, ftype=1

log      =internal log           bsize=4096   blocks=1368, version=2

         =                       sectsz=512   sunit=0 blks, lazy-count=1

realtime =none                   extsz=4096   blocks=0, rtextents=0

data blocks changed from 38912 to 47104