LVM (Logical Volume Manager): The Complete Guide¶
LVM adds a flexible abstraction layer between physical disks and the filesystems that live on them. Instead of being locked into fixed partitions, you pool storage together and carve it into logical volumes that can be grown, shrunk, moved between disks, snapshotted, mirrored, and cached, usually without downtime.
Reference: Logical Volume Manager (Linux), Wikipedia
Conventions used in this guide
- Volume group:
vg_data. Logical volume:lv_data. Disks:/dev/sdb,/dev/sdc.- Commands need root (
sudo).- Most LVM commands accept
-t/--test(dry run) and-v(verbose). Use them when in doubt.- Destructive commands are marked with WARNING.
Table of Contents¶
- Concepts and architecture
- Inspecting LVM
- Creating LVM storage
- Growing storage
- Shrinking storage
- Moving data and reorganizing
- Renaming, removing, and deactivating
- Snapshots
- Thin provisioning
- RAID, mirroring, and striping
- Caching with dm-cache
- Encryption with LUKS
- Metadata backup, restore, and recovery
- Foreign and external volumes
- Low-level device-mapper tricks
- Configuration (
lvm.conf) - Troubleshooting
- Best practices
- Cheat sheet
1. Concepts and architecture¶
LVM has three main layers, built bottom to top:
Filesystem (ext4, xfs, swap, ...)
|
Logical Volumes (LV) /dev/vg_data/lv_data (also /dev/mapper/vg_data-lv_data)
|
Volume Group (VG) vg_data (a pool of extents)
|
Physical Volumes (PV) /dev/sdb1, /dev/sdc, /dev/mapper/luks-...
|
Block devices disks, partitions, RAID arrays, LUKS mappings, iSCSI/SAN LUNs
| Term | Meaning |
|---|---|
| PV (Physical Volume) | A block device initialized for LVM. It holds an LVM label and metadata. |
| VG (Volume Group) | One or more PVs pooled together. The unit of administration. |
| LV (Logical Volume) | A virtual block device carved from a VG. You put a filesystem (or swap, or a database) on it. |
| PE (Physical Extent) | The allocation unit of a PV (default 4 MiB). All space is handed out in whole PEs. |
| LE (Logical Extent) | The allocation unit of an LV. Each LE maps to one PE (or more, when mirrored). |
| device-mapper | The kernel subsystem that implements LVM (and LUKS, multipath, and more). LVs appear as /dev/dm-N. |
| Metadata | Text description of the VG layout stored on each PV, with backups in /etc/lvm/backup and history in /etc/lvm/archive. |
Because sizes are rounded up to whole extents, an LV of "10G" may occupy slightly more than requested if the size is not a multiple of the PE size.
Common LV types: linear (default), striped, mirror/RAID (raid1, raid5, raid6, raid10), snapshot, thin pool, thin volume, cache.
Filesystem support at a glance:
| Filesystem | Grow online | Shrink | Grow tool | Shrink tool |
|---|---|---|---|---|
| ext4 | Yes | Yes, offline only | resize2fs |
resize2fs |
| XFS | Yes | Never | xfs_growfs (takes the mount point) |
n/a |
| Btrfs | Yes | Yes (online) | btrfs filesystem resize |
btrfs filesystem resize |
| JFS | Yes | No | mount option remount,resize |
n/a |
| swap | n/a | n/a | mkswap again |
mkswap again |
2. Inspecting LVM¶
Always look before you leap.
Summaries¶
pvs # one line per physical volume
vgs # one line per volume group
lvs # one line per logical volume
lvs -a -o +devices # include hidden LVs and show which PVs back each LV
pvs -o +uuid # show PV UUIDs
lsblk -f # tree view of disks, LVs, filesystems, UUIDs, mount points
Detail¶
pvdisplay
vgdisplay
lvdisplay
Key fields to check before any resize:
pvdisplay: are the LVs you care about on the same PV / VG? (VG Name,Free PE)vgdisplay:VG Size,PE Size,Alloc PE / Size, and especiallyFree PE / Size, which is space you can allocate right now.lvs: LV sizes and the attribute string (see below).
Example vgs output:
VG #PV #LV #SN Attr VSize VFree
vg_data 1 3 0 wz--n- 40.29g 5.84g
Reading the lvs Attr column¶
The attribute string is positional. Common values:
| Position | Meaning |
|---|---|
| 1 | Volume type: - linear, s snapshot, V thin volume, t thin pool, r RAID, m mirror, C cache |
| 2 | Permissions: w writable, r read-only |
| 3 | Allocation policy (i inherited) |
| 5 | State: a active, s suspended, I invalid snapshot, S invalid suspended snapshot |
| 6 | Device: o open (mounted or in use) |
So -wi-ao---- means a linear, writable LV that is active and open.
Low-level device-mapper view¶
dmsetup ls # all mapped devices
dmsetup ls --tree # dependency tree (great for LUKS on LVM)
dmsetup info /dev/vg_data/lv_data # state, open count, major/minor, UUID
dmsetup table # the actual mapping tables
Open count matters: a non-zero value means something (a mount, a process, another mapping) is holding the device open, and removal will fail.
3. Creating LVM storage¶
3.1 Prepare the disk¶
You can use a whole disk or a partition. Whole-disk PVs are simple and fine for data disks; partitions are safer on shared/boot disks because other tools can see that a partition table exists.
Partition (optional):
# GPT with one partition spanning the disk, flagged for LVM
parted -s /dev/sdb mklabel gpt mkpart primary 1MiB 100% set 1 lvm on
# or interactively
fdisk /dev/sdb # new partition; set type to "Linux LVM" (8e00 in gdisk, 8e in fdisk/MBR)
Re-using a disk? Wipe old signatures first so old RAID/filesystem/LVM labels do not confuse things:
wipefs -a /dev/sdb1 # WARNING: destroys signatures
3.2 Create the Physical Volume¶
pvcreate /dev/sdb1
pvdisplay /dev/sdb1
3.3 Create the Volume Group¶
vgcreate vg_data /dev/sdb1
# Optional: choose a different PE size (default 4 MiB). Larger PEs suit huge VGs.
vgcreate -s 16M vg_data /dev/sdb1
vgdisplay vg_data
3.4 Create Logical Volumes¶
# Fixed size
lvcreate -L 10G -n lv_data vg_data
# Percentage of the VG or of the remaining free space
lvcreate -l 50%VG -n lv_half vg_data
lvcreate -l 100%FREE -n lv_rest vg_data # note: %FREE, all remaining space
lvdisplay /dev/vg_data/lv_data
Size options at a glance:
| Option | Meaning |
|---|---|
-L 10G |
Absolute size in bytes-based units |
-L +5G |
Add 5G (extend/resize commands) |
-l 2560 |
Size in extents |
-l +100%FREE |
Use all remaining free space |
-l 50%VG |
Half of the entire VG |
-l 20%ORIGIN |
Relative to the snapshot origin |
3.5 Make a filesystem¶
mkfs.ext4 /dev/vg_data/lv_data
# or
mkfs.xfs /dev/vg_data/lv_data
/dev/vg_data/lv_data and /dev/mapper/vg_data-lv_data are the same device. Note that in the mapper name, any hyphen in the VG or LV name is doubled (my-vg / my-lv becomes my--vg-my--lv).
3.6 Mount it persistently¶
mkdir -p /data
blkid /dev/vg_data/lv_data # copy the UUID (or use lsblk -f)
Add to /etc/fstab. Make sure the filesystem type in fstab matches what you actually created:
UUID=afa2f55b-49c2-4e16-9fba-b7fab68bfbdb /data xfs defaults 0 0
# or, using the stable device path (equally valid for LVs):
/dev/mapper/vg_data-lv_data /data ext4 defaults 0 2
For non-critical volumes add nofail so a missing disk does not drop the system into emergency mode.
mount -a # validates fstab entries and mounts anything new
df -h /data
Tip: XFS uses
0for the fsck field because it does not usefsckat boot; ext4 uses2for non-root filesystems.
4. Growing storage¶
Growing is the safe, everyday operation. It can be done online (mounted) for ext4 and XFS.
There are two questions to answer:
- Is there free space in the VG? If not, add capacity to the VG first (4.2 / 4.3).
- Extend the LV, then extend the filesystem inside it.
4.1 Extend an LV using free VG space¶
vgs # check VFree
lvextend -L +5G /dev/vg_data/lv_data # add 5 GiB
The one-command way (recommended): -r / --resizefs grows the filesystem for you, picking the correct tool:
lvextend -r -L +5G /dev/vg_data/lv_data
lvextend -r -l +100%FREE /dev/vg_data/lv_data # use all free space
lvextend -r -L 50G /dev/vg_data/lv_data # to an absolute size
The manual way, when you extend the LV without -r:
# ext4
resize2fs /dev/vg_data/lv_data # grows to fill the LV
resize2fs -p /dev/vg_data/lv_data # with progress
# XFS (argument is the MOUNT POINT, and it must be mounted)
xfs_growfs /data
xfs_growfs -D <blocks> /data # grow to a specific size in blocks
# Generic front end that picks the right tool
fsadm resize /dev/vg_data/lv_data
Legacy note: very old systems used
ext2onlinefor online ext3 growth. It has been folded intoresize2fsfor many years and should no longer be needed.
4.2 Add a new disk to the VG¶
pvcreate /dev/sdc
vgextend vg_data /dev/sdc
lvextend -r -l +100%FREE /dev/vg_data/lv_data
To extend an LV onto a specific PV:
lvextend -r -L +20G /dev/vg_data/lv_data /dev/sdc
4.3 Grow the underlying disk (virtual disks, SAN LUNs, cloud volumes)¶
When the hypervisor or storage array enlarges an existing disk, tell the kernel and LVM about the new size.
Case A: PV is a whole disk
echo 1 > /sys/class/block/sdb/device/rescan # kernel re-reads size
pvresize /dev/sdb
lvextend -r -l +100%FREE /dev/vg_data/lv_data
Case B: PV is a partition (grow the partition first)
echo 1 > /sys/class/block/sda/device/rescan
growpart /dev/sda 2 # from cloud-utils-growpart; or use parted/fdisk to resize the partition
pvresize /dev/sda2
lvextend -r -l +100%FREE /dev/vg_data/lv_data
4.4 Add a new virtual disk (VMware, KVM, cloud) without a reboot¶
Snapshot the disk list before and after so you can see exactly what appeared:
lsblk > /tmp/disks-pre.txt
# ...attach the disk in the hypervisor / cloud console...
# Rescan every SCSI host
for h in /sys/class/scsi_host/host*; do echo "- - -" > "$h/scan"; done
# or: rescan-scsi-bus.sh (package: sg3_utils / scsitools)
lsblk > /tmp/disks-post.txt
diff /tmp/disks-pre.txt /tmp/disks-post.txt
pvcreate /dev/sdb
vgextend vg_data /dev/sdb
lvextend -r -l +100%FREE /dev/vg_data/lv_data
Then verify with df -h and lvs.
5. Shrinking storage¶
Shrinking is the risky operation. The golden rule:
Shrink the filesystem first, then the LV. Grow the LV first, then the filesystem.
If you reduce the LV below the size of the filesystem, you truncate the filesystem and corrupt data. Take a backup first.
Requirements and limits¶
- ext4 can shrink, but only offline (unmounted). For the root filesystem, boot from a live USB/rescue environment.
- XFS and JFS cannot be shrunk. The only option is: back up, recreate a smaller LV and filesystem, restore.
- Btrfs can shrink online.
- Check the filesystem's used space first (
df -h); you cannot shrink below the data in use plus overhead.
5.1 The easy way: lvreduce -r¶
umount /data
e2fsck -f /dev/vg_data/lv_data # required by resize2fs before shrinking
lvreduce -r -L 5G /dev/vg_data/lv_data # shrinks fs then LV, in the right order
mount /data
-r calls fsadm/resize2fs for you, shrinking the filesystem before the LV. LVM will prompt with a data-loss warning unless you use -f.
5.2 The manual, step-by-step way (ext4)¶
Example: reduce a 10 GiB volume to 5 GiB.
# 1. Unmount
umount /data
# 2. Check the filesystem (mandatory)
e2fsck -f /dev/vg_data/lv_data
# 3. Shrink the FILESYSTEM to slightly LESS than the target size
# (resize2fs accepts whole units like 4G; fractional values such as 4.5G are rejected)
resize2fs /dev/vg_data/lv_data 4G
# 4. Shrink the LV to the target size
lvreduce -L 5G /dev/vg_data/lv_data
# WARNING: Reducing active logical volume to 5.00 GiB
# THIS MAY DESTROY YOUR DATA (filesystem etc.)
# Do you really want to reduce lv_data? [y/n]: y
# 5. Grow the filesystem to fill the LV exactly (reclaims the safety margin)
resize2fs /dev/vg_data/lv_data
# 6. Remount and verify
mount /data
df -h /data
Why the safety margin? Shrinking the filesystem to 4G first, then the LV to 5G, guarantees the LV never ends up smaller than the filesystem. Step 5 then grows the filesystem into the remaining 1G.
5.3 Worked example: move free space from /home to /¶
A common scenario: / is nearly full while /home has plenty of room, and both are in the same VG.
- Are they in the same VG, and is there free space?
bash
pvs; vgs; lvs
Suppose the VG has 5.8 GiB free, root is 5.6 GiB at 97% used, and home is 23 GiB at 6% used.
- Use the free VG space first. It needs no shrinking:
bash
lvextend -r -L +5G /dev/vg/root
- Need more? Take it from
/home(offline, from a live/rescue environment if/homecannot be unmounted, or just log out and unmount from a root shell):
bash
umount /home
e2fsck -f /dev/vg/home
lvreduce -r -L -3G /dev/vg/home # shrink by 3 GiB
mount /home
lvextend -r -l +100%FREE /dev/vg/root
- Verify with
df -handlvs.
If a volume is on an encrypted (LUKS) layer, the layers must be shrunk in order: filesystem, then the LUKS mapping, then the LV. See section 12.
5.4 Shrinking the VG (removing a PV)¶
You cannot remove a PV that still holds data. Move the data off it, then remove it from the VG:
pvmove /dev/sdb # migrate all extents from sdb to other PVs in the VG
vgreduce vg_data /dev/sdb # remove sdb from the VG
pvremove /dev/sdb # wipe the LVM label (optional)
# Removed "/dev/sdb" from volume group "vg_data"
pvmove needs enough free extents on the remaining PVs. See section 6.
5.5 Undoing a mistaken shrink¶
If you shrank the LV before the filesystem, stop writing to it immediately. Do not simply re-extend: LVM may not hand back the same blocks, which corrupts the filesystem. Instead, restore the earlier metadata from the archive (see section 13). This only works if the freed extents have not been reused since.
6. Moving data and reorganizing¶
Move extents between PVs (online)¶
pvmove /dev/sdb # everything off sdb
pvmove /dev/sdb /dev/sdc # everything off sdb, onto sdc specifically
pvmove -n lv_data /dev/sdb /dev/sdc # only lv_data's extents
pvmove -i 5 /dev/sdb # report progress every 5 seconds
pvmove is safe to interrupt and resume: run pvmove with no arguments to continue, or pvmove --abort to cancel.
Typical uses: replacing an old disk, migrating to a faster disk, evacuating a failing disk.
Split and merge volume groups¶
# Merge: absorb vg_old into vg_data (vg_old must be inactive)
vgchange -an vg_old
vgmerge vg_data vg_old
# Split: move a PV (and the LVs entirely on it) into a new VG
vgsplit vg_data vg_new /dev/sdc
Migrate a whole VG to another machine¶
umount /data
vgchange -an vg_data
vgexport vg_data
# physically move the disks
vgimport vg_data
vgchange -ay vg_data
7. Renaming, removing, and deactivating¶
Rename¶
vgs; lvs
lvrename vg_data lv_old lv_new # same as: lvrename vg_data/lv_old vg_data/lv_new
vgrename vg_old vg_new
After renaming, update /etc/fstab, bootloader config (root=), and initramfs if the VG or LV holds the root filesystem, or the system may not boot. Rebuild with update-initramfs -u (Debian/Ubuntu) or dracut -f (RHEL/Fedora).
Deactivate and reactivate¶
umount /data
lvchange -an /dev/vg_data/lv_data # deactivate one LV
lvchange -ay /dev/vg_data/lv_data # activate it again
vgchange -an vg_data # deactivate the whole VG
vgchange -ay vg_data # activate all LVs in the VG
(--available y is the long form of -ay.)
Remove: go in reverse order of creation¶
WARNING: destroys data.
umount /data # and remove the fstab entry
lvremove /dev/vg_data/lv_data # 1. remove the logical volume(s)
vgremove vg_data # 2. remove the volume group
pvremove /dev/sdb1 # 3. remove the physical volume label
To remove a single PV from a VG that continues to exist, use pvmove then vgreduce (section 5.4). Note that vgreduce requires the PV to be empty.
8. Snapshots¶
A snapshot is a point-in-time view of an LV. Classic (thick) LVM snapshots use copy-on-write: when the origin changes, the old blocks are copied into the snapshot's own space first.
8.1 Classic snapshots¶
# The size (-L) is the space reserved to store CHANGES, not a full copy
lvcreate -L 5G --snapshot --name lv_data_snap /dev/vg_data/lv_data
lvs
Use it for consistent backups:
mkdir -p /mnt/snap
mount -o ro /dev/vg_data/lv_data_snap /mnt/snap # for XFS add: -o ro,nouuid
tar -C /mnt/snap -czf /backup/data.tar.gz .
umount /mnt/snap
lvremove -y /dev/vg_data/lv_data_snap
Things to know:
- Size matters. If changes to the origin exceed the snapshot's space, the snapshot becomes invalid (Attr shows
I) and is unusable. MonitorData%inlvsand size for expected churn (10-20% of the origin is a common start). - Snapshots slow writes to the origin (copy-on-write overhead). Do not leave them around indefinitely.
- You can extend a snapshot:
lvextend -L +2G /dev/vg_data/lv_data_snap. - Automatic extension can be configured with
snapshot_autoextend_thresholdandsnapshot_autoextend_percentinlvm.conf. - XFS snapshots share the origin's UUID; mount with
-o nouuidif the origin is mounted at the same time. - Flush application state first (database checkpoint,
fsfreeze) for application-consistent snapshots.
8.2 Roll back (merge) a snapshot¶
To revert the origin to the state at the time of the snapshot:
umount /data
lvconvert --merge /dev/vg_data/lv_data_snap
# If the origin is busy, the merge is deferred until the next activation:
lvchange -an /dev/vg_data/lv_data && lvchange -ay /dev/vg_data/lv_data
mount /data
The snapshot is consumed by the merge. Anything written to the origin after the snapshot was taken is lost.
8.3 Snapshotting a swap or system volume¶
Any LV can be snapshotted, e.g.:
lvcreate -L 5G --snapshot --name web-dev-snap /dev/vg01/web-dev
For VM images, snapshot the LV backing the VM, and shut down (or freeze) the guest for consistency.
Thin snapshots (section 9) avoid most of these limitations.
9. Thin provisioning¶
Thin provisioning lets you allocate more virtual space than physically exists ("overprovisioning") and store data only as it is written. It also gives cheap, fast, unlimited-ish snapshots.
9.1 Create a thin pool and thin volumes¶
# 1. Create the pool (data + metadata) from real space
lvcreate --type thin-pool -L 100G -n pool0 vg_data
# 2. Create thin volumes with a VIRTUAL size (can exceed the pool)
lvcreate --thin -V 500G -n lv_thin1 vg_data/pool0
lvcreate --thin -V 500G -n lv_thin2 vg_data/pool0
mkfs.xfs /dev/vg_data/lv_thin1
9.2 Thin snapshots¶
Thin snapshots need no size argument and are independent of the origin's lifetime:
lvcreate -s -n lv_thin1_snap vg_data/lv_thin1
lvchange -ay -K vg_data/lv_thin1_snap # -K: ignore the "activation skip" flag
9.3 Monitor and protect the pool¶
A full thin pool is an outage. Watch it:
lvs -a -o +data_percent,metadata_percent
Enable auto-extension in lvm.conf (requires the dmeventd monitoring service):
activation {
thin_pool_autoextend_threshold = 80
thin_pool_autoextend_percent = 20
}
Extend manually if needed:
lvextend -L +50G vg_data/pool0
lvextend --poolmetadatasize +1G vg_data/pool0
Return unused space to the pool by mounting with discard or running fstrim -av periodically.
10. RAID, mirroring, and striping¶
LVM can do RAID itself via the kernel's MD RAID code (--type raid*). Alternatively, place LVM on top of mdadm arrays. Both are valid; pick one approach and stay consistent.
10.1 Striping (performance)¶
# Stripe across 2 PVs with a 64 KiB stripe size
lvcreate -i 2 -I 64 -L 50G -n lv_fast vg_data
Striping has no redundancy: losing one PV loses the whole LV.
10.2 RAID1 (mirroring)¶
lvcreate --type raid1 -m 1 -L 50G -n lv_mirror vg_data
lvs -a -o name,copy_percent,devices # watch the initial sync
Add or remove a mirror leg:
lvconvert -m +1 vg_data/lv_mirror # add a third copy
lvconvert -m -1 vg_data/lv_mirror # drop back
10.3 Other RAID levels¶
lvcreate --type raid5 -i 3 -L 100G -n lv_r5 vg_data # 3 data stripes + parity (4 PVs)
lvcreate --type raid6 -i 3 -L 100G -n lv_r6 vg_data # 3 data + 2 parity (5 PVs)
lvcreate --type raid10 -i 2 -m 1 -L 100G -n lv_r10 vg_data
10.4 Health and repair¶
lvs -a -o name,raid_sync_action,sync_percent,raid_mismatch_count
lvchange --syncaction check vg_data/lv_mirror # scrub
lvchange --syncaction repair vg_data/lv_mirror
lvconvert --repair vg_data/lv_mirror # replace a failed leg using free PVs
11. Caching with dm-cache¶
Use a fast device (NVMe/SSD) to accelerate a slow LV (HDD).
# 1. Add the fast device to the VG
pvcreate /dev/nvme0n1p1
vgextend vg_data /dev/nvme0n1p1
# 2. Create a cache volume on the fast device
lvcreate -n cache0 -L 50G vg_data /dev/nvme0n1p1
# 3. Attach it to the slow LV
lvconvert --type cache --cachevol cache0 vg_data/lv_data
# Optional: choose the cache mode (writethrough is safer; writeback is faster)
lvconvert --type cache --cachevol cache0 --cachemode writethrough vg_data/lv_data
Remove the cache (flushes dirty data first) with:
lvconvert --uncache vg_data/lv_data
Use writeback only with redundant cache devices, because losing the cache can lose data that was not yet flushed to the slow disk.
12. Encryption with LUKS¶
There are two common layouts:
| Layout | Description | Use when |
|---|---|---|
| LUKS on LVM | Each LV is separately encrypted: PV → VG → LV → LUKS → filesystem |
You want different keys per volume or to leave some volumes unencrypted. |
| LVM on LUKS | The whole disk/partition is encrypted once: disk → LUKS → PV → VG → LV → filesystem |
You want one passphrase and the whole VG (incl. LV names and layout) hidden. |
12.1 Add an encrypted volume to an existing system (LUKS on LVM)¶
# 1. (Only if re-using a disk) overwrite old data with random data
dd if=/dev/urandom of=/dev/sdb bs=1M status=progress # WARNING: destroys all data
# 2. Partition and set up LVM as usual
pvcreate /dev/sdb1
vgcreate vg_secure /dev/sdb1
lvcreate -L 20G -n lv_secure vg_secure
# 3. Encrypt the LV
cryptsetup luksFormat /dev/vg_secure/lv_secure
cryptsetup luksOpen /dev/vg_secure/lv_secure secure
# 4. Filesystem and mount
mkfs.ext4 /dev/mapper/secure
mount /dev/mapper/secure /mnt/secure
Persist with /etc/crypttab (secure /dev/vg_secure/lv_secure none luks) and /etc/fstab (/dev/mapper/secure /mnt/secure ext4 defaults 0 2).
12.2 Grow a LUKS-encrypted volume¶
Order: LV, then LUKS mapping, then filesystem.
Modern cryptsetup and ext4/XFS can do this online with the volume open and mounted:
lvextend -L +20G /dev/vg_data/lv_crypt # 1. grow the LV
cryptsetup resize secure # 2. grow the LUKS mapping (name of the opened mapping)
resize2fs /dev/mapper/secure # 3. ext4 (or: xfs_growfs /mnt/secure)
df -h /mnt/secure
If the encrypted volume is the root filesystem, the online approach above works too on current systems. On older systems, or if something goes wrong, use a live USB:
# From a live environment
cryptsetup luksOpen /dev/vg_data/lv_root encrypted
fsck.ext4 -C 0 -f /dev/mapper/encrypted # check first
lvextend -L +20G /dev/vg_data/lv_root # (skip if already extended online)
cryptsetup --verbose resize encrypted
fsck.ext4 -f /dev/mapper/encrypted
resize2fs /dev/mapper/encrypted
mount /dev/mapper/encrypted /mnt/encrypted
df -h /mnt/encrypted
cryptsetup luksClose encrypted # after unmounting
Use a mapping name that does not clash with the LV's own mapper name (for example encrypted, not vg_data-lv_root).
12.3 Shrink a LUKS-encrypted volume¶
Reverse order: filesystem, then LUKS, then LV. ext4 only, offline:
umount /mnt/secure
e2fsck -f /dev/mapper/secure
resize2fs /dev/mapper/secure 8G # 1. shrink the filesystem
cryptsetup resize secure --size $(( 9 * 1024 * 1024 * 2 )) # 2. LUKS size in 512-byte sectors (9 GiB here, with margin)
lvreduce -L 10G /dev/vg_data/lv_secure # 3. LV, keeping it larger than the LUKS device
cryptsetup resize secure # 4. grow the mapping to fill the LV
resize2fs /dev/mapper/secure # 5. grow the filesystem to fill it
Keep margins between layers (fs < LUKS < LV) at every step, and take a backup first.
12.4 Mount and unmount an external encrypted LVM disk¶
cryptsetup luksOpen /dev/sdx1 externalcrypt # enter the passphrase
vgscan
vgchange -ay
mount /dev/mapper/vgXXX-lv_root /mnt/external
# ...when done, tear down in reverse order
umount /mnt/external
vgchange -an vgXXX
cryptsetup luksClose externalcrypt
lsblk -f
13. Metadata backup, restore, and recovery¶
LVM automatically saves a text copy of VG metadata before and after every change:
| Location | Purpose |
|---|---|
/etc/lvm/backup/<vg> |
The most recent metadata for each VG |
/etc/lvm/archive/<vg>_NNNNN-<random>.vg |
History: one file per change. Kept as long as archive = 1 in lvm.conf. |
Archiving is controlled by backup and archive in /etc/lvm/lvm.conf (both default to 1). Keep them on.
Metadata is not data. Restoring metadata brings back the layout (which extents belong to which LV). It cannot recover contents overwritten after the change. Act quickly, and do not write to the affected disks.
13.1 Manual backup¶
vgcfgbackup # all VGs to /etc/lvm/backup
vgcfgbackup -f /root/vg_data.meta vg_data
Copy these files off the machine. If the disk that holds /etc/lvm dies, the on-disk metadata copy on the PV is still there, but an off-box copy is a lifesaver.
13.2 List the history¶
ls -ltrah /etc/lvm/archive/
vgcfgrestore -l vg_data
Each entry shows a description of the command that triggered the archive (for example, Created *before* executing 'lvreduce -L -256M ...'). Use these descriptions to pick the archive taken just before the change you want to undo.
13.3 Undo a change (restore an earlier layout)¶
umount /data # LVs of the VG must not be in use
lvchange -an /dev/vg_data/lv_data # or vgchange -an vg_data
# Dry run first
vgcfgrestore --test -f /etc/lvm/archive/vg_data_00001-1528176681.vg vg_data
# Do it
vgcfgrestore -f /etc/lvm/archive/vg_data_00001-1528176681.vg vg_data
vgchange -ay vg_data
Then run fsck on the filesystem before mounting it.
13.4 Recover accidentally removed logical volumes¶
Symptom: after an lvremove, vgchange -ay reports 0 logical volume(s) in volume group "vg_data" now active.
ls -ltrah /etc/lvm/archive/ # find archives for the VG, newest last
vgcfgrestore --test -f /etc/lvm/archive/vg_data_00002-504999937.vg vg_data
vgcfgrestore -f /etc/lvm/archive/vg_data_00002-504999937.vg vg_data
vgchange -ay vg_data
ls /dev/mapper/
If only some LVs came back (for instance just swap), you picked a state that is too recent or too old. Try an earlier archive file (the one with the previous sequence number) until all the LVs you expect are present:
vgcfgrestore -f /etc/lvm/archive/vg_data_00001-878307462.vg vg_data
vgchange -ay vg_data
Each restore is itself archived, so you can move back and forth between states safely.
13.5 vgcfgrestore fails¶
"Couldn't find device with uuid ..." / "Cannot restore Volume Group ... with N PVs marked as missing".
- Is the PV encrypted? Open it first (
cryptsetup luksOpen ...) and then retry. This is the most common cause. - Check the PV UUIDs that LVM can currently see and compare them with the archive:
bash
pvs -o +uuid
lvs -o +devices
grep -A3 'pv0 {' /etc/lvm/archive/vg_data_00002-504999937.vg # UUID the archive expects
- If a PV was wiped or replaced, recreate it with the original UUID using the archive as a template, then restore:
bash
pvcreate --uuid <original-uuid> --restorefile /etc/lvm/archive/vg_data_00002-504999937.vg /dev/sdX
vgcfgrestore -f /etc/lvm/archive/vg_data_00002-504999937.vg vg_data
vgchange -ay vg_data
13.6 Permanently missing disk¶
If a PV is gone for good (and you have no mirror or RAID):
vgs -o +pv_missing
vgchange -ay --activationmode partial vg_data # activate what can be activated
vgreduce --removemissing vg_data # drop the missing PV; LVs that used it are lost
vgreduce --removemissing --force vg_data # also remove LVs that touched the missing PV
Copy whatever you can out of the partially active LVs first. For RAID/mirror LVs use lvconvert --repair instead (section 10.4).
14. Foreign and external volumes¶
14.1 Use LVM disks from another system (for example, a USB drive)¶
vgscan
# Found volume group "vg_ext" using metadata type lvm2
vgchange -ay vg_ext
# 2 logical volume(s) in volume group "vg_ext" now active
mount /dev/vg_ext/lv_data /mnt/external
When you are done:
umount /mnt/external
vgchange -an vg_ext
vgexport vg_ext # optional, marks it safe to unplug/move
14.2 Duplicate VG names¶
If the foreign disk has a VG with the same name as one on your machine (common with cloned root disks), LVM refuses to activate one of them. Rename by UUID:
vgs -o +vg_uuid
vgrename <vg-uuid> vg_ext_new
14.3 Using a live/rescue environment on the host's own disks¶
vgscan
vgchange -ay
lsblk -f
mount /dev/vg_system/lv_root /mnt
Bind-mount /dev, /proc, /sys for a chroot as needed.
15. Low-level device-mapper tricks¶
dmsetup talks to device-mapper directly. It is a scalpel; prefer the lv* tools where possible.
Suspend and resume I/O¶
Suspending freezes all I/O to the device. Processes that touch it will block until it is resumed. Useful for atomic operations such as storage-array snapshots.
dmsetup info /dev/vg_data/lv_data # State: ACTIVE
dmsetup suspend /dev/vg_data/lv_data
dmsetup info /dev/vg_data/lv_data # State: SUSPENDED
dmsetup resume /dev/vg_data/lv_data
dmsetup info /dev/vg_data/lv_data # State: ACTIVE
For filesystem-level quiescing (flushes dirty data first), fsfreeze -f /data / fsfreeze -u /data is usually better.
Remove a mapping¶
dmsetup remove /dev/vg_data/lv_data
dmsetup remove --force <device_name> # replaces the mapping with an error target; last resort
Prefer lvremove or lvchange -an; use dmsetup remove only for stale mappings that LVM no longer knows about.
Device or resource busy¶
device-mapper: remove ioctl on failed: Device or resource busy
Find what is holding it:
dmsetup info /dev/vg_data/lv_data | grep -i 'open count'
findmnt /dev/mapper/vg_data-lv_data
lsof /dev/mapper/vg_data-lv_data
fuser -vm /data
ls /sys/block/dm-*/holders/ /sys/block/dm-N/holders/ # stacked devices (LUKS, other LVs, multipath)
dmsetup ls --tree
Common culprits: a mounted filesystem, a process with a working directory inside the mount, a LUKS mapping opened on top, a loop device, a swap area, an exported NFS share, a container with a bind mount, or a kernel snapshot/thin dependency.
I/O errors while removing a volume¶
If the underlying disk vanished you may see:
/dev/vg_data/lv_data: read failed after 0 of 4096 at 0: Input/output error
Then the VG has a missing PV. Remove the stale mapping and clean up the metadata:
dmsetup remove --force /dev/mapper/vg_data-lv_data
vgreduce --removemissing --force vg_data
16. Configuration (lvm.conf)¶
Location: /etc/lvm/lvm.conf. View the effective configuration with lvmconfig (lvmconfig --typeconfig diff shows only your changes).
| Setting | Section | Purpose |
|---|---|---|
backup = 1, archive = 1 |
backup |
Keep metadata backups and history. Leave enabled. |
archive_dir, backup_dir |
backup |
Where they are stored. |
issue_discards = 1 |
devices |
Send TRIM/discard to the disk when an LV is removed or reduced. Good for SSD/thin storage; note that it makes accidental removals unrecoverable. |
filter, global_filter |
devices |
Regexes controlling which devices LVM scans or ignores. Use global_filter to exclude devices that would cause loops (for example, VM disk images that contain LVM). |
use_devicesfile = 1 |
devices |
Newer LVM only: restrict scanning to devices listed in /etc/lvm/devices/system.devices. Manage with lvmdevices --adddev /dev/sdb. |
thin_pool_autoextend_threshold/percent |
activation |
Auto-grow thin pools. |
snapshot_autoextend_threshold/percent |
activation |
Auto-grow classic snapshots. |
monitoring = 1 |
activation |
Enable dmeventd monitoring (needed for autoextend and RAID events). |
use_lvmetad |
global |
Removed in modern releases (autoactivation uses udev / lvm-activate). |
After changing filters or on systems that boot from LVM, rebuild the initramfs.
17. Troubleshooting¶
| Symptom | Likely cause | What to do |
|---|---|---|
Device or resource busy on unmount/remove |
Open files, mounts, stacked devices | Section 15: lsof, fuser -vm, dmsetup ls --tree, check holders |
Insufficient free space: N extents needed, but only M available |
VG has no free PE | Add a PV (4.2) or free space by shrinking another LV |
resize2fs: New size smaller than minimum |
Filesystem holds more data than the target | Free up data, or choose a larger target |
resize2fs: Please run 'e2fsck -f' first |
Filesystem not freshly checked | Run e2fsck -f <dev>, then retry |
resize2fs: Invalid new size: 4.5G |
Fractional units unsupported | Use whole units (4G) or M/sectors |
xfs_growfs: not a mount point |
XFS tools need the mount point | Mount it and pass the mount path |
| Trying to shrink XFS | Not supported | Back up, recreate smaller, restore |
LV shows I (invalid) in Attr |
Snapshot ran out of COW space | Remove the snapshot; next time size it larger or enable autoextend |
| Thin pool at 100% | Overcommitted, no autoextend | Extend the pool, fstrim, delete unneeded thin volumes; enable autoextend |
Couldn't find device with uuid ... |
PV missing, not decrypted, or not yet scanned | Open LUKS, pvscan, check cables; see 13.5 / 13.6 |
Volume group "X" not found |
Not scanned or filtered out | vgscan, pvscan --cache, check filter/devices file |
WARNING: Not using device ... for PV ... because it is a duplicate |
Multipath or cloned disks | Configure multipath properly, or use global_filter |
| System boots to emergency shell after a rename | fstab/initramfs/root= still use old names |
Fix the names and rebuild the initramfs |
LV in use: not deactivating |
Still mounted or held open | Unmount, close LUKS, stop the process using it |
Cannot resize ... snapshot exists |
Some operations refuse with snapshots | Remove or merge the snapshot first |
| I/O errors when accessing a removed disk | Missing PV | Section 15 / 13.6 |
General checklist when something looks wrong:
pvs -a; vgs; lvs -a -o +devices
dmsetup ls --tree
journalctl -k -b | grep -Ei 'lvm|device-mapper|dm-'
lvmdiskscan
pvscan --cache && vgscan
18. Best practices¶
- Back up before any shrink, restore, or removal. Snapshots are not backups.
- Leave free space in the VG. Unallocated extents give you room to grow any LV, take snapshots, or run
pvmovein an emergency. Avoid-l 100%FREEon every LV. - Use meaningful names (
vg_prod,lv_pgdata) and avoid hyphens in VG/LV names to sidestep mapper-name doubling. - Prefer
-r(--resizefs) onlvextend/lvreduceso the filesystem and LV are always changed together and in the correct order. - Choose XFS when you will only ever grow; choose ext4 if shrinking is a realistic need.
- Dry-run with
-t/--testand review with-vbefore destructive commands. - Keep metadata backups enabled and copy
/etc/lvm/backupand/etc/lvm/archive(orvgcfgbackupoutput) off the host regularly. - Do not leave classic snapshots running. Delete them after the backup or merge; monitor
Data%. - Monitor thin pools and snapshots (
lvs -o +data_percent) and enabledmeventdautoextend. - Separate failure domains. LVM linear/striped LVs across multiple disks fail if any disk fails. Use RAID (LVM RAID or
mdadm) under or inside LVM for redundancy. - Use UUIDs or
/dev/mapperpaths in fstab, not/dev/dm-N, which can change between boots. - Automate
fstrim(systemctl enable --now fstrim.timer) for SSDs and thin pools. - Document the layout (
lsblk -f,vgdisplay,lvs -a -o +devicesoutput) somewhere off-box before major changes.
19. Cheat sheet¶
Inspect¶
pvs; vgs; lvs # summaries
pvdisplay; vgdisplay; lvdisplay
lvs -a -o +devices # which PV backs each LV
lsblk -f # full device tree with filesystems
dmsetup ls --tree # device-mapper dependency tree
Create¶
pvcreate /dev/sdb1
vgcreate vg_data /dev/sdb1
lvcreate -L 10G -n lv_data vg_data # or -l 100%FREE
mkfs.xfs /dev/vg_data/lv_data
mount /dev/vg_data/lv_data /data
Grow¶
lvextend -r -L +5G /dev/vg_data/lv_data # add 5G and resize fs
lvextend -r -l +100%FREE /dev/vg_data/lv_data # use all free space
vgextend vg_data /dev/sdc # add a disk to the VG
pvresize /dev/sdb # after growing an underlying disk
xfs_growfs /data | resize2fs /dev/vg_data/lv_data # manual fs grow
Shrink (ext4, offline only)¶
umount /data
e2fsck -f /dev/vg_data/lv_data
lvreduce -r -L 5G /dev/vg_data/lv_data
mount /data
Move / remove disks¶
pvmove /dev/sdb # evacuate a PV
vgreduce vg_data /dev/sdb # remove from the VG
pvremove /dev/sdb # wipe the label
Snapshots¶
lvcreate -s -L 5G -n snap vg_data/lv_data # classic
lvcreate -s -n snap vg_data/lv_thin # thin (no size)
lvconvert --merge vg_data/snap # roll back to the snapshot
lvremove vg_data/snap # delete it
Rename / activate / remove¶
lvrename vg_data lv_old lv_new
vgrename vg_old vg_new
lvchange -an|-ay vg_data/lv_data
vgchange -an|-ay vg_data
lvremove vg_data/lv_data && vgremove vg_data && pvremove /dev/sdb1
Recover¶
vgcfgrestore -l vg_data # list history
vgcfgrestore --test -f /etc/lvm/archive/<file>.vg vg_data # dry run
vgcfgrestore -f /etc/lvm/archive/<file>.vg vg_data # restore
vgchange -ay vg_data
External disks¶
cryptsetup luksOpen /dev/sdx1 ext # only if encrypted
vgscan && vgchange -ay
mount /dev/<vg>/<lv> /mnt/external
# done:
umount /mnt/external && vgchange -an <vg> && cryptsetup luksClose ext
Further reading¶
man lvm,man lvmthin,man lvmraid,man lvmcache,man lvmsystemid- Logical Volume Manager (Linux), Wikipedia
- Arch Wiki: LVM
- Red Hat: Configuring and managing logical volumes