logical volume manager (LVM)
About 9 min
logical volume manager (LVM)
main usage
- physical to logical abstraction
- you can manage multiple disks as one logical volume
- you can split one disk into multiple logical volumes
- dynamic volume resizing
- resizing logical disks
- add more physical disks or move old physical disks for needs
- in combination with hot swapping, you can add or replace disks without stopping the service
conceptions
lvm.svg from wikipedia
- PVs: physical volumes
- can be hard disks or partitions
- LVM treats each PV as a sequences of PEs(physical extends)
- PEs: physical extends
- PEs have a uniform size, which is the minimal storage size for LVM
- LEs: logical extends
- usually mapping to PEs as one to one relationship
- VG: volume group
- each VG is a pool of LE
- consequently, VG consists of multiple PVs
- LVs: logical volumes
- LEs can be concatenated together into virtual disk partitions called LVs
- LVs can be used as raw block devices, which is supported by Linux kernel
- in result, we can use LVs as file systems, swap and so on
practise
pre-requirements
- you need to know basic conceptions
- but only PV, PE, VG and LV appear in commands
purpose
- check volume structures after default centos 8 installation
- resize LV
- ext filesystem
- xfs filesystem
- swap
- resize PV
- will affect VG size
- won't affect disk partition size
- create PV? VG?
do it
- prepare a virtual machine according to create centos 8 with qemu
- check volume structures
- use
fdisk -l
to check disks[root@node-01 ~]# fdisk -l Disk /dev/vda: 40 GiB, 42949672960 bytes, 83886080 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: dos Disk identifier: 0x656b2fe0 Device Boot Start End Sectors Size Id Type /dev/vda1 * 2048 2099199 2097152 1G 83 Linux /dev/vda2 2099200 83886079 81786880 39G 8e Linux LVM Disk /dev/mapper/cl_node--01-root: 36.9 GiB, 39569063936 bytes, 77283328 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 /dev/mapper/cl_node--01-swap: 2.1 GiB, 2302672896 bytes, 4497408 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
- in this example
- we have a disk
/dev/vda
whose storage size is 40G - the disk
/dev/vda
is split to two partitions:/dev/vda1
and/dev/vda2
- the storage size of
/dev/vda1
is 1G - the storage size of
/dev/vda2
is 39G
- the storage size of
- disk
/dev/mapper/cl_node--01-root
and/dev/mapper/cl_node--01-swap
are logical partitions of LVM
- we have a disk
- use
df -h
to check mount points of partitions[root@node-01 ~]# df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 386M 0 386M 0% /dev tmpfs 405M 0 405M 0% /dev/shm tmpfs 405M 11M 395M 3% /run tmpfs 405M 0 405M 0% /sys/fs/cgroup /dev/mapper/cl_node--01-root 37G 1.7G 36G 5% / /dev/vda1 1014M 198M 817M 20% /boot tmpfs 81M 0 81M 0% /run/user/0
- in this example
/dev/vda1
is mounted to/boot
/dev/mapper/cl_node--01-root
is mounted to/
- but where is
/dev/mapper/cl_node--01-swap
?- we may guess: it's for swap according to the name
- use
cat /proc/swaps
to check swaps[root@node-01 ~]# cat /proc/swaps Filename Type Size Used Priority /dev/dm-1 partition 2248700 0 -2 [root@node-01 ~]# ll /dev/mapper/cl_node--01-swap lrwxrwxrwx. 1 root root 7 Sep 15 2021 /dev/mapper/cl_node--01-swap -> ../dm-1
- in this example
/dev/dm-1
is used for swap- and
/dev/mapper/cl_node--01-swap
is a link which point to/dev/dm-1
- use
vgs
to list VGs - use
pvs
to list VGs - use
lvs
to list VGs - demos for
vgs
,pvs
andlvs
[root@node-01 ~]# vgs VG #PV #LV #SN Attr VSize VFree cl_node-01 1 2 0 wz--n- <39.00g 0 [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 [root@node-01 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root cl_node-01 -wi-ao---- 36.85g swap cl_node-01 -wi-ao---- 2.14g
- in this example
- we have one VG named
cl_node-01
- we have one PV created by the physical disk partition device
/dev/vda2
- we have two LVs named
root
andswap
- we have one VG named
- use
lsblk -f
to check filesystems[root@node-01 ~]# lsblk -f NAME FSTYPE LABEL UUID MOUNTPOINT sr0 vda |-vda1 xfs 9174c9ea-7d2e-4bd0-b179-d24010edeaf4 /boot `-vda2 LVM2_member dw2bHR-OfJz-v2KZ-L6WE-LHa3-fVc1-zUZ9bF |-cl_node--01-root xfs 3523fb97-866b-4146-b1ae-7ed5f41da505 / `-cl_node--01-swap swap 792b46de-e709-4159-ae48-362e2dee609f [SWAP]
- in this example
- disk
vda
is partitioned tovda1
andvda2
- the filesystem type of partition
vda1
isxfs
- partition
vda2
, which is split into two LVs(cl_node--01-root
andcl_node--01-swap
), isLVM2_member
- the filesystem type of
cl_node--01-root
isxfs
- the filesystem type of
cl_node--01-swap
isswap
- disk
- use
- create PVs, VGs and LVs
- if this machine is created by
qemu
- stop it
shutdown -h now
- create another disk named
lvm.disk.qcow2
qemu-img create -f qcow2 lvm.disk.qcow2 40G
- start it again two disks
qemu-system-x86_64 \ -accel kvm \ -cpu kvm64 -smp cpus=1 \ -m 1G \ -drive file=$(pwd)/centos.8.qcow2,if=virtio,index=0,media=disk,format=qcow2 \ -drive file=$(pwd)/lvm.disk.qcow2,if=virtio,index=1,media=disk,format=qcow2 \ -rtc base=localtime \ -pidfile $(pwd)/centos.8.qcow2.pid \ -display none \ -nic user,hostfwd=tcp::1022-:22 \ -daemonize
- use
fdisk -l
we will see another disk named/dev/vdb
[root@node-01 ~]# fdisk -l ... Disk /dev/vdb: 40 GiB, 42949672960 bytes, 83886080 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 ...
- use
fdisk /dev/vdb
to partition the disk named/dev/vdb
[root@node-01 ~]# fdisk /dev/vdb 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. Device does not contain a recognized partition table. Created a new DOS disklabel with disk identifier 0xd94b045d. Command (m for help): p Disk /dev/vdb: 40 GiB, 42949672960 bytes, 83886080 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: dos Disk identifier: 0xd94b045d Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1): First sector (2048-83886079, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-83886079, default 83886079): +10G Created a new partition 1 of type 'Linux' and of size 10 GiB. Command (m for help): n Partition type p primary (1 primary, 0 extended, 3 free) e extended (container for logical partitions) Select (default p): p Partition number (2-4, default 2): First sector (20973568-83886079, default 20973568): Last sector, +sectors or +size{K,M,G,T,P} (20973568-83886079, default 83886079): +10G Created a new partition 2 of type 'Linux' and of size 10 GiB. Command (m for help): n Partition type p primary (2 primary, 0 extended, 2 free) e extended (container for logical partitions) Select (default p): p Partition number (3,4, default 3): First sector (41945088-83886079, default 41945088): Last sector, +sectors or +size{K,M,G,T,P} (41945088-83886079, default 83886079): Created a new partition 3 of type 'Linux' and of size 20 GiB. Command (m for help): p Disk /dev/vdb: 40 GiB, 42949672960 bytes, 83886080 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: dos Disk identifier: 0xd94b045d Device Boot Start End Sectors Size Id Type /dev/vdb1 2048 20973567 20971520 10G 83 Linux /dev/vdb2 20973568 41945087 20971520 10G 83 Linux /dev/vdb3 41945088 83886079 41940992 20G 83 Linux Command (m for help): F Unpartitioned space /dev/vdb: 0 B, 0 bytes, 0 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks.
- in this example
- disk
/dev/vdb
is partitioned into/dev/vdb1
,/dev/vdb2
and/dev/vdb3
- storage size of
/dev/vdb1
is 10G - storage size of
/dev/vdb2
is 10G - storage size of
/dev/vdb3
is 20G
- disk
- use
pvcreate
to create PVs[root@node-01 ~]# pvcreate /dev/vdb1 /dev/vdb2 /dev/vdb3 Physical volume "/dev/vdb1" successfully created. Physical volume "/dev/vdb2" successfully created. Physical volume "/dev/vdb3" successfully created. [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 /dev/vdb1 lvm2 --- 10.00g 10.00g /dev/vdb2 lvm2 --- 10.00g 10.00g /dev/vdb3 lvm2 --- <20.00g <20.00g
- in this example
- three PVs were created:
/dev/vdb1
,/dev/vdb1
,/dev/vdb1
- each PV bind with a disk partition
- three PVs were created:
- use
vgcreate
to create VGs[root@node-01 ~]# vgcreate vg-test /dev/vdb1 /dev/vdb2 Volume group "vg-test" successfully created [root@node-01 ~]# vgs VG #PV #LV #SN Attr VSize VFree cl_node-01 1 2 0 wz--n- <39.00g 0 vg-test 2 0 0 wz--n- 19.99g 19.99g [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 /dev/vdb1 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb2 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb3 lvm2 --- <20.00g <20.00g [root@node-01 ~]# vgextend vg-test /dev/vdb3 Volume group "vg-test" successfully extended [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 /dev/vdb1 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb2 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb3 vg-test lvm2 a-- <20.00g <20.00g [root@node-01 ~]# vgreduce vg-test /dev/vdb2 Removed "/dev/vdb2" from volume group "vg-test" [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 /dev/vdb1 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb2 lvm2 --- 10.00g 10.00g /dev/vdb3 vg-test lvm2 a-- <20.00g <20.00g [root@node-01 ~]# vgextend vg-test /dev/vdb2 Volume group "vg-test" successfully extended [root@node-01 ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 cl_node-01 lvm2 a-- <39.00g 0 /dev/vdb1 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb2 vg-test lvm2 a-- <10.00g <10.00g /dev/vdb3 vg-test lvm2 a-- <20.00g <20.00g
- in this example
- a VG named
vg-test
was created vg-test
consists of two PVs(/dev/vdb1
and/dev/vdb2
)/dev/vdb3
was added into VG namedvg-test
byvgextend
/dev/vdb2
was removed from VG namedvg-test
byvgreduce
- finally,
/dev/vdb2
was added into VG namedvg-test
byvgextend
- a VG named
- use
lvcreate
to create LVs[root@node-01 ~]# lvcreate -L 5G -n small vg-test Logical volume "small" created. [root@node-01 ~]# lvcreate -L 10G -n medium vg-test Logical volume "medium" created. [root@node-01 ~]# lvcreate -L 24G -n large vg-test Logical volume "large" created. [root@node-01 ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root cl_node-01 -wi-ao---- 36.85g swap cl_node-01 -wi-ao---- 2.14g large vg-test -wi-a----- 24.00g medium vg-test -wi-a----- 10.00g small vg-test -wi-a----- 5.00g [root@node-01 ~]# lsblk -f NAME FSTYPE LABEL UUID MOUNTPOINT sr0 vda |-vda1 xfs 9174c9ea-7d2e-4bd0-b179-d24010edeaf4 /boot `-vda2 LVM2_member dw2bHR-OfJz-v2KZ-L6WE-LHa3-fVc1-zUZ9bF |-cl_node--01-root xfs 3523fb97-866b-4146-b1ae-7ed5f41da505 / `-cl_node--01-swap swap 792b46de-e709-4159-ae48-362e2dee609f [SWAP] vdb |-vdb1 LVM2_member hqHssd-JnW3-kax3-qcHe-8YOe-5akf-6coSxT | |-vg--test-small | `-vg--test-large |-vdb2 LVM2_member yrvWiP-A0sR-SVvN-znwh-dFXK-2BLV-q8zIsU | `-vg--test-large `-vdb3 LVM2_member QgObUx-rH0u-VzKo-eyfB-yOrL-sv0F-Jxag0B |-vg--test-medium `-vg--test-large [root@node-01 ~]# fdisk -l ... Disk /dev/mapper/vg--test-small: 5 GiB, 5368709120 bytes, 10485760 sectors ... Disk /dev/mapper/vg--test-medium: 10 GiB, 10737418240 bytes, 20971520 sectors ... Disk /dev/mapper/vg--test-large: 24 GiB, 25769803776 bytes, 50331648 sectors ...
- in this example
- we create a LV named
small
, whose storage size is 5G - we create a LV named
medium
, whose storage size is 10G - we create a LV named
large
, whose storage size is 24G - LV named
small
is mapped to/dev/mapper/vg--test-small
- LV named
medium
is mapped to/dev/mapper/vg--test-medium
- LV named
large
is mapped to/dev/mapper/vg--test-large
- we create a LV named
- use
mkfs.xfs
to makexfs
filesystem for/dev/mapper/vg--test-small
and/dev/mapper/vg--test-large
mkfs.xfs /dev/mapper/vg--test-small mkfs.xfs /dev/mapper/vg--test-large
- use
mkfs.ext4
to makexfs
filesystem for/dev/mapper/vg--test-medium
mkfs.ext4 /dev/mapper/vg--test-medium
- filesystems can be mounted into any path
mkdir -p /mnt/small && mount /dev/mapper/vg--test-small /mnt/small mkdir -p /mnt/medium && mount /dev/mapper/vg--test-medium /mnt/medium mkdir -p /mnt/large && mount /dev/mapper/vg--test-large /mnt/large
[root@node-01 ~]# df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 386M 0 386M 0% /dev tmpfs 405M 0 405M 0% /dev/shm tmpfs 405M 11M 395M 3% /run tmpfs 405M 0 405M 0% /sys/fs/cgroup /dev/mapper/cl_node--01-root 37G 1.7G 36G 5% / /dev/vda1 1014M 198M 817M 20% /boot tmpfs 81M 0 81M 0% /run/user/0 /dev/mapper/vg--test-small 5.0G 68M 5.0G 2% /mnt/small /dev/mapper/vg--test-medium 9.8G 37M 9.3G 1% /mnt/medium /dev/mapper/vg--test-large 24G 204M 24G 1% /mnt/large
- if this machine is created by
- resize LV of xfs filesystem
- xfs filesystem itself not support resize
- and it's not possible for us to umount
/dev/mapper/cl_node--01-root
as it is mounted to/
- consequently, we need to use another disk
- resize LV of xfs filesystem by re-create it
[root@node-01 ~]# umount /dev/mapper/vg--test-large [root@node-01 ~]# lvremove /dev/mapper/vg--test-large Do you really want to remove active logical volume vg-test/large? [y/n]: y Logical volume "large" successfully removed [root@node-01 ~]# lvcreate -L 18G -n large vg-test WARNING: xfs signature detected on /dev/vg-test/large at offset 0. Wipe it? [y/n]: y Wiping xfs signature on /dev/vg-test/large. Logical volume "large" created. [root@node-01 ~]# mkfs.xfs /dev/mapper/vg--test-large ... [root@node-01 ~]# mount /dev/mapper/vg--test-large /mnt/large [root@node-01 ~]# umount /dev/mapper/vg--test-small [root@node-01 ~]# lvremove /dev/mapper/vg--test-small Do you really want to remove active logical volume vg-test/small? [y/n]: y Logical volume "small" successfully removed [root@node-01 ~]# lvcreate -L 11G -n small vg-test WARNING: xfs signature detected on /dev/vg-test/small at offset 0. Wipe it? [y/n]: y Wiping xfs signature on /dev/vg-test/small. Logical volume "small" created. [root@node-01 ~]# mkfs.xfs /dev/mapper/vg--test-small ... [root@node-01 ~]# mount /dev/mapper/vg--test-small /mnt/small [root@node-01 ~]# df -h ... /dev/mapper/vg--test-medium 9.8G 37M 9.3G 1% /mnt/medium /dev/mapper/vg--test-large 18G 161M 18G 1% /mnt/large /dev/mapper/vg--test-small 11G 111M 11G 1% /mnt/small
- in this example
/dev/mapper/vg--test-large
resized from 24G to 18G/dev/mapper/vg--test-small
resized from 5G to 11G- NOTE: the data will be loss, you should backup the data and restore it back in production environment
- resize LV of ext4 filesystem
- ext4 filesystem itself is resizable
- resize
/dev/mapper/vg--test-medium
umount /dev/mapper/vg--test-medium e2fsck -f /dev/mapper/vg--test-medium resize2fs /dev/mapper/vg--test-medium 3G lvreduce -L 3G /dev/mapper/vg--test-medium e2fsck /dev/mapper/vg--test-medium mount /dev/mapper/vg--test-medium /mnt/medium
[root@node-01 ~]# df -h ... /dev/mapper/vg--test-large 18G 161M 18G 1% /mnt/large /dev/mapper/vg--test-small 11G 111M 11G 1% /mnt/small /dev/mapper/vg--test-medium 2.9G 25M 2.8G 1% /mnt/medium
umount /dev/mapper/vg--test-medium e2fsck -f /dev/mapper/vg--test-medium lvextend -L +3G /dev/mapper/vg--test-medium # without size, the partition be extend with all the space resize2fs /dev/mapper/vg--test-medium e2fsck /dev/mapper/vg--test-medium mount /dev/mapper/vg--test-medium /mnt/medium
- now you can image the case
- add or remove PVs in VGs
- then resize the filesystem online
- or replace the hardware disks online(need
pvmove
which will be introduced another time)