linux LVM Tutorial
Updated in 16/01/2023
- add vgrename / lvrename
LVM简介
LVM 是逻辑盘卷管理(Logical Volume Manager)的简称,最早是 IBM 为 AIX 研发的存储管理机制。
LVM 通过在硬盘和分区之间建立一个逻辑层,可以让多个分区或者物理硬盘作为一个逻辑卷 ( 相当于一个逻辑硬盘 ),提高了磁盘分区管理的灵活性。
1998 年,Heinz Mauelshagen 在 Linux 2.4 内核上提供了 Linux 的 LVM 实现。目前 Linux 2.6 内核支持 LVM2,Redhat 官方网站目前提供最新可下载版本为 2.2.02.77;如果需要最新或者其它版本,请参考网页。
LVM 早期多用于服务器,配合存储硬件的 Raid 技术,提供高可靠性,可灵活配置的磁盘分区管理;普通 PC 由于存储容量有限,很少使用这种技术。
随着单个磁盘容量的不断扩大和硬盘价格的下降,普通 PC 拥有 TB 级的大容量存储空间逐渐普及,也带来对 PC 上存储管理的需要,LVM 无疑是很好的解决方案。
只是普通 PC 用户由于缺少硬件冗余保护,在发生灾难时,通常会发生比较严重的数据损失。好在 LVM 提供了一系列灾难恢复的功能,可以帮助普通 PC 用户尽可能减少损失。
LVM 同样是一个多才多艺的硬盘系统工具。无论在 Linux 或者其他类似的系统,都是非常的好用。传统分区使用固定大小分区,重新调整大小十分麻烦。但是,LVM 可以创建和管理“逻辑”卷,而不是直接使用物理硬盘。可以让管理员弹性的管理逻辑卷的扩大缩小,操作简单,而不损坏已存储的数据。可以随意将新的硬盘添加到 LVM,以直接扩展已经存在的逻辑卷。LVM 并不需要重启就可以让内核知道分区的存在。
LVM基本术语
前面谈到,LVM是在磁盘分区和文件系统之间添加的一个逻辑层,来为文件系统屏蔽下层磁盘分区布局,提供一个抽象的盘卷,在盘卷上建立文件系统。首先我们讨论以下几个LVM术语:
物理存储介质(The physical media) :这里指系统的存储设备:硬盘,如:/dev/hda1、/dev/sda等等,是存储系统最低层的存储单元。PV(physical volume) :物理卷就是指硬盘分区或从逻辑上与磁盘分区具有同样功能的设备(如RAID),是LVM的基本存储逻辑块,但和基本的物理存储介质(如分区、磁盘等)比较,却包含有与LVM相关的管理参数。VG(Volume Group) :LVM卷组类似于非LVM系统中的物理硬盘,其由物理卷组成。可以在卷组上创建一个或多个“LVM分区”(逻辑卷),LVM卷组由一个或多个物理卷组成。LV(logical volume) :LVM的逻辑卷类似于非LVM系统中的硬盘分区,在逻辑卷之上可以建立文件系统(比如/home或者/usr等)。PE(physical extent) :每一个物理卷被划分为称为PE(Physical Extents)的基本单元,具有唯一编号的PE是可以被LVM寻址的最小单元。PE的大小是可配置的,默认为4MB。LE(logical extent) :逻辑卷也被划分为被称为LE(Logical Extents) 的可被寻址的基本单位。在同一个卷组中,LE的大小和PE是相同的,并且一一对应。
简单来说就是:
- PV:是物理的磁盘分区
- VG:LVM中的物理的磁盘分区,也就是PV,必须加入VG,可以将VG理解为一个仓库或者是几个大的硬盘。
- LV:也就是从VG中划分的逻辑分区
LVM分层结构
图中自上而下分别为:
- 实际的物理存储介质及其划分的分区和其上的 PV。
- 一个或多个 PV 可以用来创建 VG。
- 基于 VG 可以创建 LV。只要在 VG 中有可用空间,就可以随心所欲的创建 LV。
- 文件系统就是在 LV 上创建的,然后可以在操作系统挂载和访问。
Install LVM
1 | :~$ apt-get install lvm2 |
LVM创建和使用
基本流程
格式化物理存储介质(The physical media)
物理存储介质,即硬盘、U盘、闪存卡等等。在本篇文章中通指硬盘。
我们使用以下两种工具来格式化硬盘。
- fdisk:mbr disk
- gdisk:gpt disk
通过使用fdisk
创建磁盘分区。在这里,我们创建3个1G的分区,注意,并不要求分区的大小一致。同样,分区需要修改成LVM类型来使他们可用于LVM。
1 | :~$ fdisk /dev/sdb |
重复上面操作创建其他两个分区。当分区创建完成后,我们应该有类似如下的输出:
1 | :~$ fdisk -l /dev/sdb |
PV
pvcreate
pvcreate
是用来创建PV的,我们要在刚刚所创建的分区之上创建PV。
1 | :~$ pvcreate /dev/sdb1 |
pvcreate 其它使用方法
1 | :~$ pvcreate --help |
pvdisplay
使用下列命令检查PV的创建情况。下面截取部分输出。/dev/sdb2
是一个新的1.01 GiB
物理卷。
1 | :~$ pvdisplay |
pvs
Display information about physical volumes
1 | :~$ sudo pvs -a |
pvscan
List all physical volumes
1 | :~$ sudo pvscan |
pvmove
Move extents from one physical volume to another
1 | # Use a specific destination PV when moving physical extents. |
pvremove
使用下列命令可以删除PV。
1 | :~$ pvremove /dev/sdb1 |
VG
vgcreate
下列命令用来创建名为 ‘volume-group1’ 的 VG ,使用/dev/sdb1
, /dev/sdb2
和 /dev/sdb3
创建。
1 | :~$ vgcreate volume-group1 /dev/sdb1 /dev/sdb2 /dev/sdb3 |
vgdisplay
使用下列命令可以来验证VG。
1 | :~$ vgdisplay |
从输出中,我们可以看见VG的使用量/总量。PV给VG提供空间。
vgs
Display information about volume groups.
1 | :~$ vgs -v |
vgrename
Rename a volume group.
1 | :~$ vgrename wtiwP6-mocI-M8Jd-6oUw-go3J-FuVQ-tnQqrd vg1 |
vgextend
Add physical volumes to a volume group.
1 | # add /dev/sdg1 to bg[bt] |
vgremove
使用下列命令删除VG。
1 | :~$ vgremove volume-group1 |
extend VG size
让我们假设我们的VG ‘volume-group1’已经满了,需要扩大。手上的硬盘(sdb)已经没有其他空闲分区,我们添加了另外一个硬盘(sdc)。
我们将看到如何把sdc的分区添加到VG以扩展。
- 检测现在卷组状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21:~$ vgdisplay volume-group1
--- Volume group ---
VG Name volume-group1
System ID
Format lvm2
Metadata Areas 3
Metadata Sequence No 8
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 0
Max PV 0
Cur PV 3
Act PV 3
VG Size 3.02 GiB
PE Size 4.00 MiB
Total PE 774
Alloc PE / Size 25 / 100.00 MiB
Free PE / Size 749 / 2.93 GiB
VG UUID bwd2pS-fkAz-lGVZ-qc7C-TaKv-fFUC-IzGNBK - 我们创建一个2GB分区sdc1,类型为LVM(8e),如教程前所述。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16:~$ fdisk /dev/sdc
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1044, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-1044, default 1044): +2G
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)
Command (m for help): w
The partition table has been altered! - 然后,我们创建一个PV /dev/sdc1
1
:~$ pvcreate /dev/sdc1
- 现在,PV已经准备好,我们可以简单地将它增加到已存在的VG ‘volume-group1’上。
1
:~$ vgextend volume-group1 /dev/sdc1
- 使用vgdisplay来验证(可以看到卷组大小已经增大)。注意,尽管我们使用一个单独的磁盘做示范,其实
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21:~$ vgdisplay
--- Volume group ---
VG Name volume-group1
System ID
Format lvm2
Metadata Areas 4
Metadata Sequence No 9
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 0
Max PV 0
Cur PV 4
Act PV 4
VG Size 5.03 GiB
PE Size 4.00 MiB
Total PE 1287
Alloc PE / Size 25 / 100.00 MiB
Free PE / Size 1262 / 4.93 GiB
VG UUID bwd2pS-fkAz-lGVZ-qc7C-TaKv-fFUC-IzGNBK只要是8e类型的磁盘分区都可以用来扩展VG 。
LV
lvcreate
下列命令创建一个名为’1v1’、大小为100MB的LV。我们使用小分区减少执行时间。这个LV使用之前创建的VG的空间。
1 | :~$ lvcreate -L 100M -n lv1 volume-group1 |
lvdisplay
LV可使用lvdisplay命令查看。
1 | :~$ lvdisplay |
lvs
1 | :~$ lvs |
lvremove
使用lvremove我们可以删除LV。
1 | :~$ umount /lvm-mount/ |
lvrename
Rename a logical volume
1 | :~$ lvs |
extend LV size
调整LV大小的功能是LVM最有用的功能。下面,我们将会扩展先前创建的LV ‘lv1’扩大到200MB。
注意,
- 卸载掉lv1卷
1
:~$ umount /lvm-mount/
- 设置卷的大小为200M
1
:~$ lvresize -L 200M /dev/volume-group1/lv1
- 检查磁盘错误
1
:~$ e2fsck -f /dev/volume-group1/lv1
- 运行以下命令扩展文件系统更新ext4信息
1
:~$ resize2fs /dev/volume-group1/lv1
- 检查LV的状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15:~$ lvdisplay
--- Logical volume ---
LV Name /dev/volume-group1/lv1
VG Name volume-group1
LV UUID 9RtmMY-0RIZ-Dq40-ySjU-vmrj-f1es-7rXBwa
LV Write Access read/write
LV Status available
# open 0
LV Size 200.00 MiB
Current LE 50
Segments 1
Allocation inherit
Read ahead sectors auto
\- currently set to 256
Block device 253:2
现在,这个逻辑卷可以再次挂载,同样这个方法也可用于其他分区。
reduce LV size
注意减少LV的大小值若小于储存的数据大小,存储在后面的数据会丢失。
- 卸载掉LV
1
:~$ umount /dev/volume-group1/lv1
- 检测磁盘错误。
1
:~$ e2fsck -f /dev/volume-group1/lv1
- 缩小文件系统,更新ext4信息。
1
:~$ resize2fs /dev/volume-group1/lv1 100M
- 减少LV大小
1
2
3:~$ lvresize -L 100M /dev/volume-group1/lv1
WARNING: Reducing active logical volume to 100.00 MiB THIS MAY DESTROY YOUR DATA (filesystem etc.) Do you really want to reduce lv1? [y/n]: y
Reducing logical volume lv1 to 100.00 MiB Logical volume lv1 successfully resized - 验证调整后的LV大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15:~$ lvdisplay
--- Logical volume ---
LV Name /dev/volume-group1/lv1
VG Name volume-group1
LV UUID 9RtmMY-0RIZ-Dq40-ySjU-vmrj-f1es-7rXBwa
LV Write Access read/write
LV Status available
# open 0
LV Size 100.00 MiB
Current LE 25
Segments 1
Allocation inherit
Read ahead sectors auto
\- currently set to 256
Block device 253:2
format/mount LVM
1 | :~$ mkfs.ext4 /dev/volume-group1/lv1 |
一旦LV挂载,我们就可以到挂载点 /lvm-mount/ 上读写了。要创建和挂载其它的LV,我们重复这个过程。
Expand/Reduce LV or VG
VG
Expand
- 准备分区,设置新分区的System ID为8e
- 使用pvcreate构建PV
- 使用vgextend将新的PV加入到原有VG中
查看当前系统中原有的PV:
1 | [root@localhost ~]# pvs |
准备分区结果:
1 | [root@localhost ~]# fdisk /dev/sdd |
使用pvcreate 命令创建pv:
1 | [root@localhost ~]# pvcreate /dev/sdd1 |
查看当前系统中的所有PV:
1 | [root@localhost ~]# pvscan |
可见sdb1和sdc1已经加入到了名为volume-group1的VG中,
将名为/dev/sdd1的PV加入到名为volume-group1中:
1 | [root@localhost ~]# vgextend volume-group1 /dev/sdd1 |
查看VG扩展结果:
1 | [root@localhost ~]# pvs |
Reduce
- 确定要移除的PV
- 使用pvmove将此PV上的数据转移到其它PV
- 使用vgreduce:从卷组中将此PV移除
- 使用pvremove删除物理卷,真正删除pv的物理卷
移除名为/dev/sdb1的pvpvmove /path/to/pv
将PV上的数据转移到其它PV,如果不指定目标PV则转移到同卷组的其它PV上:
1 | [root@localhost ~]# pvmove /dev/sdb1 |
卷组volume-group1的当前情况:
1 | [root@localhost ~]# pvs |
从卷组volume-group1中移除名为/dev/sdv1的PV:
1 | [root@localhost ~]# vgreduce volume-group1 /dev/sdb1 |
再次查看卷组volume-group1的情况:
1 | [root@localhost ~]# pvs |
可以看到vgreduce命令只是把/dev/sdb1从卷组volume-group1中移除,但并没有删除名为/dev/sdb1的PV
使用pvremove真正删除名为/dev/sdb1的PV:
1 | [root@localhost ~]# pvremove /dev/sdb1 |
查看pvremove的操作结果,可以看到名为/dev/sdb1的pv被删除了
1 | [root@localhost ~]# pvs |
注意:pvmove 和 pvremove操作的不同,pvmove是移动数据,而pvremove是删除PV.
LV
Expand
- 确定当前逻辑卷所在的卷组有足够的空闲空间:
- 扩展物理边界,即分区的大小
- 扩展逻辑边界,即文件系统的大小
- 完成文件系统检测
使用命令pvs查看名为volume-group1的信息:
1 | [root@localhost ~]# vgs |
可以看到在volume-group1的卷组中PV数为2 LV数为1 ,VG总大小为20G ,空闲10G
查看lv的大小:
1 | [root@localhost ~]# lvs |
使用命令lvextend [-L|-l] [+] SIZE /path/to/lv
扩展物理边界的大小:
size前边有+号和没有加号的区别:
- 有+号:表示扩展了
- 无+号: 表示扩展到
- -L:SIZE 以B ,M ,G 为单位表示扩展的量
- -l:以物理扩展为单位,表示扩展了多少个pe
1 | [root@localhost ~]# lvextend -L +5G /dev/volume-group1/testLV |
使用lvs查看扩展后的lv的前况:
1 | [root@localhost ~]# lvs |
可以看到扩展成功,但是为什么我们把lv挂载之后使用df -lh查看,却只是看得到10G而不是15G呢?
1 | [root@localhost ~]# df -lh /backup/ |
是因为我们只扩展了分区的大小,并没有扩展文件系统的大小:
使用命令resize2fs /path/to/device
扩展文件系统:
1 | [root@localhost ~]# resize2fs /dev/volume-group1/testLV |
再次使用df -lh
查看文区大小,可以看到结果也是15G了
1 | [root@localhost ~]# df -lh /backup/ |
文件系统检测:
fsck :可以检测所有的支持的文件系统e2fsck [-t fs_type][-f][-p] /path/to/device
只支持ext系列文件系统
- -f :强制检测
- -p:检测过程中如果有问题就修复
注意不能检测当前正处于挂载中的设备
1 | [root@localhost ~]# umount /dev/volume-group1/testLV |
Reduce
- 确定要缩减为多大? 前提是:至少能容纳原有的所有数据
- 卸载当前正在挂载中的LV并检测文件系统
- 缩减逻辑边界
resize2fs /path/to/device SIZE
- 缩减物理边界
lvreduce [-L | -l ] SIZE /path/to/lv
- 检测文件系统
- 挂载使用
查看当前处于挂载中的设备:
1 | [root@localhost ~]# mount |
卸载当前正在挂载中的LV并检测文件系统
1 | [root@localhost ~]# umount /dev/mapper/volume-group1-testLV |
使用resize2fs使用缩减逻辑边界:
1 | [root@localhost ~]# resize2fs /dev/volume-group1/testLV 5G |
使用lvs查看LV,发现LV并没有变化,因为我们只缩减了逻辑边界,并没有缩减物理边界
1 | [root@localhost ~]# lvs |
使用lvreduce缩减物理边界:
1 | [root@localhost ~]# lvchange -a n /dev/volume-group1/testLV |
再次使用lvs发现lv减小了:
1 | [root@localhost ~]# lvs |
检测文件系统:
1 | [root@localhost ~]# e2fsck -f /dev/volume-group1/testLV |
挂载设备并查看大小:
1 | [root@localhost ~]# mount /dev/volume-group1/testLV /backup/ |
灾难修复
LVM 灾难修复基本思路
灾难的类型
文件系统灾难一般可以分为两类——
人为灾难 主要是人为操作导致的数据丢失,分区损坏,分区表损坏等等自然灾难 主要是由于事故、意外事件或者自然损耗导致的磁盘坏道,磁盘损坏,相关硬件损坏导致的磁盘位置调整等等。
由于 LVM 和普通文件系统的硬件环境并没有什么区别,所以他们所面对的自然灾难类型也是一致的。
但是对于 LVM 而言,通过虚拟化存储管理带来分区容量动态调整便利的同时,也带来了一些 LVM 特有的人为灾难。
LVM 将所有磁盘创建为物理卷置于卷组中统一管理,然后创建逻辑卷供操作系统调用,这也就导致可能出现卷组损坏,逻辑卷损坏,物理卷损坏等灾难。
修复的策略
对于企业用户而言,通常会制定严格的操作规章制度来和完备的备份策略来抵御人为灾难,还有完整的硬件冗余方案来对抗自然灾难;对于普通用户而言,一般都不具备这种客观条件来防范灾难。一旦发生灾难,我们所要做的是尽量减少灾难的影响,尽可能恢复灾难所造成的数据损失。
对于 LVM 的人为灾难恢复而言,LVM 本身提供了数据备份和配置信息备份的工具,可以充分利用这些工具进行备份,在发生人为灾难导致物理卷错误,逻辑卷错误和卷组错误的时候,利用备份进行恢复,尽可能恢复灾难所导致的数据损失。
由于 LVM 将所有磁盘进行统一管理,所以磁盘损坏会导致整个文件系统不可使用。
因此
LVM 本身提供了一套工具,用户可以通过这套工具解决绝大多数由于硬件故障导致的 LVM 不可用的问题,在自然灾难发生后尽可能恢复 LVM 的可用性。
在某些情况下,由于人为灾难造成 LVM 发生卷组、物理卷或者逻辑卷不一致的情况,进而导致部分逻辑卷、甚至整个卷组无法访问的情况,修复此类问题也可以通过上述工具来进行。
LVM 的灾难恢复
我们将结合具体灾难,演示如何进行 LVM 灾难恢复。为了便于演示,我们假设试验环境如下:
- 基于 X86 架构的 PC,除硬盘外所有硬件均能正常稳定的工作
- PC 上安装了 2 块磁盘 Disk-A 和 Disk-B。
LV(逻辑卷)损坏
硬盘的逻辑损坏的原因往往是多种多样的,可能是误操作,可能是不正常掉电,也可能是病毒甚至汇编语言的 diskkiller 直接造成的,但这些损坏大都并非是不可逆的。
下面我们就将在实验用 PC 上模拟一些常见的错误并进行恢复操作。
先来看看当前的磁盘及文件系统状况:
清单 2. 检查磁盘及文件系统状况
1 | linux-c3k3:~ # pvs |
接着我们将模拟一些错误情况:
情况 1: 文件系统正常,硬盘无物理故障的状况
在这之前我们先确认一些状况,请确认你的 root 分区不在 lvm 的管理范围内,否则一旦 lvm 系统出现故障,整个系统将无法启动,虽然通过光盘 rescure 模式启动可以进行一定的操作,但会造成很多不必要的麻烦。
/etc/lve/backup/
下的文件用以系统恢复.
清单 3. 尝试应用存在逻辑卷的 pv
1 | linux-c3k3:~ # pvcreate -ff /dev/sdb |
可以看到 pvcreate 拒绝对那些上面有逻辑卷的 pv,如果要执行该操作的话需要把上面的逻辑卷删除,该命令后面将会用到。
现在我们用 dd 命令擦除 sdb 对应 lvm2 的标签但保留分区表(操作有一定风险,请谨慎尝试)
清单 4. 擦除 lvm2 对应标签并查看状态
1 | linux-c3k3:~ # dd if=/dev/zero of=/dev/sdb bs=512 count=1 seek=1 |
从上面的情况我们不难看出 sdb 已经变成了未知设备,卷组的 metadata 变成只读的了,且是 partial 的状态,但 lv 的情况还是基本正常的。
其实,在这种情况下,还是可以挂载、访问故障的文件系统的,毕竟分区表本身并没有损坏。于是我们首先要做的无疑是备份(最好以只读方式挂载)
清单 5. 以只读方式挂载并备份
1 | linux-c3k3:~ # mount -o remount -o ro /alpha |
修复
清单 6. 修复操作
1 | * 如果出现 Can't open /dev/sdb exclusively. Mounted filesystem? 的情况请先 deactive 你的 vg |
到此处为止,你会发现,一切正常了,数据也没有任何的损失,但为了保险起见还是应该尝试进行一下文件系统扫描以确保万无一失。
回头看我们前面提到的如果 root 分区在 lvm 管理下的情况,会出现系统无法启动的情况,这时候怎么办呢?
其实也不是无法解决的,先用操作系统盘引导,进入 Rescure 模式,利用你之前备份的 /etc/lve/backup/
下的文件进行恢复即可,如果你需要先启动起原本的系统以取出备份文件,可以使用 vgreduce – removemissing system
命令去掉丢失标签的物理磁盘再启动,而后利用备份文件执行恢复操作,但是每次正常的 lvm 启动都会更改 /etc/lve/backup/
下的内容,这也是为什么我们需要对其内容进行备份的原因。
如果很不幸的你没有备份 /etc/lve/backup/
下的内容,且 root 分区在 lvm 管理下的情况,那么很遗憾,即使你的硬盘没有物理损毁,你的数据也很难救回了,针对这种情况向系统的恢复方法,请参照 磁盘损坏 部分进行操作。
情况 2:PV 的损坏与替换
先看一下系统的情况
清单 7. 检查磁盘及文件系统状况
1 | (none):/test # pvs |
我们在 lv0 下存储了一个文件
备份一下 /etc/lvm/backup
的文件
清单 8. 备份 Lvm 信息
1 | (none):/etc/lvm/backup # cp * /testback/ |
我们用 dd 命令把 /dev/sdc
的前 400 个扇区都清零(包括 LVM2 label、meta data、分区表等)
清单 9. 应用 dd 模拟故障状态
1 | (none):/ # dd if=/dev/zero of=/dev/sdc bs=512 count=400 |
这种情况下想要完全恢复可能比较困难了,如果无意找回还可能存在的数据,请参照 磁盘损坏 部分进行操作。如想尽可能多的找回数据,请先尝试 mount
清单 10. 尝试 mount 损坏分区
1 | (none):~ # mount /dev/test/lv0 /test |
文件系统已经损坏 .
这里我们尝试进行替换,以 sdd 替换 sdc
清单 11. 故障卷的替换
1 | (none):/ # pvcreate --restorefile /etc/lvm/backup/test \n |
我们可以看到 sdd 已经替换了 sdc
不过这时候 /etc/lvm/backup
下的文件并不会更新,同时会看到如下的情况
清单 12. 同步 metadata
1 | (none):/ # vgchange -an test |
已不存在该问题,这时候 /etc/lvm/backup
也已经更新了。
之后尝试 mount
清单 13. 重新挂载
1 | (none):~ # mount /dev/test/lv0 /test |
我们开始尝试修复文件系统
1 | reiserfsck /dev/test/lv0 --check |
命令之后(实际需要执行的情况依据硬盘受损情况可能有所不同)
清单 14. 查看修复后的状态
1 | (none):~ # mount /dev/test/lv0 /test |
很幸运,我们的文件还在。
磁盘坏道
硬盘长时间的使用,非正常操作或电源管理失误都可能造成磁盘坏道的产生。最典型的症状就是一旦对硬盘的某一部分进行操作,就会出现整个硬盘停止工作,如果操作系统也在该硬盘上,那么系统立即崩溃也就成为了必然。这还不是最可怕的,因为坏道一旦产生就有扩散的可能,每次触及,导致的 crash 都比一次系统非正常掉电造成的伤害更为严重,除了坏道的扩散外还很有可能破坏整块硬盘的动平衡,从而导致整个硬盘不可恢复的物理性损坏。可见,及时发现硬盘坏道,并尽早处理是十分必要的。
LVM 自己本身其实有一套对坏道的处理机制:
- 硬盘内部的数据重定位:最底层的重定位,发生在磁盘内部,出现的时候不会通知用户。
- 由 LVM 产生的硬件重定位:更高层次的重定位,LVM 将有问题的物理地址 A 上的数据拷贝到物理地址 B,LVM 会继续读地址 A 上的数据,但是硬盘已经将真实的 IO 转向物理地址 B。
- 软件重定位:最高层次的重定位,也由 LVM 设备产生。LVM 生成一个坏道表,当读物理地址 A 上的数据时,先检查坏道表,如果 A 在坏道表中,就转向物理地址 B。
但以上这些,其实对用户都是透明的,用户可以在创建 lv 时通过 lvcreate – r n
参数关闭这样,系统将不创建坏块重定位区域(BBRA),引导、根和主交换逻辑卷必须使用此参数。当用户觉得 LVM 有问题的时候,首先要做的事情就是备份,尽可能地保存卷组中的数据。卷组发生问题后进行的备份需要和发生问题前进行的备份进行对比。针对存在坏道的情况,fsck 一定要慎用,尤其对于重定位已经无法处理的应尽快将硬盘导出(操作见 3.3 磁盘位置更改部分)LVM 以防坏道扩散,如在导出过程中出现问题,请比照 3.4 磁盘损坏处理。
磁盘位置更改
主板端口损坏、更欢 PC 主板、添加新的设备都可能导致磁盘位置更改的发生。由于 Linux 的主引导记录(MBR)一般记录在第一块磁盘的第一个扇区上,如果第一块磁盘的顺序发生改变,会导致系统无法启动。对于这种情况,只需要调整磁盘顺序就可以解决(只需要保证有 MBR 的磁盘排在第一顺位就可以,不一定是总线的第一个端口)。这里讨论两种比较常见的情况,磁盘在系统内位置更改和磁盘在系统间移动。
磁盘在系统内移动
对于单一卷组的 LVM 文件系统而言,LVM 能够自动识别出磁盘位置的更改。磁盘位置更改后,正常启动系统就可以正常访问了。当系统中存在单独的卷组,或者系统中存在多个卷组是,更改磁盘位置前需要停用卷组,在完成磁盘移动后需要重新激活卷组,执行操作如下:
清单 15. 重新激活卷组
1 | * 停用卷组: |
磁盘在系统间移动
当磁盘在系统间移动的时候,除了需要停用激活卷组外,还需要执行卷组导出 / 倒入的操作。
清单 16. 导出卷组
1 | * 停用卷组: |
此时就可以将磁盘移动到其他系统。
清单 17. 导入并激活卷组
1 | * 扫描 PV |
到此,卷组就可以恢复正常了。某些卷组可能是跨多块磁盘建立的,而磁盘移动可能只是针对其中的某些磁盘。在这种情况下,可以执行 pvmove
命令,把数据移动到指定磁盘上,然后针对指定磁盘执行移动操作。
磁盘损坏
对于普通 PC 而言,多块磁盘的主要目的是扩充存储容量,一般不会采用 RAID 方案来应对磁盘损坏。一旦发生磁盘损坏的情况,用户在承受损坏硬盘上面的所有数据丢失之痛的时候,最不愿看到的就是剩下的磁盘也没法访问的情况。好在 LVM 的开发者充分考虑了这一点,为 LVM 提供了恢复机制。
当 root 分区不是创建在 LVM 上时,情况就如同普通的磁盘损坏一样,只需要更换磁盘,重装系统,然后将原来的 LVM 分区重新挂载就可以,和挂载其它类型的文件系统并没有什么区别,在此不作赘述。当 root 分区创建在 LVM 上时,我们还需要分两种情况来处理—— root 分区所在的磁盘损坏和非 root 分区所在的磁盘损坏。
非 root 分区磁盘损坏
用 Disk-A 和 Disk-B 创建 System VG,root 分区和交换分区存在于 Disk-A 上,Disk-A 和 Disk-B 上创建了多个 LV 用于存放用户数据。当用户在某次重起后,发现系统无法起动,经检查发现 Disk-B 损坏,用户希望能够启动系统,恢复 Disk-A 上的数据。
移除损坏磁盘 Disk-B 后,系统无法启动,系统输出如下:
清单 18. 磁盘损坏后状态
1 | … .. |
分析输出可知,该问题是磁盘 Disk-B 损坏导致的。究其原因,是 root 分区创建于 LVM 上,当硬盘丢失时,导致 LVM 的发生不一致,导致 root 分区无法被正常读取,进而系统无法正常启动。如果能够恢复 LVM 的一致性,恢复 root 分区的正常读取,就可以恢复 Disk-A 上的数据。
由于此时系统已经不能正常启动,需要用光盘启动进入到紧急恢复模式,用 root 用户登录:
清单 19. 紧急恢复登陆
1 | Rescue Login: root |
执行如下命令检查当前状态:
清单 20. 检查磁盘及文件系统状况
1 | Rescue:~#lvscan |
由上面输出可以知道,由于磁盘缺失,系统无法正确识别 system 卷组,但是系统可以正确识别出硬盘,也可以检测到硬盘的缺失。
当系统挂载的是普通文件系统的时候,我们可以通过紧急恢复模式下直接挂载文件系统的方法来进行数据恢复,然而这种方法在 LVM 下行不通,因为所有的逻辑卷都是 LVM 管理的,当卷组不能被正确识别的时候,所有的 LV 也不能被处理。
因此我们要做的就是删除卷组中的缺失物理盘,恢复卷组的一致性。
LVM 提供 vgreduce 来执行从卷组中删除物理卷的操作,并且提供”— removemissing”来删除卷组中所有缺失的物理卷。
清单 21. 删除缺失的物理卷
1 | Rescue:~#vgreduce – removemissing system |
通过删除缺失的硬盘,此时系统已经可以正确识别卷组。但是经历过如此劫难,LV 还需要额外的步骤才能正常工作。执行 lvscan,我们可以发现 root 和 swap 两个逻辑卷都处于 inactive 状态,需要手动执行 lvchange 命令激活,才能使它正常工作。
清单 22. 激活修复后的卷
1 | Rescue:~#lvscan |
到此,大功告成,重起,系统启动,除了损坏的磁盘已经一去不复返以外,系统又恢复正常了。
root 分区磁盘损坏
当 root 分区磁盘发生损坏的时候,唯一的选择只能是另外找一台机器,把没有损坏的磁盘装上去。开机后执行 fdisk – l
,输出显示硬盘不包含有效分区表,不能够正确读取。
执行 LVM 的相关检查,可以注意到错误信息与非 root 分区输出的一致。执行非 root 分区磁盘损坏的操作步骤,就可以让卷组恢复正常。将恢复后的卷组挂载后,就可以执行正常读写了。
总结
对于运行在普通 PC 上的 LVM,通常缺少有计划的备份和硬件冗余来应对灾难,因而在灾难发生时,往往需要承受严重的数据损失。本文介绍了 LVM 上可能发生的灾难,结合实例演示了如何进行灾难恢复,在 LVM 遇到灾难时,可以尽可能恢复数据,减少损失。
References:
- Linux LVM简明教程
- LVM灾难修复
- 51cto