📄 lvm.c.txt
字号:
(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 + -