Expanding a Linux VM’s disk without rebooting is one of those things that sounds scary until you’ve done it once. The actual process — rescan the bus, resize the partition, grow the PV, extend the LV — takes about 30 seconds once you know the commands. This works on any Linux system with LVM; the only part that varies is how you expand the virtual disk on the hypervisor side. Back up first, obviously.

Repartition The Disk

First, identify the partition that you will resize on the physical disk using fdisk.

# fdisk /dev/sda

Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p

Disk /dev/sda: 107.4 GB, 107374182400 bytes, 209715200 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 label type: dos
Disk identifier: 0x000e0e38

Device      Boot  Start      End         Blocks    Id  System
/dev/sda1   *     2048       1050623     524288    83  Linux
/dev/sda2         1050624    61876223    30412800  8e  Linux LVM
Command (m for help): q

Extend the VMDK and rescan drive

The next step is to resize the physical disk on the virtual machine. This can be done without having to reboot.

Once the disk is resized run the following command to scan for disk changes.

echo "- - -" > /sys/class/scsi_host/host0/scan

Run pvdisplay to see if the physical disk space has registered, if it hasn’t then reboot and check again.

Delete The Partition

Using fdisk delete the main partition, it will be the main linux partition typically follows the “default” partition.

IMPORTANT: DON'T delete the previous LVM signature

# fdisk /dev/sda

Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p

Disk /dev/sda: 107.4 GB, 107374182400 bytes, 209715200 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 label type: dos
Disk identifier: 0x000e0e38

    Device Boot      Start       End        Blocks     Id  System
    /dev/sda1  *     2048        1050623    524288     83  Linux
    /dev/sda2        1050624     61876223   30412800   8e  Linux LVM

Command (m for help): d
Partition number (1,2, default 2): 2 
Partition 2 is deleted

Create The New Partition

Once the partition is removed –don’t worry the data is still there– you have to create a new partition. See the following example.

Command (m for help): n 
Partition type:
    p   primary (1 primary, 0 extended, 3 free)
    e   extended
Select (default p): p 
Partition number (2-4, default 2): 2 
First sector (1050624-209715199, default 1050624): enter 
Using default value 1050624
Last sector, +sectors or +size{K,M,G} (1050624-209715199, default 209715199): enter 
Using default value 209715199
Partition 2 of type Linux and of size 99.5 GiB is set

Set the Partition Type

You will need to set the partition type to Linux LVM. The hex code is 8e. Note: On newer versions of RHEL, when listing partition types (by typing ‘L’ in fdisk), Linux LVM may appear as type 31 in the decimal list, but you should still enter the hex code ‘8e’.

Command (m for help): t
Partition number (1,2, default 2): 2
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

Write the Changes

This is the part where the partition gets rewritten, make sure all previous steps have been followed before committing these changes. If unsure, exit and start over.

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
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.
You have mail in /var/spool/mail/root

Reprobe the Partition Tables

The changes should show up when you run the pvs command. If they don’t, reboot.

# partprobe -s
/dev/sda: msdos partitions 1 2

Resize and Extend Logical Volume

Once those changes are done, the physical volume needs to be resized.

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

Confirm that the Volume Group Size

If you see that your new volume group has the correct size, then you are good to proceed.

# vgdisplay
--- Volume group ---
VG Name               vg_ce7
System ID
Format                lvm2
Metadata Areas        1
Metadata Sequence No  9
VG Access             read/write
VG Status             resizable
MAX LV                0
Cur LV                7
Open LV               7
Max PV                0
Cur PV                1
Act PV                1
VG Size               <99.50 GiB
PE Size               4.00 MiB
Total PE              25471
Alloc PE / Size       7424 / 29.00 GiB
Free  PE / Size       18047 / <70.50 GiB
VG UUID               64Vs7T-1224-124312-124124-124124

Confirm LV size in the LV pool

# lvdisplay
--- Logical volume ---
LV Path                /dev/vg_ce7/lv_root
LV Name                lv_root
VG Name                vg_ce7
LV UUID                64Vs7T-1224-124312-124124-124124
LV Write Access        read/write
LV Creation host, time localhost.localdomain, 2019-04-24 18:11:27 -0500
LV Status              available
# open                 1
LV Size                12.00 GiB
Current LE             3072
Segments               1
Allocation             inherit
Read ahead sectors     auto
- currently set to     8192
Block device           253:0

Confirm space on Disk

# df -h
Filesystem                       Size  Used Avail Use% Mounted on
/dev/mapper/vg_ce7-lv_root        12G  2.8G  9.3G  24% /
devtmpfs                         1.9G     0  1.9G   0% /dev
tmpfs                            1.9G     0  1.9G   0% /dev/shm
tmpfs                            1.9G  8.9M  1.9G   1% /run
tmpfs                            1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/mapper/vg_ce7-lv_tmp        3.0G   33M  3.0G   2% /tmp
/dev/mapper/vg_ce7-lv_home       5.0G  362M  4.7G   8% /home
/dev/mapper/vg_ce7-lv_var        3.0G  186M  2.9G   7% /var
/dev/mapper/vg_ce7-lv_log       1014M   37M  978M   4% /var/log
/dev/mapper/vg_ce7-lv_audit     1014M  636M  379M  63% /var/log/audit
/dev/sda1                        509M  182M  327M  36% /boot
tmpfs                            379M     0  379M   0% /run/user/1000

Extend the Logical Volume

# lvextend -l +100%FREE /dev/vg_ce7/lv_root
Size of logical volume vg_ce7/lv_root changed from 12.00 GiB (3072 extents) to <82.50 GiB (21119 extents).
Logical volume vg_ce7/lv_root successfully resized.

Note the + in +100%FREE — it adds all the free space to the LV. Without it, lvextend tries to set the LV’s total size to the amount of free space, which isn’t what you want. (You can also pass -r to lvextend to grow the filesystem in the same step.)

Grow the filesystem

# xfs_growfs /

meta-data=/dev/mapper/vg_ce7-lv_root     isize=512    agcount=4, agsize=786432 blks
         =                               sectsz=512   attr=2, projid32bit=1
         =                               crc=1        finobt=0 spinodes=0
data     =                               bsize=4096   blocks=3145728, imaxpct=25
         =                               sunit=0      swidth=0 blks
naming   =version 2                      bsize=4096   ascii-ci=0 ftype=1
log      =internal                       bsize=4096   blocks=2560, version=2
         =                               sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                           extsz=4096   blocks=0, rtextents=0
data blocks changed from 3145728 to 21625856
# df -h
Filesystem                       Size  Used Avail Use% Mounted on
/dev/mapper/vg_ce7-lv_root        83G  2.8G   80G   4% /
devtmpfs                         1.9G     0  1.9G   0% /dev
tmpfs                            1.9G     0  1.9G   0% /dev/shm
tmpfs                            1.9G  8.9M  1.9G   1% /run
tmpfs                            1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/mapper/vg_ce7-lv_home       5.0G  362M  4.7G   8% /home
/dev/mapper/vg_ce7-lv_tmp        3.0G   33M  3.0G   2% /tmp
/dev/mapper/vg_ce7-lv_var        3.0G  186M  2.9G   7% /var
/dev/sda1                        509M  182M  327M  36% /boot
/dev/mapper/vg_ce7-lv_log       1014M   37M  978M   4% /var/log
/dev/mapper/vg_ce7-lv_audit     1014M  636M  379M  63% /var/log/audit
tmpfs                            379M     0  379M   0% /run/user/1000