I remember back when I was introduced to Arch Linux this thing called LVM but I never really used it and knew what were its capabilities.
I simply couldn’t understand why someone would want to resize a partition on the fly (guess what, I’ve done that so many times in AWS nowadays). Why would someone want to snapshot? Why LVM?
Now many years after my first Arch Linux installation I understand what are its benefits but I’ve never really set up on a Linux machine myself though. Here in this article, I go through the process of how one can play around with LVM without needing to have an extra disk or format anything.
ps.: If you’re looking for high-level concepts of LVM, this is not really the place you’re looking for. This is just hands-on on how to get it running with a loopback device (
ps.: in all of the code below the “hashtags” before the command (
#) indicates that we’re executing it with a privileged user.
ps.: this is an area I’m not expert at all! Please be kind of pointing to me the places I got stuff wrong and I’ll update right away!
First, let’s verify that we have some loopback devices
# ls /dev | grep loop loop0 loop1 loop2 loop3 loop4 loop5 loop6 loop7 loop-control
Now create a file to hold the data that will be written to the first loopback device. This is important because we’re wanting to simulate a real disk so we have to reserve some space for it.
# dd if=/dev/zero of=./lvm0.img bs=50 count=1M 1048576+0 records in 1048576+0 records out 52428800 bytes (52 MB, 50 MiB) copied, 1.06171 s, 49.4 MB/s
The next step is linking the loopback devices with the file we just created.
This is important because the file itself is just another regular file in the OS. LVM can’t get set up on a regular file though - it demands a special block device (like those you have under
# losetup /dev/loop0 ./lvm0.img
Verify that the loopback device has been recognized as an actual disk
# fdisk -l Disk /dev/loop0: 50 MiB, 52428800 bytes, 102400 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/sda: 10 GiB, 10737418240 bytes, 20971520 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: 0x14f750bf # lsblk lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 50M 0 loop <<<<<<< (not mounted yet) sda 8:0 0 10G 0 disk └─sda1 8:1 0 10G 0 part / sdb 8:16 0 10M 0 disk
Check all the partitions that we have in our disks - we should see
0 partitions in
/dev/loop0. For doing so we can use
GNU parted (
parted command in ubuntu zesty).
# man parted NAME GNU Parted - a partition manipulation program SYNOPSIS parted [options] [device [command [options...]...]] ... -l, --list lists partition layout on all block devices ...
Now, let’s execute it:
# parted -l Model: VBOX HARDDISK (scsi) Disk /dev/sda: 10.7GB <<<< NOT THE LOOPBACK Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 1049kB 10.7GB 10.7GB primary ext4 boot
So now what we need to do is format the device and set it to use LVM.
For doing so we can make use of
fdisk. As we don’t want to go
through the process using the interactive section we can make use of
man sfdisk you can see that it’s a “script-oriented tool for partitioning any block device”. Here we only have to submit the same inputs we’d use with
fdisk but in the
stdin of the executable:
# echo ",,8e,," | sfdisk /dev/loop0 Checking that no-one is using this disk right now ... OK Disk /dev/loop0: 50 MiB, 52428800 bytes, 102400 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 >>> Created a new DOS disklabel with disk identifier 0x9f5773d1. /dev/loop0p1: Created a new partition 1 of type 'Linux LVM' and of size 49 MiB. /dev/loop0p2: Done. New situation: Device Boot Start End Sectors Size Id Type /dev/loop0p1 2048 102399 100352 49M 8e Linux LVM The partition table has been altered. Calling ioctl() to re-read partition table. Re-reading the partition table failed.: Invalid argument The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8). Syncing disks.
,,8e,, means? It’s the same as “create a partition starting at the default start, with the default size, being LVM and using the default value for the bootable property”.
We can understand that better by looking at
# man sfdisk.8 ... Unnamed-fields format start size type bootable LIKE WHAT WE DID >>>>> , , 8e , , where each line fills one partition descriptor.
You can check that
8e is the type of LVM by using
fdisk manually, typing
m to look for help, and then
l to list known partition types:
#fdisk press m press l Command (m for help): l ... 7 HPFS/NTFS/exFAT 4d QNX4.x 88 Linux plaintext de Dell Utility ++++++++++++++ 8 AIX 4e QNX4.x 2nd part 8e Linux LVM| df BootIt /\++++++++++++ || the 8e we used! ...
Cool, we have our
/dev/loop0 device partitioned with LVM. Using the same commands we used before we can make sure that the statement is true:
# fdisk -l fdisk -l Disk /dev/loop0: 50 MiB, 52428800 bytes, 102400 sectors ... Device Boot Start End Sectors Size Id Type /dev/loop0p1 2048 102399 100352 49M 8e Linux LVM
But if you go back to the output of the
sfdisk command you can see there was an error:
The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).
We can confirm that indeed there’s something wrong if we make use of a command that relies on the mentioned table.
We can be faced with such problem by using our first LVM command:
# lvmdiskscan /dev/loop0 [ 50.00 MiB] /dev/sda1 [ 10.00 GiB] /dev/sdb [ 10.00 MiB] 1 disk 2 partitions 0 LVM physical volume whole disks 0 LVM physical volumes
What? We just created an LVM partition on a disk (on the loopback device) and it says that there’s no LVM devices? That’s the mentioned problem in place.
To fix it we can make use of
partx to force an update in the kernel table:
# partx --update /dev/loop0
and then see the new output:
# lvmdiskscan /dev/loop0p1 [ 49.00 MiB] /dev/loop0 [ 50.00 MiB] /dev/sda1 [ 10.00 GiB] /dev/sdb [ 10.00 MiB] 1 disk 3 partitions 0 LVM physical volume whole disks 0 LVM physical volumes
But we still don’t have a physical volume that LVM can use.
# lvmdiskscan -l WARNING: only considering LVM devices 0 LVM physical volume whole disks 0 LVM physical volumes
To create that we now make use of
PVCREATE(8) System Manager's Manual PVCREATE(8) NAME pvcreate — initialize a disk or partition for use by LVM ... Examples Initialize partition #4 on the third SCSI disk and the entire fifth SCSI disk for later use by LVM: pvcreate /dev/sdc4 /dev/sde
So that’s cool, we can just follow the example provided and do ourselves:
# lvmdiskscan -l WARNING: only considering LVM devices 0 LVM physical volume whole disks 0 LVM physical volumes # pvcreate /dev/loop0 WARNING: dos signature detected on /dev/loop0 at offset 510. Wipe it? [y/n]: y Wiping dos signature on /dev/loop0. Physical volume "/dev/loop0" successfully created. # lvmdiskscan -l WARNING: only considering LVM devices /dev/loop0 [ 50.00 MiB] LVM physical volume 0 LVM physical volume whole disks 1 LVM physical volume
So now we have our first physical volume. Next step is creating a volume group:
VGCREATE(8) System Manager's Manual VGCREATE(8) NAME vgcreate — create a volume group SYNOPSIS vgcreate [opts...] VolumeGroupName PhysicalDevicePath DESCRIPTION vgcreate creates a new volume group called VolumeGroupName using the block spe‐ cial device PhysicalDevicePath. # vgcreate myvg /dev/loop0 Volume group "myvg" successfully created
vgdisplay we can then check that everything went fine:
# vgdisplay --- Volume group --- VG Name myvg System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 1 VG Access read/write VG Status resizable ... VG Size 48.00 MiB ...
Now that we have a volume group we can create a logical volume using a desired amount of size from the volume group:
# lvcreate --size 10M --name lv1 myvg Rounding up size to full physical extent 12.00 MiB Logical volume "lv1" created.
Having the logical volume created we can inspect the before and after of
--- initial 2017-11-11 18:54:11.000000000 -0200 +++ after 2017-11-11 18:54:23.000000000 -0200 @@ -3,11 +3,11 @@ System ID Format lvm2 Metadata Areas 1 - Metadata Sequence No 1 + Metadata Sequence No 2 VG Access read/write VG Status resizable MAX LV 0 - Cur LV 0 + Cur LV 1 Open LV 0 Max PV 0 Cur PV 1 @@ -15,6 +15,6 @@ VG Size 48.00 MiB PE Size 4.00 MiB Total PE 12 - Alloc PE / Size 0 / 0 - Free PE / Size 12 / 48.00 MiB + Alloc PE / Size 3 / 12.00 MiB + Free PE / Size 9 / 36.00 MiB VG UUID TmGsRi-3SZg-kU9Q-FTOI-72rG-XaYB-xkxXYB
Clearly, we can see that we took some space from the pool of all available space of the volume group (as it was allocated to the logical volume).
To finish, just see that our logical volume is not listed under
# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 50M 0 loop ├─myvg-lv1 253:0 0 12M 0 lvm └─loop0p1 259:0 0 49M 0 loop sda 8:0 0 10G 0 disk └─sda1 8:1 0 10G 0 part / sdb 8:16 0 10M 0 disk
Having that we’re set to use the partition for anything we want - mounting XFS, EXT4 .. any filesystem you want there and have all the benefits that LVM gives us (which is not the focus of this article).
Compared to just set up up a block device with a different filesystem, setting up LVM takes a big number of steps. Besides this, it’s pretty cool to see that because the interface (a special block device) is so simple we can totally skip the need for a real device and work in the same manner. Once meet the needs of the interface we’re done. That’s pretty cool IMHO.
What I plan to do next is script that process and set up multiple loopback devices so that I can experiment with the concept of having multiple volumegroups together with docker volumes.
Let’s see if that works out well 🙌.
If you’re struggling with a concept related to this or do something related to your work, your side project .. make sure you subscribe to the newsletter - you’ll be interested in other content similar to this.
Have a good one!
I used two resources (beside
man pages) that really helped me along the way. I want to thank these two for the great resources they provided:
- Anothony’s blog: LVM Loopbackv HOW-TO - this is what I used the most to write the article. It goes through almost the same as I do here but I think I explained more some pieces that he just passed by.
- Digital Ocean: How to use LVM To Manage storage devices on Ubuntu 16.04: another pretty great article that covers the process of using LVM on Ubuntu but not really focused on loopback devices.