linux LVM Tutorial

宁静
想把家里2块老旧的80G硬盘当作下载盘来使用,但总不能每次下载时查看硬盘剩余空间够不够吧,想着如果可以把这2块硬盘当作一块160G的硬盘来使用就好了。在一番搜索后,发现 LVM 完全可以满足我的需求。

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分层结构

LVM

图中自上而下分别为:

  1. 实际的物理存储介质及其划分的分区和其上的 PV。
  2. 一个或多个 PV 可以用来创建 VG。
  3. 基于 VG 可以创建 LV。只要在 VG 中有可用空间,就可以随心所欲的创建 LV。
  4. 文件系统就是在 LV 上创建的,然后可以在操作系统挂载和访问。

Install LVM

1
:~$ apt-get install lvm2

LVM创建和使用

基本流程

LVM

格式化物理存储介质(The physical media)

物理存储介质,即硬盘、U盘、闪存卡等等。在本篇文章中通指硬盘。
我们使用以下两种工具来格式化硬盘。

  • fdisk:mbr disk
  • gdisk:gpt disk

通过使用fdisk创建磁盘分区。在这里,我们创建3个1G的分区,注意,并不要求分区的大小一致。同样,分区需要修改成LVM类型来使他们可用于LVM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
:~$ fdisk /dev/sdb
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): ## 回车用默认的1
Last cylinder, +cylinders or +size{K,M,G} (1-1044, default 1044): +1G ## 大小
Command (m for help): t ## 改变类型
Selected partition 1
Hex code (type L to list codes): lvm ## LVM 的分区代码,MBR为8E,而GPT为43
## 具体可以输入 L 来查看
Changed system type of partition 1 to 8e (Linux LVM)

重复上面操作创建其他两个分区。当分区创建完成后,我们应该有类似如下的输出:

1
2
3
4
5
:~$ fdisk -l /dev/sdb
Device Boot Start End Blocks Id System
/dev/sdb1 1 132 1060258+ 8e Linux LVM
/dev/sdb2 133 264 1060290 8e Linux LVM
/dev/sdb3 265 396 1060290 8e Linux LVM

PV

pvcreate

pvcreate是用来创建PV的,我们要在刚刚所创建的分区之上创建PV。

1
2
3
:~$ pvcreate /dev/sdb1
:~$ pvcreate /dev/sdb2
:~$ pvcreate /dev/sdb3

pvcreate 其它使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
:~$ pvcreate --help
pvcreate - Initialize physical volume(s) for use by LVM

pvcreate PV ...
[ -f|--force ]
[ -M|--metadatatype lvm2 ]
[ -u|--uuid String ]
[ -Z|--zero y|n ]
[ --dataalignment Size[k|UNIT] ]
[ --dataalignmentoffset Size[k|UNIT] ]
[ --bootloaderareasize Size[m|UNIT] ]
[ --labelsector Number ]
[ --pvmetadatacopies 0|1|2 ]
[ --metadatasize Size[m|UNIT] ]
[ --metadataignore y|n ]
[ --norestorefile ]
[ --setphysicalvolumesize Size[m|UNIT] ]
[ --reportformat basic|json ]
[ --restorefile String ]
[ COMMON_OPTIONS ]
# 在指定UUID分区上创建PV
:~$ pvcreate --uuid xxxx-xxxx-xxxx-xxxx

pvdisplay

使用下列命令检查PV的创建情况。下面截取部分输出。
/dev/sdb2是一个新的1.01 GiB物理卷。

1
2
3
4
5
6
7
8
9
10
11
12
:~$ pvdisplay

--- NEW Physical volume ---
PV Name /dev/sdb2
VG Name
PV Size 1.01 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID jszvzz-ENA2-g5Pd-irhV-T9wi-ZfA3-0xo092

pvs

Display information about physical volumes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
:~$ sudo pvs -a
PV VG Fmt Attr PSize PFree
/dev/bt/bt --- 0 0
/dev/sda10 --- 0 0
/dev/sda2 --- 0 0
/dev/sda5 --- 0 0
/dev/sda6 --- 0 0
/dev/sda7 --- 0 0
/dev/sda8 --- 0 0
/dev/sdb1 --- 0 0
/dev/sdb2 --- 0 0
/dev/sdc1 --- 0 0
/dev/sdd1 bt lvm2 a-- <74.53g <74.53g
/dev/sde1 bt lvm2 a-- 76.33g 6.33g
/dev/sdf1 --- 0 0

# PFree----Unallocated pv size

pvscan

List all physical volumes

1
2
3
4
:~$ sudo pvscan
PV /dev/sde1 VG bt lvm2 [76.33 GiB / 6.33 GiB free]
PV /dev/sdd1 VG bt lvm2 [<74.53 GiB / <74.53 GiB free]
Total: 2 [<150.86 GiB] / in use: 2 [<150.86 GiB] / in no VG: 0 [0 ]

pvmove

Move extents from one physical volume to another

1
2
3
4
5
# Use a specific destination PV when moving physical extents.
:~$ pvmove /dev/sdb1 /dev/sdc1

#Move all physical extents that are used by simple LVs on the specified PV to free physical extents elsewhere in the VG.
:~$ pvmove /dev/sdb1

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
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 3
Metadata Sequence No 1
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 0
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 0 / 0
Free PE / Size 774 / 3.02 GiB
VG UUID bwd2pS-fkAz-lGVZ-qc7C-TaKv-fFUC-IzGNBK

从输出中,我们可以看见VG的使用量/总量。PV给VG提供空间。只要在这个VG中还有可用空间,我们就可以随意创建LV。

vgs

Display information about volume groups.

1
2
3
:~$ vgs -v
VG Attr Ext #PV #LV #SN VSize VFree VG UUID VProfile
volume-group1 wz--n- 4.00m 2 1 0 <3.02G 0g wtiwP6-mocI-M8Jd-6oUw-go3J-FuVQ-tnQqrd

vgrename

Rename a volume group.

1
2
3
4
5
6
7
8
9
:~$ vgrename wtiwP6-mocI-M8Jd-6oUw-go3J-FuVQ-tnQqrd vg1
:~$ vgs -v
VG Attr Ext #PV #LV #SN VSize VFree VG UUID VProfile
vg1 wz--n- 4.00m 2 1 0 <3.02G 0g wtiwP6-mocI-M8Jd-6oUw-go3J-FuVQ-tnQqrd

:~$ vgrename vg1 volume-group1
:~$ vgs -v
VG Attr Ext #PV #LV #SN VSize VFree VG UUID VProfile
volume-group1 wz--n- 4.00m 2 1 0 <3.02G 0g wtiwP6-mocI-M8Jd-6oUw-go3J-FuVQ-tnQqrd

vgextend

Add physical volumes to a volume group.

1
2
# add /dev/sdg1 to bg[bt]
:~$ vgextend bt /dev/sdg1

vgremove

使用下列命令删除VG。

1
:~$ vgremove volume-group1

extend VG size

让我们假设我们的VG ‘volume-group1’已经满了,需要扩大。手上的硬盘(sdb)已经没有其他空闲分区,我们添加了另外一个硬盘(sdc)。

我们将看到如何把sdc的分区添加到VG以扩展。

  1. 检测现在卷组状态
    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
  2. 我们创建一个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!
  3. 然后,我们创建一个PV /dev/sdc1
    1
    :~$ pvcreate /dev/sdc1
  4. 现在,PV已经准备好,我们可以简单地将它增加到已存在的VG ‘volume-group1’上。
    1
    :~$ vgextend volume-group1 /dev/sdc1
  5. 使用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
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 YNQ1aa-QVt1-hEj6-ArJX-I1Q4-y1h1-OFEtlW
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

lvs

1
2
3
4
5
6
7
8
9
10
:~$ lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
movies media -wi-a----- <4.64t
haven200 shares -wi-ao---- 400.00g
public shares -wi------- 200.00g
:~$ lvs -v
LV VG #Seg Attr LSize Maj Min KMaj KMin Pool Origin Data% Meta% Move Cpy%Sync Log Convert LV UUID LProfile
movies media 2 -wi-a----- <4.64t -1 -1 254 1 ebx82O-kgH2-wAzs-9e0F-hqVA-3k0v-Q4TdoM
haven200 shares 1 -wi-ao---- 400.00g -1 -1 254 0 Zi1ufd-pCRi-KdBh-8WRg-epOi-FTuG-jj2O7Q
public shares 1 -wi------- 200.00g -1 -1 -1 -1 2u4lcV-H0O7-W2fF-UgwK-6YVs-lb4O-T9jx7w

lvremove

使用lvremove我们可以删除LV。

1
2
:~$ umount /lvm-mount/
:~$ lvremove /dev/volume-group1/lv1

lvrename

Rename a logical volume

1
2
3
4
5
6
7
8
9
10
11
:~$ lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
movies media -wi-a----- <4.64t
haven200 shares -wi-ao---- 400.00g
public shares -wi------- 200.00g
:~$ lvrename /dev/shares/public software
:~$ lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
movies media -wi-a----- <4.64t
haven200 shares -wi-ao---- 400.00g
software shares -wi------- 200.00g

extend LV size

调整LV大小的功能是LVM最有用的功能。下面,我们将会扩展先前创建的LV ‘lv1’扩大到200MB。

注意,调整LV大小之后,也需要对文件系统调整大小进行匹配。这个额外的步骤各不相同,取决于创建文件系统的类型。在本文中,我们使用’lv1’创建了ext4类型的文件系统,所以这里的操作是针对ext4文件系统的。(ext2/3文件系统也类同)。命令的执行顺序是很重要的。

  1. 卸载掉lv1卷
    1
    :~$ umount /lvm-mount/
  2. 设置卷的大小为200M
    1
    :~$ lvresize -L 200M /dev/volume-group1/lv1
  3. 检查磁盘错误
    1
    :~$ e2fsck -f /dev/volume-group1/lv1
  4. 运行以下命令扩展文件系统更新ext4信息
    1
    :~$ resize2fs /dev/volume-group1/lv1
  5. 检查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

命令的顺序同样重要。并且,下列命令对ext2/3/4文件系统同样有效。

注意减少LV的大小值若小于储存的数据大小,存储在后面的数据会丢失。

  1. 卸载掉LV
    1
    :~$ umount /dev/volume-group1/lv1
  2. 检测磁盘错误。
    1
    :~$ e2fsck -f /dev/volume-group1/lv1
  3. 缩小文件系统,更新ext4信息。
    1
    :~$ resize2fs /dev/volume-group1/lv1 100M
  4. 减少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
  5. 验证调整后的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

LV已经准备好后,我们可以格式化和挂载LV,就像其它ext2/3/4分区一样!

1
2
3
:~$ mkfs.ext4 /dev/volume-group1/lv1
:~$ mkdir /lvm-mount
:~$ mount /dev/volume-group1/lv1 /lvm-mount/

一旦LV挂载,我们就可以到挂载点 /lvm-mount/ 上读写了。要创建和挂载其它的LV,我们重复这个过程。

Expand/Reduce LV or VG

VG上的操作并不会影响lv中的数据

VG

LVM

Expand

  1. 准备分区,设置新分区的System ID为8e
  2. 使用pvcreate构建PV
  3. 使用vgextend将新的PV加入到原有VG中

查看当前系统中原有的PV:

1
2
3
4
[root@localhost ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/sdb1 volume-group1 lvm2 a-- 10.00g 0
/dev/sdc1 volume-group1 lvm2 a-- 10.00g 10.00g

准备分区结果:

1
2
3
[root@localhost ~]# fdisk /dev/sdd
Device Boot Start End Blocks Id System
/dev/sdd1 1 1306 10490413+ 8e Linux LVM

使用pvcreate 命令创建pv:

1
2
[root@localhost ~]# pvcreate /dev/sdd1
Physical volume "/dev/sdd1" successfully created

查看当前系统中的所有PV:

1
2
3
4
5
[root@localhost ~]# pvscan
PV /dev/sdb1 VG volume-group1 lvm2 [10.00 GiB / 0 free]
PV /dev/sdc1 VG volume-group1 lvm2 [10.00 GiB / 10.00 GiB free]
PV /dev/sdd1 volume-group1 lvm2 [10.00 GiB]
Total: 3 [30.00 GiB] / in use: 2 [20.00 GiB] / in no VG: 1 [10.00 GiB]

可见sdb1和sdc1已经加入到了名为volume-group1的VG中,

将名为/dev/sdd1的PV加入到名为volume-group1中:

1
2
[root@localhost ~]# vgextend volume-group1 /dev/sdd1
Volume group "volume-group1" successfully extended

查看VG扩展结果:

1
2
3
4
5
[root@localhost ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/sdb1 volume-group1 lvm2 a-- 10.00g 0
/dev/sdc1 volume-group1 lvm2 a-- 10.00g 10.00g
/dev/sdd1 volume-group1 lvm2 a-- 10.00g 10.00g

Reduce

  1. 确定要移除的PV
  2. 使用pvmove将此PV上的数据转移到其它PV
  3. 使用vgreduce:从卷组中将此PV移除
  4. 使用pvremove删除物理卷,真正删除pv的物理卷

移除名为/dev/sdb1的pv
pvmove /path/to/pv 将PV上的数据转移到其它PV,如果不指定目标PV则转移到同卷组的其它PV上:

1
2
3
4
[root@localhost ~]# pvmove  /dev/sdb1
/dev/sdb1: Moved: 0.2%
/dev/sdb1: Moved: 61.5%
/dev/sdb1: Moved: 100.0%

卷组volume-group1的当前情况:

1
2
3
4
5
[root@localhost ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/sdb1 volume-group1 lvm2 a-- 10.00g 10.00g
/dev/sdc1 volume-group1 lvm2 a-- 10.00g 0
/dev/sdd1 volume-group1 lvm2 a-- 10.00g 10.00g

从卷组volume-group1中移除名为/dev/sdv1的PV:

1
2
[root@localhost ~]# vgreduce  volume-group1 /dev/sdb1
Removed "/dev/sdb1" from volume group "volume-group1"

再次查看卷组volume-group1的情况:

1
2
3
4
5
[root@localhost ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/sdb1 lvm2 a-- 10.00g 10.00g
/dev/sdc1 volume-group1 lvm2 a-- 10.00g 0
/dev/sdd1 volume-group1 lvm2 a-- 10.00g 10.00g

可以看到vgreduce命令只是把/dev/sdb1从卷组volume-group1中移除,但并没有删除名为/dev/sdb1的PV

使用pvremove真正删除名为/dev/sdb1的PV:

1
2
[root@localhost ~]# pvremove  /dev/sdb1
Labels on physical volume "/dev/sdb1" successfully wiped

查看pvremove的操作结果,可以看到名为/dev/sdb1的pv被删除了

1
2
3
4
[root@localhost ~]# pvs
PV VG Fmt Attr PSize PFree
/dev/sdc1 volume-group1 lvm2 a-- 10.00g 0
/dev/sdd1 volume-group1 lvm2 a-- 10.00g 10.00g

注意:pvmove 和 pvremove操作的不同,pvmove是移动数据,而pvremove是删除PV.

LV

LVM

Expand

  1. 确定当前逻辑卷所在的卷组有足够的空闲空间:
  2. 扩展物理边界,即分区的大小
  3. 扩展逻辑边界,即文件系统的大小
  4. 完成文件系统检测

使用命令pvs查看名为volume-group1的信息:

1
2
3
[root@localhost ~]# vgs
VG #PV #LV #SN Attr VSize VFree
volume-group1 2 1 0 wz--n- 20.00g 10.00g

可以看到在volume-group1的卷组中PV数为2 LV数为1 ,VG总大小为20G ,空闲10G

查看lv的大小:

1
2
3
[root@localhost ~]# lvs
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
testLV volume-group1 -wi-ao--- 10.00g

使用命令lvextend [-L|-l] [+] SIZE /path/to/lv扩展物理边界的大小:

size前边有+号和没有加号的区别:

  • 有+号:表示扩展了
  • 无+号: 表示扩展到
  • -L:SIZE 以B ,M ,G 为单位表示扩展的量
  • -l:以物理扩展为单位,表示扩展了多少个pe
1
2
3
[root@localhost ~]# lvextend -L +5G /dev/volume-group1/testLV
Extending logical volume testLV to 15.00 GiB
Logical volume testLV successfully resized

使用lvs查看扩展后的lv的前况:

1
2
3
[root@localhost ~]# lvs
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
testLV volume-group1 -wi-ao--- 15.00g

可以看到扩展成功,但是为什么我们把lv挂载之后使用df -lh查看,却只是看得到10G而不是15G呢?

1
2
3
4
5
[root@localhost ~]# df -lh /backup/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/volume-group1-testLV
9.9G 151M 9.2G 2% /backup
[root@localhost ~]#j ld

是因为我们只扩展了分区的大小,并没有扩展文件系统的大小:

使用命令resize2fs /path/to/device扩展文件系统:

1
2
3
4
5
6
[root@localhost ~]# resize2fs  /dev/volume-group1/testLV
resize2fs 1.41.12 (17-May-2010)
Filesystem at /dev/volume-group1/testLV is mounted on /backup; on-line resizing required
old desc_blocks = 1, new_desc_blocks = 1
Performing an on-line resize of /dev/volume-group1/testLV to 3932160 (4k) blocks.
The filesystem on /dev/volume-group1/testLV is now 3932160 blocks long.

再次使用df -lh查看文区大小,可以看到结果也是15G了

1
2
3
4
[root@localhost ~]# df -lh /backup/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/volume-group1-testLV
15G 153M 14G 2% /backup

文件系统检测:

fsck :可以检测所有的支持的文件系统
e2fsck [-t fs_type][-f][-p] /path/to/device只支持ext系列文件系统

  • -f :强制检测
  • -p:检测过程中如果有问题就修复

注意不能检测当前正处于挂载中的设备

1
2
3
4
5
6
7
8
9
[root@localhost ~]# umount /dev/volume-group1/testLV
[root@localhost ~]# e2fsck -f /dev/volume-group1/testLV
e2fsck 1.41.12 (17-May-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/volume-group1/testLV: 12/983040 files (0.0% non-contiguous), 100865/3932160 blocks

Reduce

  1. 确定要缩减为多大? 前提是:至少能容纳原有的所有数据
  2. 卸载当前正在挂载中的LV并检测文件系统
  3. 缩减逻辑边界resize2fs /path/to/device SIZE
  4. 缩减物理边界lvreduce [-L | -l ] SIZE /path/to/lv
  5. 检测文件系统
  6. 挂载使用

查看当前处于挂载中的设备:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# mount
/dev/sda2 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw,rootcontext="system_u:object_r:tmpfs_t:s0")
/dev/sda1 on /boot type ext4 (rw)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
/dev/mapper/volume-group1-testLV on /backup type ext4 (rw)

卸载当前正在挂载中的LV并检测文件系统

1
2
3
4
5
6
7
8
9
[root@localhost ~]# umount /dev/mapper/volume-group1-testLV
[root@localhost ~]# e2fsck -f /dev/mapper/volume-group1-testLV
e2fsck 1.41.12 (17-May-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/volume-group1-testLV: 12/983040 files (0.0% non-contiguous), 100865/3932160 block

使用resize2fs使用缩减逻辑边界:

1
2
3
4
[root@localhost ~]# resize2fs /dev/volume-group1/testLV  5G
resize2fs 1.41.12 (17-May-2010)
Resizing the filesystem on /dev/volume-group1/testLV to 1310720 (4k) blocks.
The filesystem on /dev/volume-group1/testLV is now 1310720 blocks long.

使用lvs查看LV,发现LV并没有变化,因为我们只缩减了逻辑边界,并没有缩减物理边界

1
2
3
[root@localhost ~]# lvs
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
testLV volume-group1 -wi-a---- 15.00g

使用lvreduce缩减物理边界:

1
2
3
4
5
[root@localhost ~]# lvchange  -a n /dev/volume-group1/testLV
[root@localhost ~]# lvreduce -L 5G /dev/volume-group1/testLV
Reducing logical volume testLV to 5.00 GiB
Logical volume testLV successfully resized
[root@localhost ~]# lvchange -a y /dev/volume-group1/testLV

再次使用lvs发现lv减小了:

1
2
3
[root@localhost ~]# lvs
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
testLV volume-group1 -wi-a---- 5.00g

检测文件系统:

1
2
3
4
5
6
7
8
[root@localhost ~]# e2fsck  -f /dev/volume-group1/testLV
e2fsck 1.41.12 (17-May-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/volume-group1/testLV: 12/327680 files (0.0% non-contiguous), 58463/1310720 blocks

挂载设备并查看大小:

1
2
3
4
5
[root@localhost ~]# mount /dev/volume-group1/testLV  /backup/
[root@localhost ~]# df -lh /backup/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/volume-group1/testLV
5.0G 148M 4.6G 4% /backup

灾难修复

LVM 灾难修复基本思路

灾难的类型

文件系统灾难一般可以分为两类——人为灾难和自然灾难

  • 人为灾难主要是人为操作导致的数据丢失,分区损坏,分区表损坏等等
  • 自然灾难主要是由于事故、意外事件或者自然损耗导致的磁盘坏道,磁盘损坏,相关硬件损坏导致的磁盘位置调整等等。

由于 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
linux-c3k3:~ # pvs
PV VG Fmt Attr PSize PFree
/dev/sdb system lvm2 a- 2.00G 92.00M
/dev/sdc system lvm2 a- 2.00G 0

linux-c3k3:~ # vgs
VG #PV #LV #SN Attr VSize VFree
system 2 1 0 wz--n- 4.00G 92.00M

linux-c3k3:~ # lvs -o +devices
LV VG Attr LSize Origin Snap% Move Log Copy% Devices
alpha system -wi-ao 3.90G /dev/sdc(0)
alpha system -wi-ao 3.90G /dev/sdb(0)

linux-c3k3:~ # mount |grep '/dev/mapper'
/dev/mapper/system-alpha on /alpha type reiserfs (rw,acl,user_xattr)

接着我们将模拟一些错误情况:

情况 1: 文件系统正常,硬盘无物理故障的状况

在这之前我们先确认一些状况,请确认你的 root 分区不在 lvm 的管理范围内,否则一旦 lvm 系统出现故障,整个系统将无法启动,虽然通过光盘 rescure 模式启动可以进行一定的操作,但会造成很多不必要的麻烦。

如果在平时的使用中你已经将 root 分区置于 lvm 管理之下,那么请定期备份 /etc/lve/backup/ 下的文件用以系统恢复.否则即使硬盘没有物理损坏,而只是 lvm 逻辑标签对应错误,你的数据也很有可能救不回来了。当然,即使 root 分区不在 lvm 的管理范围内,定期备份该目录也是一个很好的习惯。

清单 3. 尝试应用存在逻辑卷的 pv

1
2
3
linux-c3k3:~ # pvcreate -ff /dev/sdb
Really INITIALIZE physical volume "/dev/sdb" of volume group "system" [y/n]? y
Can't open /dev/sdb exclusively. Mounted filesystem?

可以看到 pvcreate 拒绝对那些上面有逻辑卷的 pv,如果要执行该操作的话需要把上面的逻辑卷删除,该命令后面将会用到。

现在我们用 dd 命令擦除 sdb 对应 lvm2 的标签但保留分区表(操作有一定风险,请谨慎尝试)

清单 4. 擦除 lvm2 对应标签并查看状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
linux-c3k3:~ # dd if=/dev/zero of=/dev/sdb bs=512 count=1 seek=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 9.8e-05 seconds, 5.2 MB/s

linux-c3k3:~ # pvs --partial
Partial mode. Incomplete volume groups will be activated read-only.
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R'.
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R'.
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R'.
......
PV VG Fmt Attr PSize PFree
/dev/sdc system lvm2 a- 2.00G 0
unknown device system lvm2 a- 2.00G 92.00M

linux-c3k3:~ # vgs --partial
Partial mode. Incomplete volume groups will be activated read-only.
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R'.
......
VG #PV #LV #SN Attr VSize VFree
system 2 1 0 rz-pn- 4.00G 92.00M

linux-c3k3:~ # lvs --partial
Partial mode. Incomplete volume groups will be activated read-only.
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R'.
......
LV VG Attr LSize Origin Snap% Move Log Copy%
alpha system -wi-ao 3.90G

从上面的情况我们不难看出 sdb 已经变成了未知设备,卷组的 metadata 变成只读的了,且是 partial 的状态,但 lv 的情况还是基本正常的。

其实,在这种情况下,还是可以挂载、访问故障的文件系统的,毕竟分区表本身并没有损坏。于是我们首先要做的无疑是备份(最好以只读方式挂载)

清单 5. 以只读方式挂载并备份

1
linux-c3k3:~ # mount -o remount -o ro /alpha
修复

清单 6. 修复操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
* 如果出现 Can't open /dev/sdb exclusively.  Mounted filesystem? 的情况请先 deactive 你的 vg
linux-c3k3: ~ # pvcreate -ff --uuid 7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R \n
--restorefile /etc/lvm/backup/system /dev/sdb
Couldn't find device with uuid '7m0QBR-3kNP-J0fq-GwAq-iv6u-LQkF-yhJh5R '.
Physical volume "/dev/sbd" successfully created
linux-c3k3:~ # pvs
PV VG Fmt Attr PSize PFree
/dev/sdb system lvm2 a- 2.00G 92.00M
/dev/sdc system lvm2 a- 2.00G 0
* 恢复成功,然后我们继续对卷组进行恢复
linux-c3k3: ~ # vgcfgrestore -f /etc/lvm/backup/system system
Restored volume system
* 卷组完成恢复,然后激活后查看
linux-c3k3: ~ #vgchange – ay system
1 logical volume(s) in volume group "system" now active

到此处为止,你会发现,一切正常了,数据也没有任何的损失,但为了保险起见还是应该尝试进行一下文件系统扫描以确保万无一失。

回头看我们前面提到的如果 root 分区在 lvm 管理下的情况,会出现系统无法启动的情况,这时候怎么办呢?

其实也不是无法解决的,先用操作系统盘引导,进入 Rescure 模式,利用你之前备份的 /etc/lve/backup/ 下的文件进行恢复即可,如果你需要先启动起原本的系统以取出备份文件,可以使用 vgreduce – removemissing system 命令去掉丢失标签的物理磁盘再启动,而后利用备份文件执行恢复操作,但是每次正常的 lvm 启动都会更改 /etc/lve/backup/ 下的内容,这也是为什么我们需要对其内容进行备份的原因。

如果很不幸的你没有备份 /etc/lve/backup/ 下的内容,且 root 分区在 lvm 管理下的情况,那么很遗憾,即使你的硬盘没有物理损毁,你的数据也很难救回了,针对这种情况向系统的恢复方法,请参照 磁盘损坏 部分进行操作。

情况 2:PV 的损坏与替换

先看一下系统的情况

清单 7. 检查磁盘及文件系统状况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(none):/test # pvs
PV VG Fmt Attr PSize PFree
/dev/sda2 system lvm2 a- 7.93G 0
/dev/sdb test lvm2 a- 2.00G 0
/dev/sdc test lvm2 a- 2.00G 0
/dev/sdd lvm2 -- 2.00G 2.00G
(none):/test # vgs
VG #PV #LV #SN Attr VSize VFree
system 1 2 0 wz--n- 7.93G 0
test 2 1 0 wz--n- 3.99G 0
(none):/test # lvs
LV VG Attr LSize Origin Snap% Move Log Copy%
root system -wi-ao 7.38G
swap system -wi-ao 560.00M
lv0 test -wi-ao 3.99G
(none):/test # (none):/ # mount /dev/test/lv0 /test/
(none):/ # ls /test
doc.txt
(none):/ # umount /test

我们在 lv0 下存储了一个文件

备份一下 /etc/lvm/backup 的文件

清单 8. 备份 Lvm 信息

1
(none):/etc/lvm/backup # cp * /testback/

我们用 dd 命令把 /dev/sdc 的前 400 个扇区都清零(包括 LVM2 label、meta data、分区表等)

清单 9. 应用 dd 模拟故障状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(none):/ # dd if=/dev/zero of=/dev/sdc bs=512 count=400
400+0 records in
400+0 records out
204800 bytes (205 kB) copied, 0.046619 seconds, 4.4 MB/s
(none):/ # pvs --partial
Partial mode. Incomplete volume groups will be activated read-only.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
PV VG Fmt Attr PSize PFree
/dev/sda2 system lvm2 a- 7.93G 0
/dev/sdb test lvm2 a- 2.00G 0
/dev/sdd lvm2 -- 2.00G 2.00G
unknown device test lvm2 a- 2.00G 0

这种情况下想要完全恢复可能比较困难了,如果无意找回还可能存在的数据,请参照 磁盘损坏 部分进行操作。如想尽可能多的找回数据,请先尝试 mount

清单 10. 尝试 mount 损坏分区

1
2
(none):~ # mount /dev/test/lv0 /test
mount: you must specify the filesystem type

文件系统已经损坏 .

这里我们尝试进行替换,以 sdd 替换 sdc

清单 11. 故障卷的替换

1
2
3
4
5
6
7
8
9
10
11
(none):/ # pvcreate --restorefile /etc/lvm/backup/test \n
--uuid noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO /dev/sdd
Couldn't find device with uuid 'noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO'.
Physical volume "/dev/sdd" successfully created.
(none):/ # pvs -v
Scanning for physical volume names
Wiping cache of LVM-capable devices
PV VG Fmt Attr PSize PFree DevSize PV UUID
/dev/sda2 system lvm2 a- 7.93G 0 7.93G HsErSz-vuAD-rEe1-wE5m-Mnvr-T0Re-EwO7rD
/dev/sdb test lvm2 a- 2.00G 0 2.00G OBb3qb-TW97-hKZ7-vmsr-RZ2v-fzuP-qK3wmN
/dev/sdd test lvm2 a- 2.00G 0 2.00G noOzjf-8bk2-HJhC-92fl-2f6Q-DzNZ-XBqnBO

我们可以看到 sdd 已经替换了 sdc

不过这时候 /etc/lvm/backup 下的文件并不会更新,同时会看到如下的情况

清单 12. 同步 metadata

1
2
3
4
5
6
7
8
9
10
11
(none):/ # vgchange -an test
Volume group test metadata is inconsistent
Volume group for uuid not found:
tcyuXvjcxCN7912qAJlEYzphncdWabTJ21OTTrG6DrMS8dPF5Wlh04GOHyO5ClbY
1 logical volume(s) in volume group "test" now active
* 即报告 vg 的 metadata 不一致
* 重新启动系统
(none):~ # vgchange -an test
0 logical volume(s) in volume group "test" now active
(none):~ # vgchange -ay test
1 logical volume(s) in volume group "test" now active

已不存在该问题,这时候 /etc/lvm/backup 也已经更新了。

之后尝试 mount

清单 13. 重新挂载

1
2
(none):~ # mount /dev/test/lv0 /test
mount: you must specify the filesystem type

我们开始尝试修复文件系统

1
2
3
4
5
reiserfsck /dev/test/lv0 --check
reiserfsck /dev/test/lv0 --rebuild-sb
reiserfsck /dev/test/lv0 --check
reiserfsck /dev/test/lv0 --rebuild-tree
reiserfsck /dev/test/lv0 - – check

命令之后(实际需要执行的情况依据硬盘受损情况可能有所不同)

清单 14. 查看修复后的状态

1
2
3
4
5
(none):~ # mount /dev/test/lv0 /test
(none):~ # cd /test
(none):/test # ls
doc.txt .doc.txt.swp lost+found
(none):/test #

很幸运,我们的文件还在。

磁盘坏道

硬盘长时间的使用,非正常操作或电源管理失误都可能造成磁盘坏道的产生。最典型的症状就是一旦对硬盘的某一部分进行操作,就会出现整个硬盘停止工作,如果操作系统也在该硬盘上,那么系统立即崩溃也就成为了必然。这还不是最可怕的,因为坏道一旦产生就有扩散的可能,每次触及,导致的 crash 都比一次系统非正常掉电造成的伤害更为严重,除了坏道的扩散外还很有可能破坏整块硬盘的动平衡,从而导致整个硬盘不可恢复的物理性损坏。可见,及时发现硬盘坏道,并尽早处理是十分必要的。

LVM 自己本身其实有一套对坏道的处理机制:

  1. 硬盘内部的数据重定位:最底层的重定位,发生在磁盘内部,出现的时候不会通知用户。
  2. 由 LVM 产生的硬件重定位:更高层次的重定位,LVM 将有问题的物理地址 A 上的数据拷贝到物理地址 B,LVM 会继续读地址 A 上的数据,但是硬盘已经将真实的 IO 转向物理地址 B。
  3. 软件重定位:最高层次的重定位,也由 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
2
3
4
5
6
7
8
9
10
* 停用卷组:
Linux:~# vgchange – a n /dev/system
0 logical volume(s) in volume group “system” now active
Linux:~#lvscan
Inactive '/dev/system/test'[1.90 GB] inherit
* 激活卷组:
Linux:~# vgchange – a n /dev/system
1 logical volume(s) in volume group “system” now active
Linux:~#lvscan
ACTIVE '/dev/system/test'[1.90 GB] inherit

磁盘在系统间移动

当磁盘在系统间移动的时候,除了需要停用激活卷组外,还需要执行卷组导出 / 倒入的操作。

清单 16. 导出卷组

1
2
3
4
5
6
* 停用卷组:
Linux:~# vgchange – a n /dev/system
0 logical volume(s) in volume group “system” now active
* 导出卷组
Linux:~# vgexport /dev/system
Volume group “system” successfully exported

此时就可以将磁盘移动到其他系统。

清单 17. 导入并激活卷组

1
2
3
4
5
6
7
8
9
10
* 扫描 PV
Linux:~# pvscan
PV /dev/sdc is in exported VG system [2.00 GB / 96.00 MB free]
Total: 1 [2.00 GB] / in use: 1 [2.00 GB] / in no VG: 0[0 ]
* 导入 VG
Linux:~# vgimport /dev/system
Volume group “system” successfully imported
* 激活卷组
Linux:~# vgchange – a n /dev/system
1 logical volume(s) in volume group “system” now active

到此,卷组就可以恢复正常了。某些卷组可能是跨多块磁盘建立的,而磁盘移动可能只是针对其中的某些磁盘。在这种情况下,可以执行 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
2
3
4
5
6
7
8
9
10
11
12
… ..
Reading all physical volumes. This may take a while
Couldn' t find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy ' .
Couldn' t find all physical volumes for volume group system.
Couldn' t find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy' .
Couldn' t find all physical volumes for volume group system.
Volume group “system” not found
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy' .
Couldn't find all physical volumes for volume group system.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy' .
Couldn't find all physical volumes for volume group system.
.not found -- exiting to /bin/sh

分析输出可知,该问题是磁盘 Disk-B 损坏导致的。究其原因,是 root 分区创建于 LVM 上,当硬盘丢失时,导致 LVM 的发生不一致,导致 root 分区无法被正常读取,进而系统无法正常启动。如果能够恢复 LVM 的一致性,恢复 root 分区的正常读取,就可以恢复 Disk-A 上的数据。

由于此时系统已经不能正常启动,需要用光盘启动进入到紧急恢复模式,用 root 用户登录:

清单 19. 紧急恢复登陆

1
2
Rescue Login: root
Rescue:~#

执行如下命令检查当前状态:

清单 20. 检查磁盘及文件系统状况

1
2
3
4
5
6
7
8
9
10
11
12
13
Rescue:~#lvscan
Reading all physical volumes. This may take a while
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find all physical volumes for volume group system.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find all physical volumes for volume group system.
Volume group “system” not found
Rescue:~#pvscan
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
PV /dev/sda2 VG system lvm2 [7.93 GB / 0 free]
PV unknown VG system lvm2 [2.00 GB / 2.00 GB free]
Total: 2 [9.92 GB] / in use: 2 [9.92 GB] / in no VG: 0 [0 ]

由上面输出可以知道,由于磁盘缺失,系统无法正确识别 system 卷组,但是系统可以正确识别出硬盘,也可以检测到硬盘的缺失。

当系统挂载的是普通文件系统的时候,我们可以通过紧急恢复模式下直接挂载文件系统的方法来进行数据恢复,然而这种方法在 LVM 下行不通,因为所有的逻辑卷都是 LVM 管理的,当卷组不能被正确识别的时候,所有的 LV 也不能被处理。

因此我们要做的就是删除卷组中的缺失物理盘,恢复卷组的一致性。

LVM 提供 vgreduce 来执行从卷组中删除物理卷的操作,并且提供”— removemissing”来删除卷组中所有缺失的物理卷。

清单 21. 删除缺失的物理卷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Rescue:~#vgreduce – removemissing system
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find all physical volumes for volume group system.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find all physical volumes for volume group system.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Couldn't find device with uuid 'wWnmiu-IdIw-K1P6-u10C-A4j1-LQSZ-c08RDy'.
Wrote out consistent volume group system
Rescue:~#vgscan
Reading all physical volumes. This may take a while
Found volume group “system” using metadata type lvm2
Rescue:~#pvscan
PV /dev/sda2 VG system lvm2 [7.93 GB / 0 free]
Total: 1 [7.93 GB] / in use: 1 [7.93 GB] / in no VG: 0 [0 ]

通过删除缺失的硬盘,此时系统已经可以正确识别卷组。但是经历过如此劫难,LV 还需要额外的步骤才能正常工作。执行 lvscan,我们可以发现 root 和 swap 两个逻辑卷都处于 inactive 状态,需要手动执行 lvchange 命令激活,才能使它正常工作。

清单 22. 激活修复后的卷

1
2
3
4
5
6
Rescue:~#lvscan
inactive '/dev/system/root'[7.38 GB] inherit
inactive '/dev/system/swap'[560.00 MB] inherit
Rescue:~#lvchange – ay /dev/system
ACTIVE '/dev/system/root'[7.38 GB] inherit
ACTIVE '/dev/system/swap'[560.00 MB] inherit

到此,大功告成,重起,系统启动,除了损坏的磁盘已经一去不复返以外,系统又恢复正常了。

root 分区磁盘损坏

当 root 分区磁盘发生损坏的时候,唯一的选择只能是另外找一台机器,把没有损坏的磁盘装上去。开机后执行 fdisk – l,输出显示硬盘不包含有效分区表,不能够正确读取。

执行 LVM 的相关检查,可以注意到错误信息与非 root 分区输出的一致。执行非 root 分区磁盘损坏的操作步骤,就可以让卷组恢复正常。将恢复后的卷组挂载后,就可以执行正常读写了。

总结

对于运行在普通 PC 上的 LVM,通常缺少有计划的备份和硬件冗余来应对灾难,因而在灾难发生时,往往需要承受严重的数据损失。本文介绍了 LVM 上可能发生的灾难,结合实例演示了如何进行灾难恢复,在 LVM 遇到灾难时,可以尽可能恢复数据,减少损失。


References:

  • Linux LVM简明教程
  • LVM灾难修复
  • 51cto