lvm分析之命令

来源:互联网 发布:淘宝网凯乐玩具店 编辑:程序博客网 时间:2024/05/16 23:51

1.1.         pvcreate

一个设备可以被 LVM 使用之前必须先被初始化为一个 PV 。这会在设备的起始位置放置一个标签,俗称“8e”。默认情况下,LVM 标签被放在第2个 512 字节的扇区,第一个扇区可能是启动扇区。 LVM 标签在重启后也会存在,同时在一个集群中都可知。

LVM 标签用于把一个设备识别为一个 PV ,标签包含以下部分:

Ø  对该设备的随机的唯一的标识符(UUID)

Ø  指出块设备的大小(字节)

Ø  记录 LVM 元数据的存储位置

Ø  设备顺序方面的信息

标签后面是 pv 所在卷组的元数据,元数据的存储位置大概是从4k开始到后面1M为止的空间,然后就是可用空间。其在磁盘上面的排列图如图2-1所示。


图2-1 lvm关键数据分布

 

pvcreate主要干的事情是:

1.       根据传入的设备,如果没有uuid则为其生成一个uuid

2.       读取该设备的大小等信息,同时构建用户态pv的内存数据,因为此时设备还没有加入vg,因此将其放入一个临时的orphans_lvm2的卷组中

3.       构建pv的label并写入分区头部的4k空间内,同时预留4k-1M的区间为元数据保存区域,数据存储的区域从1M位置处开始

通过

> dd if=/dev/sdc2 of=/home/fangying/test1bs=4k count=1

> cat test1

可以看到如下信息:

LABELONEd WW  LVM2 001KOeSOU0WPs0Va8aibqokjbcjBx2UKcO0€>ðÖŽÛ LVM2 x[5A%r0N*>ð

其中红色部分为设备的uuid。

观察其io数据可以看到:

[16479.271726] dev name:sdc rw:17bio-sector:524290056 size:4096

[16479.272512] dev name:sdc rw:17bio-sector:524290048 size:4096

[16479.273092] dev name:sdc rw:17bio-sector:524290056 size:4096

[16479.273437] dev name:sdc rw:17bio-sector:524290048 size:4096

       其中524290048代表的是block数目,每个block为512字节,524290048代表的是1M+250G,在测试机上正好是sdc2分区开始的位置,也就是pvcreate修改了分区开始的8k数据。rw:17代表写操作。

 

1.2.         vgcreate

LVM 元数据含有LVM 卷组的详细配置信息。默认情况下,一个卷组的元数据被放置到该卷组中的每个 PV 的一个特殊区域, 元数据很小,且以 ASCII 格式存储。当前 LVM 允许在每个 PV 上存储0,1,2 个元数据的拷贝,默认是1个。一旦配置在每个 PV 上存储多少个元数据的拷贝后,在后续就不能改动了。(也就是一旦 pv 加入 VG ,就不允许再修改了)。第一个拷贝被放在设备的起始位置,在 PV 标签的后面。如果有第2份拷贝,则放在设备的结束位置。假如不小心覆盖了开始位置的数据,可以使用结束位置的第2份来恢复。

在一个 VG 中,PE是整个LVM最小的存储单位,VG就是一个大的PE存储池。 LVM的重点在于可以弹性调整文件系统的容量,实现这个便是通过交换PE来进行数据转换,将原本LV内的PE移到其他设备中以降低LV容量或将其他设备的PE加到此LV中以扩大容量。

PE与VG的相关性如图2-3所示:

图2-3 PE、lv和vg关系图

VG要扩充的话,加上其他的PV即可;LV通过加入VG内没有使用到的PE进行扩充。

vgcreate主要做的事情:

1.       创建vg用户态的元数据结构,生成vg的uuid

2.       遍历加入vg的pv,提取pv的信息记录到vg中,主要是磁盘空间的起始位置等

3.       将vg元数据刷写道pv分区的元数据区域

4.       如果有需要的话元数据会备份到/etc/lvm目录

 

通过测试将sdc1和sdc2加入到vgtest中,看到其磁盘的io数据如下所示:

[20122.273044]dev name:sdc rw:17 bio-sector:2056 size:4096

[20122.286020]dev name:sdc rw:17 bio-sector:524290056 size:4096

[20122.286517]dev name:sdc rw:17 bio-sector:2056 size:4096

[20122.286903]dev name:sdc rw:17 bio-sector:524290056 size:4096

[20122.288834]dev name:sdc rw:17 bio-sector:2056 size:4096

[20122.289242]dev name:sdc rw:17 bio-sector:524290056 size:4096

rw:17代表写操作。2056=2048+8,正好是第一块分区的起始位置后的4k处,sdc1和sdc2都是250G,524290056正好是sdc2分区起始的4k位置,由此看以看到vg的元数据被保存到了pv起始的4k后的元数据区域。

查看sdc1前8k数据,执行:

dd if=/dev/sdc1of=/home/fangying/test11 bs=4k count=2

cat test11

结果如下:

LABELONE9B~LVM2 001YYL299FqlbumVS8Lkh9eqwqiA3KHfADx€>ð®ÖÕ LVM2 x[5A%r0N*>ð_ÖçXvgtest{

id ="2WITMf-U6Hu-0NOl-i0gB-fn6T-D5go-B8OWRW"

seqno = 1

format ="lvm2" # informational

status =["RESIZEABLE", "READ", "WRITE"]

flags = []

extent_size =8192

max_lv = 0

max_pv = 0

metadata_copies= 0

 

physical_volumes{

 

pv0 {

id = "YYL299-Fqlb-umVS-8Lkh-9eqw-qiA3-KHfADx"

device ="/dev/sdc1"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

 

pv1 {

id ="aEwUYo-xsdy-AELb-lAi0-3300-yANe-UyFQrp"

device ="/dev/sdc2"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

}

 

}

# Generated byLVM2 version 2.02.98(2) (2012-10-15): Thu Mar 21 04:24:12 2013

 

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363854252      # Thu Mar 21 04:24:122013

查看sdc1前4k数据:

dd if=/dev/sdc1of=/home/fangying/test12 bs=4k count=1

cat test12

结果:

LABELONE9B~LVM2 001YYL299FqlbumVS8Lkh9eqwqiA3KHfADx€>ð

查看sdc1前4k-8k之间数据:

dd if=/dev/sdc1of=/home/fangying/test13 bs=4k count=1 skip=1

cat test13

结果:

®ÖÕ LVM2x[5A%r0N*>ð_ÖçXvgtest {

id ="2WITMf-U6Hu-0NOl-i0gB-fn6T-D5go-B8OWRW"

seqno = 1

format ="lvm2" # informational

status =["RESIZEABLE", "READ", "WRITE"]

flags = []

extent_size =8192

max_lv = 0

max_pv = 0

metadata_copies= 0

 

physical_volumes{

 

pv0 {

id ="YYL299-Fqlb-umVS-8Lkh-9eqw-qiA3-KHfADx"

device ="/dev/sdc1"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count = 63999

}

 

pv1 {

id ="aEwUYo-xsdy-AELb-lAi0-3300-yANe-UyFQrp"

device ="/dev/sdc2"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

}

 

}

# Generated byLVM2 version 2.02.98(2) (2012-10-15): Thu Mar 21 04:24:12 2013

 

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363854252      # Thu Mar 21 04:24:122013

查看sdc2前8k数据:

dd if=/dev/sdc2of=/home/fangying/test21 bs=4k count=2

cat test21

结果:

LABELONEúÿÆLVM2 001aEwUYoxsdyAELblAi03300yANeUyFQrp€>ð®ÖÕ LVM2 x[5A%r0N*>ð_ÖçXvgtest{

id ="2WITMf-U6Hu-0NOl-i0gB-fn6T-D5go-B8OWRW"

seqno = 1

format ="lvm2" # informational

status =["RESIZEABLE", "READ", "WRITE"]

flags = []

extent_size =8192

max_lv = 0

max_pv = 0

metadata_copies= 0

 

physical_volumes{

 

pv0 {

id ="YYL299-Fqlb-umVS-8Lkh-9eqw-qiA3-KHfADx"

device ="/dev/sdc1"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

 

pv1 {

id ="aEwUYo-xsdy-AELb-lAi0-3300-yANe-UyFQrp"

device ="/dev/sdc2"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

}

 

}

# Generated byLVM2 version 2.02.98(2) (2012-10-15): Thu Mar 21 04:24:12 2013

 

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363854252      # Thu Mar 21 04:24:122013

查看sdc2前4k数据:

dd if=/dev/sdc2of=/home/fangying/test22 bs=4k count=1

cat test22

结果:

LABELONEúÿÆLVM2 001aEwUYoxsdyAELblAi03300yANeUyFQrp€>ð

查看sdc2前4k-8k数据:

dd if=/dev/sdc2of=/home/fangying/test23 bs=4k count=1 skip=1

cat test23

结果:

®ÖÕ LVM2x[5A%r0N*>ð_ÖçXvgtest {

id = "2WITMf-U6Hu-0NOl-i0gB-fn6T-D5go-B8OWRW"

seqno = 1

format ="lvm2" # informational

status =["RESIZEABLE", "READ", "WRITE"]

flags = []

extent_size =8192

max_lv = 0

max_pv = 0

metadata_copies= 0

 

physical_volumes{

 

pv0 {

id ="YYL299-Fqlb-umVS-8Lkh-9eqw-qiA3-KHfADx"

device ="/dev/sdc1"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

 

pv1 {

id ="aEwUYo-xsdy-AELb-lAi0-3300-yANe-UyFQrp"

device ="/dev/sdc2"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

}

 

}

# Generated byLVM2 version 2.02.98(2) (2012-10-15): Thu Mar 21 04:24:12 2013

 

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363854252      # Thu Mar 21 04:24:122013

 

 

 

 

1.3.         lvcreate

逻辑卷分为4种类型 :线性逻辑卷、条带化逻辑卷、镜像卷和快照卷。

1.       线性逻辑卷

线性逻辑卷聚合多个 PV 成为一个逻辑卷,顾名思义,多个物理存储设备可以看成首位相接的。建立一个线性卷时,会按顺序分配某个范围的 PE 给 LV 用。

 

2.       条带化逻辑卷

 条带化逻辑卷和线性逻辑卷的区别在于,线性逻辑卷是将pv顺序连接,只会按顺序连接一次,条带化逻辑卷会将各个pv上的区域划分成更小的stripe,现将所有pv的一个stripe线性连接,然后再将所有pv的第二个stripe连接到其后,如此循环连接。对于大型的连续读写来说,这可以提高性能。通过条带化,I/O 可以以并行的方式进行,在某些情况下,可以达到几乎线性倍数的性能提高。下面是一个分布于三个 PV 上的条带化逻辑卷。


在一个条带化的逻辑卷中,stripe 的大小不可以超过 PE 的大小。

要扩展一个 striped 逻辑卷不像扩展一个 linear 逻辑卷那么简单,需要逻辑卷所在卷组有一定的自由空间以移动数据。例如有一个跨越两个 PV 的 striped LV ,如果想扩展它,必须“至少”增加2个 PV 才能实现条带化逻辑卷的扩展。

3.       镜像逻辑卷

当建立一个镜像逻辑卷时,LVM 确保写进一个底层 pv 的数据会被写进另外一个 pv 。当一个镜像 LV 的一部分失效时(例如一个 PV 失效),镜像 LV 会变成一个普通的线性 LV ,仍然可以被访问。可以用 LVM 建立一个带有多个镜像的逻辑卷。

 一个 LVM 镜像设备把源设备分成一个个区域,大小为 512 KB 。LVM 会维护一个日志,它用于跟踪那个(些)区域是同步。 这个日志可以放在磁盘上,重启也不会丢失,或者可以被读入内存。


4.       快照卷

LVM 的快照功能允许你为一个设备在某个特定的时间点建立一个“虚拟的”的镜像,而不用中断服务。和镜像逻辑卷一样,LVM 的 snapshot 功能并不被集群所支持。在快照建立完成后,如果源设备有改变,则会把被改变的区域做一个拷贝,这样日后可以用于重建设备。因为 snapshot 只拷贝在快照卷建立后被改变的数据区域,所以 snapshot 功能只需要很少的存储空间。例如在一个很少更新的 LV 中,3-5%的空间就足够用于维护快照卷了。

snapshot只是一个虚拟的拷贝,不是实际的介质备份。snapshot 并不能取代普通的备份过程。一旦快照卷满了,就被卸载。这是为了确保源文件系统有足够的空间。你应该定时观察快照卷的使用情况。 快照卷是可以调整大小的。当建立一个快照文件系统时,源文件系统还是可以读写的。假如快照的一个 chunk 被改变,该 chunk 被打上标记,并不再从原来的卷中拷贝。

快照卷有如下用途 :

1、你可以在不用卸载原来的文件系统或者停止应用的情况下对一个 LV 进行备份;

2、你可以对快照卷进行 fsck 再决定原来的文件系统是否需要修复;

3、因为快照卷是可读写的,你可以告诉应用程序对快照卷的数据进行测试,而不用动原来的数据。

1.3.1.       线性卷

首先说明线性卷的实现,先从用户态层面看看其实现。创建一个线性卷,lvm用户态主要会做如下事情(这里不考虑lvmetad模块,该模块后续介绍):

1.       从磁盘元数据区域读取卷组的元数据

2.       从vg的剩余pe中为线性卷分配要求的空间,分配的根据就是之前读取的元数据,但是此时分配发生在用户态

3.       调用ioctl接口先创建一个dm设备

4.       根据之前分配给该dm设备的情况调用ioctl接口更新dm设备的table表,此时lv才算真正的创建起来,有了dm table才能在内核建立io和真正的存储设备的映射关系

5.       更新vg的元数据到pv的元数据区域

6.       备份元数据到/etc/lvm下面

以上几个步骤也是其他类型逻辑卷的主要步骤,只是细节实现上略有不同。

创建一个逻辑卷,然后用dd查看分区的元数据区域,信息如下所示:

LABELONE9B~LVM2 001YYL299FqlbumVS8Lkh9eqwqiA3KHfADx€>ðÒb«< LVM2 x[5A%r0N*>ð˜0¢

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363854252      # Thu Mar 21 04:24:122013

 

vgtest {

id ="2WITMf-U6Hu-0NOl-i0gB-fn6T-D5go-B8OWRW"

seqno = 2

format ="lvm2" # informational

status =["RESIZEABLE", "READ", "WRITE"]

flags = []

extent_size =8192

max_lv = 0

max_pv = 0

metadata_copies= 0

 

physical_volumes{

 

pv0 {

id ="YYL299-Fqlb-umVS-8Lkh-9eqw-qiA3-KHfADx"

device ="/dev/sdc1"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

 

pv1 {

id ="aEwUYo-xsdy-AELb-lAi0-3300-yANe-UyFQrp"

device ="/dev/sdc2"

 

status =["ALLOCATABLE"]

flags = []

dev_size =524288000

pe_start = 2048

pe_count =63999

}

}

 

logical_volumes{

 

lv1 {

id ="0bANxh-Ht9S-3V8s-YwAN-D4Lz-O1Zq-ft62ma"

status =["READ", "WRITE", "VISIBLE"]

flags = []

creation_host ="gulala"

creation_time =1363857801

segment_count = 1

 

segment1 {

start_extent = 0

extent_count =1280

 

type ="striped"

stripe_count =1        # linear

 

stripes = [

"pv0",0

]

}

}

}

}

# Generated byLVM2 version 2.02.98(2) (2012-10-15): Thu Mar 21 05:23:21 2013

 

contents ="Text Format Volume Group"

version = 1

 

description =""

 

creation_host ="gulala"        # Linux gulala3.2.28 #2 SMP Wed Mar 20 22:42:34 EDT 2013 x86_64

creation_time =1363857801      # Thu Mar 21 05:23:212013

上面红色部分就是lv的元数据了,从右下角的时间也可以看出来和vg的时间是不同的。

       以下说明用户态是如何创建这个线性的逻辑卷的。

> ls -l/dev/mapper

crw------T 1root root 10, 236 Mar 20 22:49 control

lrwxrwxrwx 1root root       7 Mar 21 05:23 vgtest-lv1-> ../dm-0

该目录下有个字符设备control。

> cat/proc/devices |grep misc

10 misc

> cat/proc/misc |grep device-mapper

236device-mapper

lvm首先会创建一个主设备号10次设备号236的虚拟设备,也就是/dev/mapper/control设备,这个设备就是内核dm设备驱动的控制接口。

字符设备的操作都通过字符设备驱动完成,内核的该control的字符设备驱动就是内核miscdevice设备,可以看到其fileoperation接口为_ctl_fops。可以看到其实现了ioctl接口,追踪其实现,其ioctl接口如下所示。

以上接口就是内核实际操纵dm驱动的入口,lvm通过ioctl接口进行设备的创建和管理。创建线性逻辑卷最后会依次调用dev_createtable_load接口。

dev_create会构建device设备、构建设备队列,重要的是初始化io处理函数,io请求到达块层后会调用此时初始化的io处理函数dm_request。table_load则根据创建的dm设备类型建立dm table以及dm目标设备(target),这里会调用target驱动的ctr接口初始化目标设备。线性逻辑卷对应的dm目标设备为linear target。


linear_map会将访问线性逻辑卷的io映射到逻辑卷所在的磁盘物理设备上去,并调用该物理设备的驱动完成io操作。

1.3.2.       条带化卷

其创建过程和线性卷类似,只是其对应的dm目标设备为stripped,其target驱动为


1.3.3.       镜像卷

创建一个镜像卷lv2,查看/dev/mapper/

> ls -l/dev/mapper/

total 0

crw------T 1root root 10, 236 Mar 20 22:49 control

lrwxrwxrwx 1root root       7 Mar 21 22:41 vgtest-lv2-> ../dm-4

lrwxrwxrwx 1root root       7 Mar 21 22:41vgtest-lv2_mimage_0 -> ../dm-2

lrwxrwxrwx 1root root       7 Mar 21 22:41vgtest-lv2_mimage_1 -> ../dm-3

lrwxrwxrwx 1root root       7 Mar 21 22:41vgtest-lv2_mlog -> ../dm-1

总共有四个和lv2相关的逻辑卷,查看分区的元数据:

lv2 {

id ="IPynpd-GHtq-MScH-eCE1-vzqi-ans6-dNdh9i"

status =["READ", "WRITE", "VISIBLE"]

flags = []

creation_host ="gulala"

creation_time =1363920086

segment_count =1

 

segment1 {

start_extent =0

extent_count =1280

 

type ="mirror"

mirror_count =2

mirror_log ="lv2_mlog"

region_size =1024

 

mirrors = [

"lv2_mimage_0",0,

"lv2_mimage_1",0

]

}

}

镜像卷对应的是内核的mirror target,其设备的组织结构和target类型如下图所示:


       lv2_mimage_0和mimage_1相当于两个线性卷,mirror会将io同时映射到这两个卷上,理论上这两个卷位于不同的pv之上。

 

1.3.4.       快照卷

详细阐述下快照卷的实现,其他卷都是相通的。详细的实现方式见第4章。

创建一个lv1的快照卷,查看/dev/mapper/

> ls -l/dev/mapper/

total 0

crw------T 1root root 10, 236 Mar 20 22:49 control

lrwxrwxrwx 1root root       7 Mar 22 02:57 vgtest-lv1-> ../dm-0

lrwxrwxrwx 1root root       7 Mar 22 02:57vgtest-lv1-real -> ../dm-2

lrwxrwxrwx 1root root       7 Mar 22 02:57vgtest-snap_lv1 -> ../dm-1

lrwxrwxrwx 1root root       7 Mar 22 02:57vgtest-snap_lv1-cow -> ../dm-3

快照卷对应的是内核的snapshot target和origin target,其设备的组织结构和target类型如下图所示:


0 0