Understanding the LVM allocation policy

A colleague of mine asked me how LVM allocates physical extends when resizing volumes. So I decided to do a bit of research.

man 8 lvm has a section called ALLOCATION that describes how LVM allocates space, no matter if creating or resizing logical volumes (LVs). Basically, LVM tries to allocate new physical extends consecutively to any existing physical extends (PEs) if possible. When multiple LVs exist, extending the first one with consecutive PEs will not be possible, as the following PEs are already occupied by the second LV. Therefore, LVM will allocate the PEs following the last LV to the first LV.

This can be reproduced using a small test scenario. Using dd and losetup, we create a small, 1GiB virtual test disk backed by a file. We create a physical volume (PV) and a volume group (VG) as well as two LVs using the corresponding LVM commands. The, we resize the first LV, and check the resulting layout of physical extends using pvdisplay. The result is shown below:

lukas@framework-rose:~$ sudo dd if=/dev/zero of=lvmtest bs=1M count=1024 status=progress
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.198158 s, 5.4 GB/s
lukas@framework-rose:~$ sudo modprobe loop max_loop=8
lukas@framework-rose:~$ sudo losetup /dev/loop0 lvmtest
lukas@framework-rose:~$ sudo pvcreate /dev/loop0
  Physical volume "/dev/loop0" successfully created.
lukas@framework-rose:~$ sudo vgcreate test /dev/loop0
  Volume group "test" successfully created
lukas@framework-rose:~$ sudo lvcreate -L 100M test
  Logical volume "lvol0" created.
lukas@framework-rose:~$ sudo lvcreate -L 100M test
  Logical volume "lvol1" created.
lukas@framework-rose:~$ sudo lvextend -L +100m test/lvol0
  Size of logical volume test/lvol0 changed from 100.00 MiB (25 extents) to 200.00 MiB (50 extents).
  Logical volume test/lvol0 successfully resized.
lukas@framework-rose:~$ sudo pvdisplay -m
  --- Physical volume ---
  PV Name               /dev/loop0
  VG Name               test
  PV Size               1.00 GiB / not usable 4.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              255
  Free PE               180
  Allocated PE          75
  PV UUID               zF00fV-5yOf-dmWr-FXjH-7LA0-Xzqh-p9AXMt
   
  --- Physical Segments ---
  Physical extent 0 to 24:
    Logical volume	/dev/test/lvol0
    Logical extents	0 to 24
  Physical extent 25 to 49:
    Logical volume	/dev/test/lvol1
    Logical extents	0 to 24
  Physical extent 50 to 74:
    Logical volume	/dev/test/lvol0
    Logical extents	25 to 49
  Physical extent 75 to 254:
    FREE
lukas@framework-rose:~$ sudo lvchange -an test/lvol0
lukas@framework-rose:~$ sudo lvchange -an test/lvol1
lukas@framework-rose:~$ sudo vgchange -an /dev/loop0 
lukas@framework-rose:~$ sudo losetup -d /dev/loop0 
lukas@framework-rose:~$ rm lvmtest*
rm: remove write-protected regular file 'lvmtest'? y
rm: remove write-protected regular file 'lvmtest32'? y

The Physical Segments section clearly shows how the PEs are allocated to the LVs: First lvol0, then lvol1, then the extension of lvol0.