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

📄 lvm.c.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 TXT
📖 第 1 页 / 共 2 页
字号:


(5)
static void __remap_snapshot(kdev_t rdev, ulong rsector,
			     ulong pe_start, lv_t *lv, vg_t *vg)
	if (!lvm_snapshot_remap_block(&rdev, &rsector, pe_start, lv) &&
	    !lvm_snapshot_COW(rdev, rsector, pe_start, rsector, vg, lv))
		lvm_write_COW_table_block(vg, lv);

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



***************************Volume Group的生成**************************
(1)
static int lvm_do_vg_create(void *arg, int minor)
	vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)	//生成一个VG的结构
	copy_from_user(vg_ptr, arg, sizeof(vg_t)	//从参数中把用户态的VG信息复制到生成的VG中

	if (minor == -1) minor = vg_ptr->vg_number;	//使用用户提供的minor号

	/*
	 * 检查给定的minor号上的设备是否为空,如果不为空。说明这个minor号已经被占用了
	 * 就要返回错误。
	 */
	if (vg[VG_CHR(minor)] != NULL) {
		P_IOCTL("lvm_do_vg_create ERROR: VG %d in use\n", minor);
		kfree(vg_ptr);
  	     	return -EPERM;
	}
	
	……
	vg_ptr->vg_status &= ~VG_ACTIVE;		//设置VG的一些域
	vg_ptr->pe_allocated = 0;			//初始化pe_allocated为0

	if (vg_ptr->pv_max > ABS_MAX_PV)		//如果最大的pv_max大于系统的规定
		……					//报错
	if (vg_ptr->lv_max > ABS_MAX_LV) 		//如果最大的lv_max大于系统的规定
		……					//报错
	
	lvm_fs_create_vg(vg_ptr);			//生成devfs
	
	vg[VG_CHR(minor)] = vg_ptr;			//将minor所标志的这个VG放到vg数组中
	
	for (p = 0; p < vg_ptr->pv_max; p++) {		//按照pv_max的指定生成相应数量的pv
		pv_t *pvp;	
		if ((pvp = vg_ptr->pv[p]) != NULL) {	//如果指定的pv位置没有pv就不做了
			ret = lvm_do_pv_create(pvp, vg_ptr, p);	//否则就生成一个pv
			if ( ret != 0) {			//如果生成错误
				lvm_do_vg_remove(minor);	//把整个系统删除
				return ret;
			}
		}
	}

	size = vg_ptr->lv_max * sizeof(lv_t *);
	if ((snap_lv_ptr = vmalloc ( size)) == NULL) {	
		lvm_do_vg_remove(minor);
		return -EFAULT;
	}
	memset(snap_lv_ptr, 0, size);

	/*
	 * 按照从用户态复制到lv结构中的数据,生成lv。
	 * 这里要注意,复制到lv[x]数组中的数据是一个指针。所以还是用户态的指针
	 * 要使用其中的数据还要使用copy_form_user。
	 */
	for (l = 0; l < vg_ptr->lv_max; l++) {
		lv_t *lvp;
		if ((lvp = vg_ptr->lv[l]) != NULL) {		//如果相应的位置上不为空。
			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {  //就复制到lv临时变量中
				……
				lvm_do_vg_remove(minor);
				return -EFAULT;
			}
			if ( lv.lv_access & LV_SNAPSHOT) {	//如果lv是snap_shot
				snap_lv_ptr[ls] = lvp;	//将用户态的指针保存到snap_shot的lv结构中
				vg_ptr->lv[l] = NULL;	//相应的LV结构为空
				ls++;			//计数加一
				continue;		//先不创建lv设备
			}
			
			/*
			 * 程序首先清除vg中相应位置的指针,因为这个时候
			 * 这里还是用户态的指针。清除以后,就可以使用lvm_do_lv_create
			 * 来生成新的lv结构,填充到这个位置上。
			 */
			vg_ptr->lv[l] = NULL;			//清除相应的LV结构(???)
			if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { //生成LV结构
				lvm_do_vg_remove(minor);	//如果失败,放弃创建
				return -EFAULT;
			}
		}
	}

	for (l = 0; l < ls; l++) {				//对于snap_shot的lv
		lv_t *lvp = snap_lv_ptr[l];
		if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {	//从用户态指针复制这个结构
			lvm_do_vg_remove(minor);
			return -EFAULT;
		}
		if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {	//创建lv设备
			lvm_do_vg_remove(minor);
			return -EFAULT;
		}
	}
	……		//其它常规处理


(2)
static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)

	pep = lv->lv_current_pe		//得到用户态传来的pe的信息指针数组	

	/*
	 * 检查整个vg中是否有和要生成的lv重名的lv。如果有报错
	 */
	for (l = 0; l < vg_ptr->lv_cur; l++) {
		if (vg_ptr->lv[l] != NULL &&
		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
			return -EEXIST;
	}	

	/*
	 * 下面的这一大堆代码其实就是在vg组中寻找一个空闲的lv的位置
	 */
	l_new = -1;
	if (vg_ptr->lv[lv->lv_number] == NULL)
		l_new = lv->lv_number;
	else {
		for (l = 0; l < vg_ptr->lv_max; l++) {
			if (vg_ptr->lv[l] == NULL)
				if (l_new == -1) l_new = l;
		}
	}
	if (l_new == -1) return -EPERM;
	else             l = l_new;

	lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)	//分配一个lv的结构
	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));	//将数据复制到这个新的结构中
	……						//进行各种初始化
	
	vg_ptr->lv[l] = lv_ptr;		//在上面寻找到的空闲的lv位置上插入这个新生成的lv
	
	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {	//如果不是snap_shot
		size = lv_ptr->lv_allocated_le * sizeof(pe_t);	//计算pe所占用的空间
		lv_ptr->lv_current_pe = vmalloc(size))	//为每一个pe分配一个pe	
		copy_from_user(lv_ptr->lv_current_pe, pep, size)
		
		/*
		 * 下面的代码其实就是将这些分配出去的PE所在的PV中的pe_allocated计数增加
		 * 同时增加VG中总的pe_allocated计数
		 */
		for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
			vg_ptr->pe_allocated++;
			for (p = 0; p < vg_ptr->pv_cur; p++) {
				if (vg_ptr->pv[p]->pv_dev ==
				    lv_ptr->lv_current_pe[le].dev)
					vg_ptr->pv[p]->pe_allocated++;
			}
		}
	} else {			//如果LV是一个snap_shot的话	
		/*
		 * 首先得到这个snap_shot的源lv
		 */
		lv_ptr->lv_snapshot_org = vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
		if (lv_ptr->lv_snapshot_org != NULL) {		//如果这个源不是空
			size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
			……		//进行错误检测
			lv_ptr->lv_block_exception = vmalloc(size)	//分配execption
			copy_from_user(lv_ptr->lv_block_exception, lvbe, size)	//复制用户数据
		
			lv_ptr = lv_ptr->lv_snapshot_org;	//得到源lv的地址
			lv_ptr->lv_snapshot_minor = 0;
			lv_ptr->lv_snapshot_org = lv_ptr;	//将他的snap_shot置为自己???
			
			lv_ptr = vg_ptr->lv[l];			//又变为snap_shot这个lv,神经!!!
			……					//设置这个snap_shot

			/*
			 * 如果lv是一个snapshot的话,他的lv_allocated_snapshot_le和
			 * lv_allocated_le是不一样的。一个是snapshot的本身所拥有的le的数量
			 * 而另一个是借用源lv的le的数量	
			 */
			lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le;
			lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;

			ret = lvm_snapshot_alloc(lv_ptr)	//设置snap_shot的iobuf
			
			……					//???
			lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)//???

			init_waitqueue_head(&lv_ptr->lv_snapshot_wait);	//???
		} else {					//如果源是空,报错
			kfree(vg_ptr->lv[l]);
			vg_ptr->lv[l] = NULL;
			return -EINVAL;
		}


	/*
	 * 以下的几行程序用来设置geninit_disk结构。
	 */	
	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;			//开始扇区是0
	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;	//有多少扇区
	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;			//大小,按k计算

	vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number;
	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number;
	……						//对一些公共变量进行设置
	vg_ptr->lv_cur++;				//当前的vg中的lv数目加一

	if (lv_ptr->lv_access & LV_SNAPSHOT) {		//如果是snap_shot的话
		lv_t *org = lv_ptr->lv_snapshot_org, *last;
		fsync_dev_lockfs(org->lv_dev);		//将源lv中的数据同步到设备上
		
		/* 
		 * 将这个snap_shot的lv连接到源lv的snap_shot队列中
		 */
		for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next);
		
			lv_ptr->lv_snapshot_prev = last;
			last->lv_snapshot_next = lv_ptr;
	}
		
	if(activate)					//如果标记为活动的lv
		lv_ptr->lv_status |= LV_ACTIVE;		//标记这个lv是活动的
	else
		lv_ptr->lv_status &= ~LV_ACTIVE;	//反之为不活动的

	if ( lv_ptr->lv_access & LV_WRITE)		//如果lv_access的写位置位了
		set_device_ro(lv_ptr->lv_dev, 0);	//设置可写
	else
		set_device_ro(lv_ptr->lv_dev, 1);	//否则只读

	lv_ptr->vg = vg_ptr;				//设置这个lv的vg指针指向当前vg

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






⌨️ 快捷键说明

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