How to: Linux LVM

Last update: Nov 2024

Preface / Motivation

Everybody who experienced a default installation of Ubuntu 24.04 or Ubuntu 23.10 and wanted the default encryption to be enabled, will inevitably come across the same problems. Ubuntu’s new installer does not allow you to use your predefined LUKS partitions anymore. LVM (Logical Volume Manager) is mandatory now. Therefore I’m writing this small blogpost as kind of a cheatsheet, because I’m sure some of you will encounter the same problems. One of my first problems was, that the Ubuntu installer takes up all your free space during LVM+LUKS creation. This is typically not what I’m asking for. And since Canocial decided to eliminate the Legacy Desktop Installer (which was able to use LUKS without LVM), there is no other way except playing around with LVM. So here we go.

Overview about LVM

First of all we need some knowledge about the relationsships. Using the following graphic of linuxconfig.org, we explain how the individual elements relate to each other.

LVM (Logical Volume Manager) consists always of three parts with the following hierarchy (from bottom to top):

  • Level 1: Physical Volume (PV): baseline element of LVM
  • Level 2: Volume Group (VG): kind of a virtual drive / can reside on multiple partitions, disks, name should be unique
  • Level 3: Logical Volume (LV): there are your “usable” volumes, where our filesystem resides

Example Installation

For showing you all details we use a default Ubuntu 24.04 installation with encryped LVM on a 50 GB drive. All of those 50 GB are used for LVM by default; as you can see in GParted:

Let’s assume we just booted the system up and want to see some facts about it. We use lsblk and df for this purpose.

lsblk

>>>
NAME                        MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
...
sda                           8:0    0    50G  0 disk  
├─sda1                        8:1    0     1G  0 part  /boot/efi
├─sda2                        8:2    0     2G  0 part  /boot
└─sda3                        8:3    0  46.9G  0 part  
  └─dm_crypt-0              252:0    0  46.9G  0 crypt 
    └─ubuntu--vg-ubuntu--lv 252:1    0  46.9G  0 lvm   /
df -Th

>>>
Filesystem                        Type      Size  Used Avail Use% Mounted on
...
/dev/mapper/ubuntu--vg-ubuntu--lv ext4       46G  9.5G   35G  22% /
...

In addition to this there are specific commands to show more information about PV, VG and LV:

PV-LevelVG-LevelLV-Level
pvscanvgscanlvscan
pvsvgslvs
pvdisplayvgdisplaylvdisplay

We will run all of them now to get more details about the system we are in.

# we want some info about the PV (physical volume):

# 1. sudo pvscan

  PV /dev/mapper/dm_crypt-0   VG ubuntu-vg       lvm2 [<46.93 GiB / 0    free]
  Total: 1 [<46.93 GiB] / in use: 1 [<46.93 GiB] / in no VG: 0 [0   ]

# 2. sudo pvs

  PV                     VG        Fmt  Attr PSize   PFree
  /dev/mapper/dm_crypt-0 ubuntu-vg lvm2 a--  <46.93g    0 

# 3. sudo pvdisplay

  --- Physical volume ---
  PV Name               /dev/mapper/dm_crypt-0
  VG Name               ubuntu-vg
  PV Size               46.93 GiB / not usable 3.00 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              12014
  Free PE               0
  Allocated PE          12014
  PV UUID               zofURa-qyMQ-1hza-DRax-8nvs-mhUR-zZhKgo

What do we learn about the PV? (Reminder: LVM base level 1 out of 3)

  • There is an encrypted partition /dev/sda3 (size 49,95 GiB) and this partition has been opened and accessible at /dev/mapper/dm_crypt-0 (size 46,93 GiB).
# now we want info about the VG (volume group):

# 1. sudo vgscan

Found volume group "ubuntu-vg" using metadata type lvm2

# 2. sudo vgs

  VG        #PV #LV #SN Attr   VSize   VFree
  ubuntu-vg   1   1   0 wz--n- <46.93g    0

# 3. sudo vgdisplay

  --- Volume group ---
  VG Name               ubuntu-vg
  System ID             
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  2
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               1
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <46.93 GiB
  PE Size               4.00 MiB
  Total PE              12014
  Alloc PE / Size       12014 / <46.93 GiB
  Free  PE / Size       0 / 0   
  VG UUID               55tDXa-6TTg-ccDx-UCCV-UaQX-mnSl-FyP1hi

What do we learn about the VG? (Reminder: LVM level 2 out of 3)

  • Inside the PV there is a VG named ubuntu-vg (size 49,93 GiB).
# now we want info about the LV (logical volumes)

# 1. sudo lvscan

ACTIVE            '/dev/ubuntu-vg/ubuntu-lv' [<46.93 GiB] inherit

# 2. sudo lvs

LV        VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
ubuntu-lv ubuntu-vg -wi-ao---- <46.93g

# 3. sudo lvdisplay

  --- Logical volume ---
  LV Path                /dev/ubuntu-vg/ubuntu-lv
  LV Name                ubuntu-lv
  VG Name                ubuntu-vg
  LV UUID                0RjrOz-HkVm-03XG-GKc7-6YUD-bejn-5kUB54
  LV Write Access        read/write
  LV Creation host, time ubuntu, 2024-11-26 22:11:39 +0100
  LV Status              available
  # open                 1
  LV Size                <46.93 GiB
  Current LE             12014
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:1

What do we learn about the LV? (Reminder: LVM level 3 out of 3)

  • There is a logical volume (“usable partition”) named ubuntu-lv (size 46,93 GiB).
  • We keep in mind that the filesystem of /dev/ubuntu-vg/ubuntu-lv is ext4.

As you can see the Ubuntu installer really used all disk space of our 50 GB disk. Argh! Let’s say I wanted to use just 30 GB of the disk. We need to change that somehow!

Example scenario: We shrink the whole stuff from 50 to 30 GiB.

For the purpose of showing how that works, we will try – as mentioned – to shrink the 50GiB filesystem to 30GiB. For this we need to boot up a live Linux like Ubuntu from a pendrive. Be conscious of what you type: 1G = 1.000.000.000 Bytes; while 1g = 1.073.741.824 Bytes.

As we found out in the part before we have the following LVM situation:

ext4filesystem type within LV where our data is stored
/dev/ubuntu-vg/ubuntu-lvlevel 3 logical volume (LV)
ubuntu-vglevel 2 volume group (VG)
/dev/mapper/dm_crypt-0level 1 physical volume (PV)

The steps we need to do now must be carried out in the correct order of the LVM: first on filesystem, then on level 3 (LV), then on level 2 (VG) and finally on level 1 (PV).

Step 0: Boot up a Linux from USB which are you familiar with.

Ensure that packages lvm2 and cryptsetup are installed.

Step 1: Opening the /dev/sda3 partition holding the LVM data

# opening the partition
sudo cryptsetup open /dev/sda3 cryptedpartition

# we will find it opened now
ls /dev/mapper

>>>
...  cryptedpartition  ubuntu--vg-ubuntu--lv

# lets check it again if it is really open
sudo fdisk -l /dev/mapper/ubuntu--vg-ubuntu--lv

>>>
Disk /dev/mapper/ubuntu--vg-ubuntu--lv: 46.93 GiB, ...

Step 2: Shrinking the ext4 filesystem within ubuntu-lv

# run the mandatory check first
sudo e2fsck -f /dev/mapper/ubuntu--vg-ubuntu--lv

>>>
e2fsck 1.47.1 (20-May-2024)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/ubuntu--vg-ubuntu--lv: 172200/3080192 files (0.2% non-contiguous), 2724943/12302336 blocks

# shrink it, -p stands for showing a progress bar
sudo resize2fs -p /dev/mapper/ubuntu--vg-ubuntu--lv 30g

>>>
resize2fs 1.47.1 (20-May-2024)
Resizing the filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv to 7864320 (4k) blocks.
Begin pass 2 (max = 1720747)
Relocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 3 (max = 376)
Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 4 (max = 16510)
Updating inode references     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv is now 7864320 (4k) blocks long.

# as you can see now the filesystem ext4 has a size of 30G (7864320 * 4096 Bytes = 32212254720 Bytes = 30 GiB) 

Step 3: Shrinking the LV: ubuntu-lv

# now we reduce the size of the LV to fixed 30GiB
sudo lvreduce -L 30g /dev/mapper/ubuntu--vg-ubuntu--lv

>>>
File system ext4 found on ubuntu-vg/ubuntu-lv.
File system size (30.00 GiB) is equal to the requested size (30.00 GiB).
File system reduce is not needed, skipping.
Size of logical volume ubuntu-vg/ubuntu-lv changed from <46.93 GiB (12014 extents) to 30.00 GiB (7680 extents).
Logical volume ubuntu-vg/ubuntu-lv successfully resized.

# if you look on gparted now, then you ll notice that /dev/sda3 is not filled 100% anymore but shows only 30GiB of usage.

Shortcut available for step 4! Typically we would have to shink the VG, shink the PV and to shrink the LUKS partition now. You can use a shortcut now: You can let the tool do the work for you. Just open it up with sudo and manually shrink the partition to the size you need, here: 30 GiB. If you click on apply, you are done with all three remaining steps at once.

In case you prefer “the hard way”, you can continue with those commands instead:

Step 4 “the hard way”: Shrinking the VG: ubuntu-vg, Shrinking the PV: /dev/mapper/dm_crypt-0, Shrinking the LUKS holding partition: /dev/sda3.

# find out how many free space we have within the VG
sudo pvs

>>>
PV                           VG        Fmt  Attr PSize   PFree  
/dev/mapper/cryptedpartition ubuntu-vg lvm2 a--  <46.93g <16.93g

# here we have 16.93g free space. we want to remove that.
# first we need some math for preparation
sudo fdisk -l /dev/sda

>>>
Device       Start       End  Sectors  Size Type
...
/dev/sda3  6397952 104855551 98457600 46.9G Linux filesystem

# now we know that the crypted partition starts at sector 6397952 and ends with 104855551. the size is 98457600 sectors. if you use a calculator it will show you that 98457600 blocks are equal to 46.9482421875 Gibibyte (GiB).

# usually we would have have to calculate 46.93g - 16.93g, but keep in mind that the LVM tells us <16.93g. that means there is some overhead and we have to consider that during calculation.
# so we count 49.93g - 16.90g = 33.03g

# we use this value for shrinking the filesystem
sudo lvm pvresize -v --yes --setphysicalvolumesize 33.05g '/dev/mapper/cryptedpartition'

>>>
WARNING: /dev/mapper/cryptedpartition: Pretending size is 69310873 not 98424832 sectors.
Resizing volume "/dev/mapper/cryptedpartition" to 69310873 sectors.
Resizing physical volume /dev/mapper/cryptedpartition from 12014 to 8460 extents.
Updating physical volume "/dev/mapper/cryptedpartition"
Archiving volume group "ubuntu-vg" metadata (seqno 3).
Physical volume "/dev/mapper/cryptedpartition" changed
Creating volume group backup "/etc/lvm/backup/ubuntu-vg" (seqno 4).
1 physical volume(s) resized or updated / 0 physical volume(s) not resized

# as we can see above the filesystem has been changed to 69310873 blocks. we need this value to shinkthe encryption volume now
sudo cryptsetup -v --size 69310873 resize 'cryptedpartition'

>>>
No usable token is available.
Enter passphrase for /dev/sda3: 
Key slot 0 unlocked.
Command successful.

Caution: Do not use the following unless you know what you are doing!

## DONT USE THIS - ITS JUST FOR MY REFERENCE ##
######## THIS IS WHAT GPARTED DID ############
# calibrating
# path: /dev/sda3 (partition)
# start: 6397952
# end: 104855551
# size: 98457600 (46.95 GiB)
# encryption path: /dev/mapper/cryptedpartition

# shrink filesystem
sudo lvm pvresize -v --yes --setphysicalvolumesize 31460352K '/dev/mapper/cryptedpartition'

# shrink encryption volume
sudo cryptsetup -v --size 62920704 resize 'cryptedpartition'

# shrink partition from 46.95 GiB to 30.02 GiB
# old start: 6397952
# old end: 104855551
# old size: 98457600 (46.95 GiB)
# new start: 6397952
# new end:  69351423
# new size: 62953472 (30.02 GiB)

Sources / further reading