Hot-Expanding Linux VM Disk Partitions Without Downtime
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