Logical Volume Manager: A Beginner's Guide
Tags: linux, beginners
Published: 2023-08-07 10:14:24

Hey there, everyone!

I'm super excited to kick off my very first blog! Today, I want to take you on a journey into the awesome realm of Linux Volume Manager (LVM). Don't worry if you're new to this – I'll start from the very basics and walk you through the entire process of creating and managing your own LVM. And guess what? I promise to keep things fun and easy to understand. So, buckle up, and let's embark on this exciting adventure together! Ready? Let's go! 😊

## Prerequisites 

Before we get started, we would need a few tools at our disposal.
- 🖥️ A Linux machine with root access (VMs would suffice as well)
- 📀 A USB drive (preferably 8 GB and above)
- ☕ A cup of coffee (can't miss this one!)
- 🐧 Some understanding of Linux is always a plus!

## Physical Volumes

As the name suggests, we would be dealing with volumes, to be precise, storage. For us to understand LVM better, we would need a firm understanding of how Linux stores data without LVM in the first hand. Let's start by inspecting how a regular hard disk drive or solid state drive (**block devices**)

![Physical Volume](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fbps7effpgqfbe33svc.png)

The diagram above illustrates how a physical device or block device is partitioned and used by our Linux machines. At the top, there's a **partition table**, which is just **a reflection of how the device is internally partitioned**. The next three blocks represent the **partitions**, named in ascending order for easy understanding. Each partition has a **filesystem**, a special database that stores the file and folder hierarchy details**. Common examples of filesystems are ext4, NTFS, and FAT. Don't worry; we'll dive into filesystems and partitions in the hands-on section later!

Linux organizes its file system like a tree structure, with the `/` directory as the root. All files and folders reside next to it. In our setup, partition 1 is **mounted** to `/`, partition 2 to /tmp, and partition 3 to `/home`. When we store data in any directory, it goes into the corresponding partition.

However, using physical volumes directly comes with some problems:

- When the `/` directory runs out of space, extending it can be tricky.
- Incorporating a new storage device with your `/home` directory requires adjustments.
- Replacing a slow storage device is a cumbersome task.

That's where LVM comes to the rescue! It simplifies these processes and provides more flexibility. Let's explore LVM further in the upcoming sections.

## Okay, so, what actually is LVM?

LVM, which stands for **Logical Volume Manager**, becomes more understandable now that we have a basic understanding of storage devices and their utilization. LVM acts as an intermediate layer, allowing us to manage our storage seamlessly. It adds flexibility and simplicity to the storage management process, making it easier to handle partitions and filesystems. With LVM, we can efficiently allocate, resize, and move logical volumes, providing us with a more dynamic and adaptable storage solution

![LVM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m01j7w8dq18idhuycyce.png)

As the diagram shows, LVM utilizes a Volume Group (VG) to abstract the Physical Volumes (PVs), which represent the raw storage devices like HDDs and SSDs. The VG is typically created with one or more PVs, and from this pool of storage, Logical Volumes (LVs) are carved out. The beauty of LVM lies in its ability to freely adjust the size of these LVs, thanks to its dynamic data management on the physical volumes. In a sense, the VGs act as a versatile and flexible **data pool**.

You may have noticed the block labeled /boot. This partition holds the data related to our system's boot process. At boot time, Linux cannot read data from the LVs directly, so a separate raw /boot partition is necessary.

It's important to note that not all LVM-based systems offer the same level of flexibility. Some systems may restrict us to just one PV and two LVs (for swap and root), limiting the benefits of LVM's true potential. However, when we have the liberty to leverage LVM's full capabilities, it opens up a world of possibilities for efficient and customizable storage management.

## Operations supported in LVM
LVM supports the following operations:

- **Add** more physical volumes (PVs) to volume group (VG)
- **Remove** PVs as long as there is enough space to accomodate the existing logical volumes (LVs) into the VG.
- **Resize** LVs

## Enough chit-chat, let's get to the real stuff!

Now that we have the theory out of the way, let's get our hands dirty by actually creating a LVM on our systems. We would be doing the following stuff:

1. Partition our USB drive to have 2 partitions (2 GB + ~6 GB).
2. Create a VG from 1 partition and, later on, extending it with the other partition.
3. Displaying the details of the VGs.
4. Create 2 LVs (1 GB + 2 GB)
5. Display the LVs
6. Create file systems on the LVs and mount them to our systems
7. Extend the 1 GB LV by 2 GB and re-adjusting the file system.
8. Removing the VGs and LVs.
9. Fixing out pendrives.

**Just to make a note of it, some commands that I will be using might not be already present on your distro. In that case, please be sure to read the error messages and install the required binaries.**

So turn on your Linux machine, get a sip of your coffee and get started!

### Partitioning our USB drive

Just so we don't actually blow up our computers trying to do anything fancy, we would do this experiment using a USB drive. I am using an 8 GB HP stick for this. Just make sure to back up any data that is present in the USB drive and then we are good to go.

The first step is to partition the USB drive.

Make sure you are in a root shell. If not, use 
```bash
sudo -i
```

Next, let's grab some details about our block devices. 
```bash
lsblk
```

![lsblk](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d86u854ta14gdyje4rce.png)

I have truncated the irrelevant details from the output. You can notice that there are 2 devices called `sda` and `sdb`. And under the `TYPE` column, you can also see that these are...disk. But wait, where did these names come from? Let's find out how.

Block devices use **SCSI (Small Computer System Interface)** to talk to processes on one side and hardware on the other side. Hence, block devices have device names (since everything on Linux is a file, so device files) starting with sd*, where s = SCSI and d = device. During boot time, the kernel detects block devices one by one and name them in the form `sd[a-z]`. So in my case, my vmware disk got detected first and hence, it was named `sda`. Next, after boot, I attached my USB stick and the kernel named it `sdb`. As I mentioned earlier, all disks have one or more partitions. In the above output, `sdb1`, `sda1`, etc. are names of partitions.
Note that USB devices use SCSI as a layer of abstraction over its USB interface. That's the reason why it gets detected as block devices.

We can fetch more details about our block devices using this command:
```bash
fdisk -l /dev/sdb
```

![fdisk details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xa0xrgelrqjf9ielwye5.png)

Now, we would partition the device into 2 halves. For that, we first need to unmount our device:
```bash
umount /dev/sdb1
```

To verify that the device is unmounted, you can run the following command:
```bash
mount | grep sdb
```
The output of this command should be empty.

Next, we will use `fdisk` to manage the partitions. Here is what we will do:
1. Delete the existing partition
2. Create a new partition of 2 GB
3. Create another partition of the remaining size
4. Save the changes (fdisk doesn't save the changes on the go)

To start, type the following command and refer to the output for more:
```bash
fdisk /dev/sdb
```

![fdisk partition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an2tgkn56e9m54psuesz.png)

**Commands used:**
- **d:** Delete existing partition
- **n:** Create new partition
- **p:** List all partitions

Once done, you can verify the newly created partitions using:
```bash
lsblk /dev/sdb
```

![lsblk /dev/sdb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1yq2napx6isi45w9w1d.png)

### Creating a volume group

Now that we are done with partitioning our USB drive, it's time to create our brand-new VG.

Before running any of the commands below, make sure you have installed the `lvm2` package:
```bash
sudo apt install lvm2 -y
```

Next, we create our VG:
```bash
vgcreate myvg /dev/sdb1
```

![vgcreate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/60dpjkz1wrj751qqit8e.png)

### Listing VGs
We can list the existing VGs in our system using the command:
```bash
vgs
```
OR
```bash
vgdisplay
```

The first command lists all the VGs in a compact manner, while the second command gives us a detailed view.

![vgs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u8qr8iknueg1eoqmqbws.png)

- **VG:** Name of the volume group
- **#PV:** Number of physical volumes associated with the VG
- **#LV:** Number of logical volumes inside the VG
- **#SN:** Number of snapshots of the VG
- **VSize:** VG Size
- **VFree:** Amount of unallocated space on the VG

![list vgs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdk92ghs28opkg4e04xg.png)

If you have come this far, give yourself a pat on the back and have a sip from that cup of yours!

### Adding PVs to VG
We want to add our `/dev/sdb2` partition to `myvg` aswell.
```bash
vgextend myvg /dev/sdb2
```

![vgextend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7taja7wbm5qp57i9ckf.png)

Notice that if we list out our VG now, we would see that its size has changed:
```bash
vgs myvg
```

![vgs myvg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qedfhoecjg2s9kaja4b.png)

### Creating logical volumes out of `myvg`
Our VG has been created. Now, we want to create volumes out of it so that we can start using it.

We will create a 1 GB volume named `mylv1`:
```bash
lvcreate --size 1g --name mylv1 myvg
```

And similarly, we will create another LV of size 2g, named `mylv2`:
```bash
lvcreate --size 2g --name mylv2 myvg
```

![lvcreate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c1eql2hhwrokt27b1330.png)

If we try to see our VG config now, we will see that the `VFree` has reduced now:

```bash
vgs myvg
```

![vgs myvg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/guyv2nrgqnbz419arpfd.png)

### Listing LVs
We have 2 LVs created and we would like to see how they look like. The command is similar to that of listing VGs:
```bash
lvs
```

![lvs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/joap9sjtj444x1m87qnf.png)

### Using our LVs
Okay, so now we have 2 LVs created and now we want to use them. Lets see how we can do that.

Previously, we saw that the kernel detects devices during boot time and assigns them the names accordingly. This means that our LV "device" names will also vary with each boot. Initially, the kernel creates the logical volumes under `/dev` folder with a naming convention `dm-*`, where * is an integer. To make sure we can map our LVs by the name we know them to these `dm-*` device files, the kernel also creates symbolic links under the `/dev/mapper` and `/dev/<vgname>` directories.

**Contents of `/dev/mapper`:**

![ls /dev/mapper](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4di5zn5r2q8idhbjcp26.png)

**Contents of `/dev/myvg`:**

![ls /dev/myvg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l4x64ljz2nwiawqje8de.png)

Now that we know what device files to use, let's actually create a file system:

```bash
mkfs -t ext4 /dev/myvg/mylv1
```

![mkfs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkx6ost80489kkkl8pb4.png)

This command creates an `ext4` file system on our `mylv1` LV. Now its time to mount it to a location.

First, I'll create a mountpoint:
```bash
mkdir /mnt/mylv1
```
Then, I'll mount the LV:
```bash
mount /dev/myvg/mylv1 /mnt/mylv1
```
Next, I'll verify my mount point using:
```bash
mount | grep mylv1
```

![mkfs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wt1s2482bwlyddn5p6ev.png)

As we can see, everything is set up exactly how we wanted it to be. If I were you, I would have tried to do the following things:
- Do the same for `mylv2`
- Take a break
- Take another sip from my cup

### Using our newly created LV
First, we need to move to our mount point:
```bash
cd /mnt/mylv1
```
Next, we can inspect the size using:
```bash
df -h .
```
Lastly, we can start creating files. I'll leave this to you. But remember, this space is created by the root so no other user would have write access to it. If you want to give the users write access, then run `chmod a+rw .` while you are still in that directory.

### Resizing the LV
Remember our `mylv1` LV just has 1 GB of storage. We now would like to ramp it up to have 3 GB. Lets do that.

```bash
lvresize -L +2g myvg/mylv1
```

![lvresize](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipd49e2ij6f5w102wxo2.png)

This command adds 2 GB of storage to `mylv1`.

But now if we run `df -h /mnt/mylv1`, we notice that the size didn't change. Did we make a mistake? No.
Remember that file systems are the managers of every partition? When we created a partition on `mylv1`, it's size was 1 GB. Just increasing the volume size doesn't mean that the filesystem would also be synchronized. So, to do that, we need to run the following command:
```bash
fsadm -v resize /dev/myvg/mylv1
```

![resize](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pwgp6ntgv0zgzczbmp5h.png)

Try running `df -h /mnt/mylv1` and you will see that the size has increased.

`lvresize` provides us with a `-r` flag to automatically do the file system resizing for us. So, the command would be:
```bash
lvresize -r -L +2g myvg/mylv1
```

### Removing LVs and VGs
We have almost reached the end of this long blog now. Before we finish, we would like to perfrom a clean-up.

First step is to unmount the LVs:
```bash
umount /dev/mylv1
```
Make sure you unmount `mylv2` if you did mount it earlier.

Second step is to delete the LVs:
```bash
lvremove myvg/mylv1
lvremove myvg/mylv2
```

And at last, we will be deleting the VG:
```bash
vgremove myvg
```

![delete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5r5rgg7ip2efiw6sxbh.png)

I made the mistake of removing a LV before unmounting it, so I got an error.
After this command, you can issue `vgs` and `lvs` to confirm that everything is deleted.

### Fixing our USB drive
Since I have already talked about partitioning and file systems, I won't be reiterating over them.
To get started, do:
```bash
fdisk /dev/sdb
```

![fix usb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfei4lvr63xx0jxhq7d7.png)


Wallah! Your USB would now be fixed. With this, we come to the end of this blog. 

## Conclusion

In conclusion, Linux Volume Manager (LVM) serves as a crucial tool for flexible storage management. It abstracts raw storage devices (PVs) into logical volumes (LVs) within volume groups (VGs). LVM empowers us to resize LVs dynamically and handle storage with ease, providing a versatile storage solution. While some systems may limit its potential, utilizing LVM opens up possibilities for optimizing storage usage and system performance. Embrace the power of LVM in your Linux journey for seamless and efficient storage management. Happy computing!