Hey,
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 (/dev/loop*
).
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!
Getting real
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 /dev
).
# 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 sfdisk
.
From 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.
What does ,,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
:
# 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
# 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
:
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
With 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 vgdisplay
:
--- 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
:
# 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).
Closing thoughts
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!
Resources
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.
finis