Resizing the system volume on a Linux VM

Background

With LVM, the preferred way of adding storage space to a computer running a Linux-based operating system seems to be to add disks, judging by my search results. Naturally, this is a great way of minimizing disruption in a physical machine, but what if you’re running your machines virtually? Adding virtual disks tends to get messy after a while, and hypervisors allow you to simply grow the vdisk, so why not do that?

Problem is, the old way I used to do it (using partprobe after growing the partition) required a system reboot to see the entire available new space if I attempted it on the system volume. Documented below is a better way.

The process

Start by confirming the current disk size so we know our baseline.

# fdisk -l

Disk /dev/sda: 26.8 GB, 26843545600 bytes, 52428800 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: 0x000ba3e8

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    52428799    25164800   8e  Linux LVM

Disk /dev/mapper/ol-root: 18.2 GB, 18249416704 bytes, 35643392 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

OK, so we have slightly less than 27 GB of disk space. Let’s grow the disk image in the hypervisor, and then re-scan the device.

# ls /sys/class/scsi_device/
1:0:0:0 2:0:0:0
# echo 1 > /sys/class/scsi_device/1\:0\:0\:0/device/rescan
# fdisk -l

Disk /dev/sda: 80.5 GB, 80530636800 bytes, 157286400 sectors
(...)

Now we have the disk space available, let’s perform the steps to grow our file system.

# fdisk /dev/sda


Command (m for help): p

Disk /dev/sda: 80.5 GB, 80530636800 bytes, 157286400 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: 0x000ba3e8

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 2099199 1048576 83 Linux
/dev/sda2 2099200 52428799 25164800 8e Linux LVM

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

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

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

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

The above statement is followed by what used to be a problem:

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.

Partprobe won’t help us here, and kpartx for some reason doesn’t consistently catch the entire new disk size. The correct way, then, is the following:

# partx -u /dev/sda2

The result?

# partx -s /dev/sda
NR START END SECTORS SIZE NAME UUID
 1 2048 2099199 2097152 1G 
 2 2099200 157286399 155187200 74G

Now let’s finish extending everything up to the actual file system:

# pvresize /dev/sda2
 Physical volume "/dev/sda2" changed
 1 physical volume(s) resized / 0 physical volume(s) not resized
# lvextend -l 100%VG /dev/mapper/ol-root
 Size of logical volume ol/root changed from <17.00 GiB (4351 extents) to <72.00 GiB (18431 extents).
 Logical volume ol/root successfully resized.
# xfs_growfs /dev/mapper/ol-root

And finally let’s check that everything worked out as we expected:

# df -h
Filesystem Size Used Avail Use% Mounted on
(...)
/dev/mapper/ol-root 72G 17G 56G 24% /
(...)

Conclusion

The Windows family of operating systems has had the ability to grow any volume on the fly since Server 2008. I couldn’t imagine that Linux would lack this ability, but I didn’t know how to do it the right way. Now I do.