⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lvm.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 TXT
字号:
any questions,send email to netxiong@eyou.com

相关文件
	/drivers/md/lvm.c
	/linux/lvm.h

lvm 的使用可以参看我的文档,其中它的设备操作函数集有open,close,ioctl,其中的open函数,只有在设备建立了文件系统以后,并且被mount到一个目录是才调用,平时不使用,只有read,write的函数进行处理。

**********************lvm的扇区分配***********************************
这是一个100M的lv的屏幕劫图。可以看到,一共204800个扇区,但是,有一部分的扇区是隐藏的,应该是一些配置信息存储的地方。一共可用的扇区数是200960个,由840个隐藏扇区,共240k.
lvm -- lvm_blk_open MINOR: 1  VG#: 1  LV#: 0  size: 204800
lv->lv_current_pe[0].pe = 4352
lv->lv_current_pe[1].pe = 12544
lv->lv_current_pe[2].pe = 20736
lv->lv_current_pe[3].pe = 28928
lv->lv_current_pe[4].pe = 37120
lv->lv_current_pe[5].pe = 45312
lv->lv_current_pe[6].pe = 53504
lv->lv_current_pe[7].pe = 61696
lv->lv_current_pe[8].pe = 69888
lv->lv_current_pe[9].pe = 78080
lv->lv_current_pe[10].pe = 86272
lv->lv_current_pe[11].pe = 94464
lv->lv_current_pe[12].pe = 102656
lv->lv_current_pe[13].pe = 110848
lv->lv_current_pe[14].pe = 119040
lv->lv_current_pe[15].pe = 127232
lv->lv_current_pe[16].pe = 135424
lv->lv_current_pe[17].pe = 143616
lv->lv_current_pe[18].pe = 151808
lv->lv_current_pe[19].pe = 160000
lv->lv_current_pe[20].pe = 168192
lv->lv_current_pe[21].pe = 176384
lv->lv_current_pe[22].pe = 184576
lv->lv_current_pe[23].pe = 192768
lv->lv_current_pe[24].pe = 200960
**********************************************************************


*********************LVM的磁盘结构************************************
(1)
PV在磁盘上的结构
每一个PV的前一K字节都保留给PV存储PV本身的一些数据。
紧接着的存储所有所在的vg的信息。
接下来是uuidlist(?)。
接下来是vg中所有的lv的信息。
最后是这个pv中所有pe的磁盘信息。

注意,这里的这些数据的分配基本上都是静态的分配,比如说,系统中最多的lv数目为n,那么
lv_disk_t区域的空间就是n*lv_disk_t这么大。虽然浪费一点,但是处理简单。

|<-------------------------------------whole disk------------------------------------------->|
|<---------------------------------------reseve------------------------------->|<----data--->|
|<--pv_disk_t-->|<--vg_disk_t-->|<--uuidlist-->|<--lv_disk_t-->|<--pe_disk_t-->|
**********************************************************************




************************lvm的内存数据结构之间的关系***************************
vg_t{
	……
	************
	(struct pv_t)
	pv[0]		
	pv[1]
	……
	pv[max_pv]
	************
	(struct lv_t)
	lv[0]
	lv[1]
	……
	lv[max_pv]
	************
	
}


pv_t{
	pe[0]
	pe[1]
	……
	pe[n]-->pe_disk_t{
		   lv_num	这个pe所属的lv号
		   le_num	这个pe在所在的lv中的编号
	        }		
}


lv_t{
	lv_current_pe[0]
	lv_current_pe[1]
	……
	lv_current_pe[n]-->pe_t {
				dev
				pe
				read
				write
			   }
}
******************************************************************************



**************************snap_shot设备和它的源设备的关系**************
snap_shot设备和普通的lvm设备的单位都是lv。如果一个普通的lv和一个snap_shot的lv
相关联了,那么在内核中相应的数据结构中就会有相应的处理。

对于被映射的lv设备,其lv结构中
typedef struct lv_v5 {
	……	
	struct lv_v5 *lv_snapshot_prev;
       	struct lv_v5 *lv_snapshot_next;
	……
}
由以上三个域将所有附属于这个lv的snap_shot类型的lv设备串联起来。当对这个源设备进行写
操作的时候,就会在这些候选的snap_shot的lv中选择一个,将源lv中的数据复制到选定的这个
snap_shot上。


对于每一个snap_shot类型的lv,同样在lv的结构中存在着一个域用于记录它是对应于哪一个源lv
typedef struct lv_v5 {
	……	
	struct lv_v5 *lv_snapshot_org;
	……
}

对于每一个snap_shot盘来说,在lv_t结构中,都有

	lv_block_exception指针数组。
	lv_remap_ptr
	lv_remap_end

	lv_snapshot_hash_table

四个结构,用来存储snap_shot盘中相应的块所对应的源盘数据。其实也就是相当于一个存储池。
每当一个源盘数据要进行snap_shot映射的时候,首先检查lv_remap_ptr的指针是否已经超过了
lv_remap_end的界限,如果没有超过,说明还有一部分的映射可以利用,就从lv_remap_ptr所
指向的地方取下来一个excption。进行一些处理以后(主要是填写源dev,r_sector)等信息,也就是
源盘上的信息。然后将它连接哈希表lv_snapshout_hash_table中,以便以后来进行查询。


一个典型的snap_shot和它的源设备的写过程如下
(1)源盘收到写请求。在snap_shot设备中选择一个作为写出设备。
(2)察看这个snap_shot的lv,如果在lv_snapshot_hash_table中已经存在一个映射。说明原来已经写过了。
(3)返回
(3)如果在lv_snapshot_hash_table中没有发现。说明要进行COW操作
(4)先从lv_block_exception中取出一个exception,如果没有exception,说明snap_shot没有空间了。
(5)取出来以后,将源盘数据的设备号和扇区号都写入到exception中
(6)将这个exception连接到哈希表中。以便以后查找。
(7)lv_remap_ptr加一。进行其它正常的写操作。
***********************************************************************



*****************关于snapshot的一致性的问题*****************************
lvm的snapshot的一致性问题不用过多的考虑。
(1)数据从源盘读出来,
(2)然后复制到snapshot盘,
(3)更新snapshot盘的纪录数据
这三个步骤都是异步的
也就是说,他们的运行不存在交叉问题,从而避免了一致性的问题。
只有在上述三个步骤都完成以后,新的数据才可以被写入到源盘上。
************************************************************************



********************snapshot的组织形式和结构*****************************
(1)
对于是snapshot的lv来说,其基本组织形式和普通的lv没有什么区别,不过,由于需要纪录
源盘的数据,所以它按照下面的方式进行组织。

snapshot盘和其它的块设备不太一样,他是按照chunk_size进行逻辑上的划分的,也就是说,
对于数据从源盘复制到snapshot盘,其数据块的大小是按照snapshot盘上的chunk_size为单位
进行复制的。这个chunk_size和一般块设备意义上的chunk不是很一样,这个chunk只是数据复制的单位。
对于不是snapshot的lv,他们的逻辑块大小是按照blk_size[][],blk_sizesize[][]这样的数组来定义的。
也就是说,上层的文件系统或者其它的设备看到的是以blk_size所标记的块大小的设备。他们的读取单位
也是这两个结构所规定的。也就是说,bh传下来的block_nr就是按照这个单位进行计量的

对于每一个le,一般大小为4M,其内部包含若干个chunks,系统经过计算,可以确定出一个le中
可同时容纳多少个chunks和他们的结构标志lv_COW_table_disk_t,一个lv_COW_table_disk_t对应
一个chunk,所有的lv_COW_table_disk_t结构都安排在le的最前头,所有的数据块都紧接在这些
lv_COW_table_disk_t结构后面。但是,这样计算的话,可能就会产生空洞,也就是必定有一块
chunk不能被填满。这也没有办法。
整个snapshot盘的组织形式如下所示


	 |------------------------------------------|
   |-----|------------------------------|	    |
   |	 |               	       \|/	   \|/
|<-1->|<-1->|……|<-1->|<-1->|……|<----2---->|<----2---->|<----2---->|  … ->|
|<----3---->|……|<----3---->|
|<-----------2-------------->|
|<----------------------------------------4---------------------------------->|

1---lv_COW_table_disk_t结构
2---一个lv_chunksize大小的数据块,用来存放一个数据块,或者存放若干lv_COW_table_disk_t结构
3---这个snapshot所在设备的块,它可以容纳若干个1
4---表示一个pe或者le
系统在进行写lv_COW_table_disk_t的时候,是按照这个结构所在的设备的块大小进行写操作的。
也就是按照3所标示的范围进行写操作。
但是同时,如果进行正常的COW操作的时候,其读写的范围是以2为单位进行的,也就是按照这个
snapshot的设备的逻辑块大小进行读写。



同时对于内存中的lv_block_exception_t结构数组来说,它的数量是snapshot中所有的le的数量
乘上一个le中所能容纳的chunks的数目。所以,lv_block_exception_t得数目和le没有什么必然的
关系。
*************************************************************************













⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -