Live expand Linux LVM logical volume

Add storage from hypervisor Link to heading

First of all, log in to the hypervisor (Hyper-V, VMware, Proxmox, etc..) and go to the settings of your target Virtual Machine.

For this example, I’m expanding the Hard disk 1 from 100GB to 300GB:

If you expand the hard disk section, you will notice the SCSI index of the disk (this will be used later):

When configured, click OK.

Expand LV of Virtual Machine Link to heading

Log in to your Virtual Machine with SSH and become root.

Inspect before acting Link to heading

With lsblk command you can see that we have one disk with 3 partitions. /dev/sda is the disk, /dev/sda3 is the Physical Volume of the LVM a.k.a. PV and underneath there are 4 Logical Volumes:

The Logical Volumes are mapped into devices:

  • /dev/mapper/rl-root
  • /dev/mapper/rl-swap
  • /dev/mapper/rl-var_log
  • /dev/mapper/rl-var_lib_mysql

The first part of the volume’s name (rl) is the Volume Group a.k.a. VG that “lives” inside the Physical Volume /dev/sda3 (multiple PVs can participate in the same VG; that’s not the case here).

With the command df -h you can see which LV needs to be expanded:

Rescanning SCSI Link to heading

As you already noticed the storage space is not yet “updated” inside your Virtual Machine, so you have to rescan the SCSI adapter of the VM.

There is 1 disk available that has the index 0:0, so:

echo 1 > /sys/class/scsi_disk/0\:0\:0\:0/device/rescan

The above command will rescan the SCSI adapter. To explain it better:

0:0:0:0 -> scsi 0 : channel 0 : ID 0 : Lun 0

You can verify it by running the below:

cat /proc/scsi/scsi

Output:

Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: VMware   Model: Virtual disk     Rev: 2.0
  Type:   Direct-Access                    ANSI  SCSI revision: 06

Now that you’ve rescanned the adapter, verify that the storage is “updated” by running lsblk again:

Expanding the PV Link to heading

Now that you’ve expanded the disk itself, you have to assign the remaining/preferred disk space to the Physical Volume which then will be assigned to the LV.

fdisk /dev/sda

Will output something like this (ignore the size mismatch, this is what you are fixing now):

Welcome to fdisk (util-linux 2.32.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

GPT PMBR size mismatch (209715199 != 629145599) will be corrected by write.
The backup GPT table is not on the end of the device. This problem will be corrected by write.

Command (m for help): 

With p you can list the partitions of the disk:

Disk /dev/sda: 300 GiB, 322122547200 bytes, 629145600 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: gpt
Disk identifier: 02812CD9-4390-4F6A-ADBE-2D030FFD4820

Device       Start       End   Sectors  Size Type
/dev/sda1     2048   1230847   1228800  600M EFI System
/dev/sda2  1230848   3327999   2097152    1G Linux filesystem
/dev/sda3  3328000 209713151 206385152 98.4G Linux LVM

Delete the partition that holds the LVM (/dev/sda3) with d:

This won’t delete the partition YET but write the configuration of the partition in memory.

Command (m for help): d
Partition number (1-3, default 3): 3

Partition 3 has been deleted.

Create a new partition with the same index (3) with n without deleting the signature of the LVM that is still living in these sectors:

Command (m for help): n
Partition number (3-128, default 3): 3
First sector (3328000-629145566, default 3328000): 3328000
Last sector, +sectors or +size{K,M,G,T,P} (3328000-629145566, default 629145566): 629145566

Created a new partition 3 of type 'Linux filesystem' and of size 298.4 GiB.
Partition #3 contains a LVM2_member signature.

Do you want to remove the signature? [Y]es/[N]o: N

Change the type of the newly created partition with t:

Command (m for help): t
Partition number (1-3, default 3): 3
Partition type (type L to list all types): 31

Changed type of partition 'Linux filesystem' to 'Linux LVM'.

For your information, here is a table with the LVM partition type codes for the latest RHEL based distributions:

Distro Code
RHEL9 30
RHEL8 31
RHEL7 8e

Finally, wirite the changes from memory to the partition table with w:

Command (m for help): w
The partition table has been altered.
Syncing disks.

Some times, the kernel must be informed as well for the changes you’ve made:

partprobe -s

Output:

/dev/sda: gpt partitions 1 2 3

Verify the changes you’ve made by running lsblk one more time:

Resize the PV:

pvresize /dev/sda3

Output:

  Physical volume "/dev/sda3" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized

Expanding the LV Link to heading

Now that you’ve assigned the storage to the PV, it’s time to assign the remaining/preferred space to the target LV which is /dev/mapper/rl-var_lib_mysql in our example:

lvextend -l +100%FREE /dev/mapper/rl-var_lib_mysql

Output:

  Size of logical volume rl/var_lib_mysql changed from 70.00 GiB (17920 extents) to 270.00 GiB (69120 extents).
  Logical volume rl/var_lib_mysql successfully resized.

Verify with lsblk again:

Expanding the Filesystem Link to heading

First of all, check what filesystem has been assigned to the LV with lsblk -f:

You are noticing that the FS is XFS, so we can use the below command to expand/grow the filesystem:

xfs_growfs /var/lib/mysql

Output:

meta-data=/dev/mapper/rl-var_lib_mysql isize=512    agcount=4, agsize=4587520 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=18350080, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=8960, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 18350080 to 70778880

For ext4 you can use the command resize2fs instead

Verify the changes by running df -h: