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

📄 lvm.c.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 TXT
📖 第 1 页 / 共 2 页
字号:
any questions,send email to netxiong@263.net

相关文件:
	/linux/lvm.h
	/driver/md/lvm-snap.c

*************************基本数据结构*************************/
(1):static struct gendisk lvm_gendisk	//可分区设备

(2):vg_t *vg[ABS_MAX_VG]		//所有的VG都在放在这个数组中


**************************************************************/


**********************从block的minor映射为VG和LV的号************
typedef struct {
        int vg_number;
        int lv_number;
} vg_lv_map_t;
static vg_lv_map_t vg_lv_map[ABS_MAX_LV];

****************************************************************



************************lvm的初始化过程*************************
(1)
int lvm_init(void)
	devfs_register_chrdev(LVM_CHAR_MAJOR,lvm_name, &lvm_chr_fops) < 0)	//注册处理函数集
	devfs_register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops)	//注册处理函数集

	/*
	 * 生成callback结构的池结构,主要避免资源短缺对系统性能的影响
	 */
	lvm_callback_mempool = mempool_create(NR_LVM_CALLBACK,
					      lvm_callback_alloc,
					      lvm_callback_free, NULL);
	lvm_init_fs();			//注册devfs等结构
	lvm_init_vars();		//注册一些公用变量	
	lvm_geninit(&lvm_gendisk);	//注册geninit结构,为上层系统所需的设备块大小等信息

	add_gendisk(&lvm_gendisk);
	
	/*
	 * 注册bh处理含数接口
	 */
	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);


(2)
static void __init lvm_init_vars(void)
	loadtime = CURRENT_TIME;	//设置装载时间
	lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;	//设置锁
	……							//其它初始化
	for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL;		//初始化vg数组为空

	for (v = 0; v < ABS_MAX_LV; v++) {	
		vg_lv_map[v].vg_number = ABS_MAX_VG;
		vg_lv_map[v].lv_number = -1;
	}


(3)
static void __init lvm_geninit(struct gendisk *lvm_gdisk)
	for (i = 0; i < MAX_LV; i++) {			//对于每一个lv
		lvm_gendisk.part[i].start_sect = -1;	
		lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0;
		lvm_blocksizes[i] = BLOCK_SIZE;		//块设备的大小都为指定的BLOCK_SIZE。
	}

	blk_size[MAJOR_NR] = lvm_size;			//设置块大小
	blksize_size[MAJOR_NR] = lvm_blocksizes;	//设置块大小
	hardsect_size[MAJOR_NR] = lvm_hardsectsizes;	//设置扇区大小

****************************************************************



*********************proc接口***********************************
(1)int lvm_proc_read_lv_info(char *page, char **start, off_t off,
				int count, int *eof, void *data)
	lv_t *lv = data;	
	打印出相应的lv的各种信息,例如下面的信息,其中lv是1GB
	name:         /dev/lvmtest/lv1	#lv->lv_name
	size:         2097152		#lv->lv_size
	access:       3			#lv->lv_access
	status:       1			#lv->lv_status
	number:       0			#lv->lv_number
	open:         1			#lv->lv_open
	allocation:   0			#lv->lv_allocation
	device:       58:00		#MAJOR(lv->lv_dev), MINOR(lv->lv_dev)


(2)int lvm_proc_read_pv_info(char *page, char **start, off_t off,
                          int count, int *eof, void *data) 
	pv_t *pv = data	
	打印相应的pv的各种信息。例如下面的信息,其中pv是15.53GB
	name:         /dev/hda7		#pv->pv_name
	size:         32563692		#pv->pv_size
	status:       1			#pv->pv_status
	number:       1			#pv->pv_number
	allocatable:  2			#pv->pv_allocatable
	LV current:   1			#pv->lv_cur
	PE size:      4096		#pv->pe_size / 2
	PE total:     3975		#pv->pe_total
	PE allocated: 256		#pv->pe_allocated
	device:       03:07		#MAJOR(pv->pv_dev), MINOR(pv->pv_dev)
	uuid:         72IZRt-XG85-AelI-4OTk-v60a-osK8-aoHA5M

****************************************************************


************************映射函数*************************************
(1)
这个函数是整个lvm系统中最为重要的一个函数。首先要声明的一点是,在这个remap的过程中,计量单位都以扇区为单位。
static int lvm_map(struct buffer_head *bh, int rw)	
	ulong size = bh->b_size >> 9;	//将bh的大小转换为扇区的大小
        ulong rsector_tmp = bh->b_blocknr * size;//这个bh所处的扇区号
	
	############################
	这样计算出来的rsector_tmp应该和bh->b_rsector的数值相同
	以下是屏幕洁图
	xwhack,bh->b_size is 1024
	xwhack,bh->b_blocknr is 1
	xwhack,bh->b_rsector is 2
	xwhack,vg_this->pe_size is 8192
	############################

	if (rsector_tmp + size > lv->lv_size)	//明显开始扇区号+这个bh的扇区						//大小应该比总的扇区上届小
		报错
	
	if (线性划分) {
		/*
		 * 计算这个扇区属于哪一个pe结构,注意这里的pe_size也是按照扇区		
		 * 来进行计量的,如4M,则pe_size = 8192
		 */
                index = rsector_tmp / vg_this->pe_size;	
                pe_start = lv->lv_current_pe[index].pe;		//得到这个bh所在块的pe的起始扇区号
		rsector_map = lv->lv_current_pe[index].pe +
				(rsector_org % vg_this->pe_size);//得到重新计算过后的扇区号。
		rdev_map = lv->lv_current_pe[index].dev;
	################################
	xwhack,bh->b_size is 1024
	xwhack,bh->b_blocknr is 252
	xwhack,bh->b_rsector is 504
	xwhack,bh->b_rdev's major is 58
	xwhack,bh->b_rdev's minor is 1
	xwhack,vg_this->pe_size is 8192
	//rsector = 252 * 1024>>9 = 252 * 2 = 504	
	lvm map: lvm - lvm_map minor:1  *rdev: 58:01  *rsector: 504  size:2
	lvm map: lv_current_pe[0].pe: 4352  rdev: 09:00  rsector:4856
	//rsector = lv_current_pe[504 /8192] + 504 % 8192 = 4352 + 504 = 4856
	################################
	
	} else {		//否则就是条纹化划分
		
	}	

	/*
	 * 如果要进行写操作的设备正在进行move操作,就要延迟它的进行
	 */
	if (rw == WRITE || rw == WRITEA) {
		if(_defer_extent(bh, rw, rdev_map,
				 rsector_map, vg_this->pe_size)) {

			up_read(&lv->lv_lock);
			return 0;
		}
		lv->lv_current_pe[index].writes++;	/* statistic */
	} else
		lv->lv_current_pe[index].reads++;	/* statistic */

	
	if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)))	//如果不是snap_shot或者它的源
		goto out;					//就可以直接返回

	if (lv->lv_access & LV_SNAPSHOT) {			//如果时snap_shot的写
		lvm_snapshot_remap_block(&rdev_map, &rsector_map, pe_start, lv) //重新计算
	} else if (rw == WRITE || rw == WRITEA) {		//如果是snap_shot的源并且是写请求
		lv_t *snap;

		for (snap = lv->lv_snapshot_next; snap;
		     snap = snap->lv_snapshot_next) {
			if (!(snap->lv_status & LV_ACTIVE))	//如果snap_shot的lv不是活动的
				continue;			//继续寻找
			_remap_snapshot(rdev_map, rsector_map,pe_start, snap, vg_this);//重新映射
		}
 	}
	
out:
	/*
	 * bh相关的快照操作已经完成,可以将这个bh按照一般bh进行处理了
	 */
	bh->b_rdev = rdev_map;			//设置dev
	bh->b_rsector = rsector_map;		//设置扇区号
	ret = lvm_push_callback(lv, rw, bh);	//
	up_read(&lv->lv_lock);
	return ret;

	……	//错误处理



(2)
static int lvm_push_callback(lv_t *lv, int rw, struct buffer_head *bh)	
	callback = mempool_alloc(lvm_callback_mempool, GFP_NOIO);	//分配一个callback结构

	callback->lv = lv;		//保存lv
	callback->bh_orig = bh;		//保存bh	

	nbh = &callback->bh_io;		
	
	……	//用bh的信息填充nbh	

	nbh->b_end_io	  = lvm_bh_callback;
	nbh->b_private	  = callback;

	down_read(&lv->lv_io_sem);
	generic_make_request(rw, nbh);	//将nbh写出道设备上
	
	return 0;			//返回0,告知系统不必再将bh提交给系统


(3)
static void lvm_bh_callback(struct buffer_head *bh, int uptodate)
	callback = bh->b_private;
	lv = callback->lv;
	obh = callback->bh_orig;
	
	mempool_free(callback, lvm_callback_mempool);	//释放callback结构
	if (obh->b_end_io)
		obh->b_end_io(obh, uptodate);		//同时将源bh释放



(4)
static inline void _remap_snapshot(kdev_t rdev, ulong rsector,
				ulong pe_start, lv_t *lv, vg_t *vg) 
	/*
	 * 检查一下是否参数指定的块已经在snap_shot中了	
	 */
	r = lvm_snapshot_remap_block(&rdev, &rsector, pe_start, lv);

	if (!r)	//如果还没有在snap_shot中有映射,就进入if结构
		__remap_snapshot(rdev, rsector, pe_start, lv, vg);	//重新进行定位和计算

⌨️ 快捷键说明

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