📄 md.c.txt
字号:
any questions,send email to netxiong@263.net
相关文件
/md/lvm.c
********************一些基本的数据结构************************
(1)static MD_LIST_HEAD(all_mddevs);//定义了所有的md设备得初始链表
在分配一个新的md设备的时候,这个新设备都要加入到这个链表中alloc_mddev
(2)static MD_LIST_HEAD(all_raid_disks); //所有新检测到的盘都要加入到这个链表 //中
(3)static MD_LIST_HEAD(pending_raid_disks);//所有悬而未决的盘都加入到这里面去
(4)static mdk_personality_t *pers[MAX_PERSONALITY];
//所有的raid系统的调用函数都在这里
(5)static struct { //这个结构主要是用于初始化的时候的数据的保存
char device_set [MAX_MD_DEVS]; //每一个数组项代表一个磁盘阵列
int pers[MAX_MD_DEVS]; //每一个磁盘阵列的pers
int chunk[MAX_MD_DEVS]; //每一个磁盘阵列的条纹大小
kdev_t devices[MAX_MD_DEVS][MD_SB_DISKS];//每一个磁盘阵列中的设备号
} md_setup_args md__initdata; //定义了两个变量
(6)struct {
int set;
int noautodetect;
} raid_setup_args md__initdata;
struct hd_struct md_hd_struct[MAX_MD_DEVS]; //分区的解码表
static int md_blocksizes[MAX_MD_DEVS]; //块大小
static int md_hardsect_sizes[MAX_MD_DEVS]; //扇区大小
static int md_maxreadahead[MAX_MD_DEVS]; //预读缓冲区
static mdk_thread_t *md_recovery_thread;
**************************************************************
*******************通用函数***********************************
(1)static mdk_rdev_t * find_rdev_all (kdev_t dev)
while (tmp != &all_raid_disks) //函数的主要功能就是对于给定的dev号召
if (rdev->dev == dev) //到相应的rdev,也就是磁盘的相应数据
return rdev; //结构
**************************************************************
*********************启动*************************************
md系统的启动分两种,一种是在编译是加入到内核中,当系统启动时进行自动检测,
另一种是以module的形式进行加载,他们的编译开关是ifndef MODULE。
###以下是编译到内核的启动过程
*********************自动检测数据结构和函数*******************
(1)static int detected_devices[128]; //存储已经检测到的设备号
(2)static int dev_cnt; //已经检测到的设备的数量
(1)void md_autodetect_dev (kdev_t dev)
detected_devices[dev_cnt++] = dev;//将设备号存入到已经检测到的数据中
**************************************************************
**********************启动过程********************************
如果md是作为内核的一部分被编译进去的话,那么系统会按下面的顺序将这几个初始化函数执行一遍。
__setup("raid=", raid_setup); //这个函数几乎没什么作用
__setup("md=", md_setup); //初始化md_setup_args
__initcall(md_init); //通用的初始化,如分区、注册等
__initcall(md_run_setup);
(1)static int md__init raid_setup(char *str)
//初始化函数,主要初始化变量raid_setup_args。
if (strncmp(str, "noautodetect", wlen) == 0)//比较输入的字符串参数
raid_setup_args.noautodetect = 1; //设置变量
raid_setup_args.set = 1;
(2)static int md__init md_setup(char *str)
//初始化函数,主要初始化变量md_setup_args。
(3)int md__init md_init (void)
devfs_register_blkdev (MAJOR_NR, "md", &md_fops)//注册md设备
devfs_handle = devfs_mk_dir (NULL, "md", NULL); //产生一个目录节点
for (minor=0; minor < MAX_MD_DEVS; ++minor) //产生md0,md2,…md31 md_hd_struct[minor].de = devfs_register (devfs_handle,
devname, DEVFS_FL_DEFAULT, MAJOR_NR, minor,
S_IFBLK | S_IRUSR | S_IWUSR, &md_fops, NULL);
blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request);
md_gendisk.next = gendisk_head; //可分区设备
md_geninit(); //可分区设备初始化
md_run_setup(autostart_arrays-----md_setup_drive)
autorun_devices
(1)int md__init md_run_setup(void)
if (raid_setup_args.noautodetect)
//不做检测,不使用superblock方式启动,改用md_setup_drive启动
else
autostart_arrays(); //检测磁盘阵列,进行数据初始化。
md_setup_drive(); //
(2)static void autostart_arrays (void)
for (i = 0; i < dev_cnt; i++) { //对每一个检测到的设备
kdev_t dev = detected_devices[i]
md_import_device(dev,1) //将设备加入到相应的队列中
rdev = find_rdev_all(dev) //找到相应的盘的描述
md_list_add(&rdev->pending, &pending_raid_disks);//加入到未知 } //队列
autorun_devices(-1); //
这个函数调用完毕后,所有可用的磁盘设备都在两条链表中,一个是all_raid_disks,一个是pending_raid_disks。提供给以后处理。
(3)static int md_import_device (kdev_t newdev, int on_disk)
if (find_rdev_all(newdev))//如果阵列中已经有这个盘了就返回
return -EEXIST;
rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL//产生一个盘
……//初始化
get_super //看这个磁盘设备是否在使用,如果在使用就丢弃
alloc_disk_sb //分配一个超级块的内存结构
read_disk_sb(rdev)//把这个磁盘设备的超级块从物理磁盘上读出来
md_list_add(&rdev->all, &all_raid_disks);//将该盘加入到磁盘组中
MD_INIT_LIST_HEAD(&rdev->pending); //初始化pending中.调用它的函数有用
(4)static void autorun_devices (kdev_t countdev)
//所有的磁盘都已经连接到all_raid_disk和pending_raid_disks中,
//这个函数的作用就是将所有连接到pending_raid_disks中的磁盘按一定的顺
//序,将有相同uuid的磁盘放到same_array中,如果上述过程成功的话,就运
//行它。
while (pending_raid_disks.next != &pending_raid_disks)
rdev0 = md_list_entry(pending_raid_disks.next//从pending中取 //一个盘作为头一个
ITERATE_RDEV_PENDING(rdev,tmp) {
//遍历pending链表,比较uuid,如果和rdev0一样的话,就 //比较下一个。如果一样的话,加入到一个新的链表 //candidates中
md_list_del(&rdev->pending);
md_list_add(&rdev->pending, &candidates);
}
mddev = alloc_mddev(md_kdev); //分配一个阵列描述符
……将磁盘bind到阵列中去
autorun_array(mddev); //运行这个阵列
}
(5)static void autorun_array (mddev_t *mddev)
err = do_md_run (mddev); //运行这个磁盘阵列
(6)static int do_md_run (mddev_t * mddev)
analyze_sbs(mddev) //检验超级块
mddev->sb->state &= ~(1 << MD_SB_CLEAN);//将整个超级块置为脏。
md_update_sb(mddev); //更新超级块
mddev->pers = pers[pnum]; //设置处理运行函数
err = mddev->pers->run(mddev); //运行相应的raid种类的运行函数,例如 //raid5_run
(7)void md__init md_setup_drive(void) //这个函数用于用户态时的启动
if (mddev_map[minor].mddev) {
printk(".. md%d already autodetected \n", minor);
} //如果已经在autostart_array中启动了,就什么都不作
(8)void md_autodetect_dev (kdev_t dev)
这个函数再fs/partition/mddos.c中被调用,各种设备将被放入 detected_devices[]数据结构中
*****************************************************************
******************超级块的处理函数****************************
分配一个磁盘阵列的超级块
(1)static int alloc_array_sb (mddev_t * mddev)
mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL);//分配sb
分配一个磁盘的超级块
(2)static int alloc_disk_sb (mdk_rdev_t * rdev)
rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL);
(3)static int set_array_info (mddev_t * mddev, mdu_array_info_t *info)
alloc_array_sb(mddev) //为磁盘阵列分配一个超级块
……//对超级块进行各种设置
#这个函数在 md_setup_drive中被调用,用来设置
(4)static int read_disk_sb (mdk_rdev_t * rdev)
从相应的磁盘上读出超级块,并将超级块的数据纪录到rdev中sb相应的位置
(5)static int analyze_sbs (mddev_t * mddev)
if ((sb->state != (1 << MD_SB_CLEAN))
//如果,磁盘的超级块步干净,就进行同步操作。
(6)int md_update_sb(mddev_t * mddev)
if ((++mddev->sb->events_lo)==0)
++mddev->sb->events_hi;//增加event的值。
sync_sbs(mddev);
if (mddev->sb->not_persistent)
return 0; //如果不是persistent型的,就不写磁盘。
write_disk_sb(rdev) //写磁盘。
(7)static int write_disk_sb(mdk_rdev_t * rdev)
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh);
ll_rw_block(WRITE, 1, &bh);//写磁盘。
wait_on_buffer(bh);
brelse(bh);
超级块的更新方法
首先在系统启动的时候,再do_md_run函数中,将超级块置为脏位,
mddev->sb->state &= ~(1 << MD_SB_CLEAN);
md_update_sb(mddev);
只有在系统正常退出的时候,也就是do_md_stop,才会置伟清洁
mddev->sb->state |= 1 << MD_SB_CLEAN;
所以,当系统死机后,重启动后就会同步操作
**************************************************************
*********************md设备的守护进程的一些函数*********************
(1)mdk_thread_t *md_register_thread (void (*run) (void *),
void *data, const char *name)
thread->sem = &sem;
thread->run = run; //设置自身的运行函数
thread->data = data; //数据
thread->name = name;
ret = kernel_thread(md_thread, thread, 0);//运行守护线程md_thread
//注意,kernel_thread的第二个参数是传给前面的线程的参数。
(2)int md_thread(void * arg)
mdk_thread_t *thread = arg; //得到参数
daemonize(); //守护进程?????
thread->tsk = current; //
/********************************************************************/
**************************设备号的转换*******************************
(1)dev_mapping_t mddev_map[MAX_MD_DEVS];
将一个设备号和一个具体的md设备相关联
(2)void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data)
unsigned int minor = MINOR(dev); //得到设备号
mddev_map[minor].mddev = mddev; //设置相应的设备
mddev_map[minor].data = data;
解除一个设备号和一个具体的md设备的关联
(3)void del_mddev_mapping (mddev_t * mddev, kdev_t dev)
mddev_map[minor].mddev = NULL; //上一个函数的逆过程
mddev_map[minor].data = NULL;
这种关联主要在md设备的创建阶段使用,主要的函数是 alloc_mddev (kdev_t dev)
*********************************************************************
**********************md设备的产生和删除**********************
(1)static mddev_t * alloc_mddev (kdev_t dev)
mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL);//分配设备块
MD_INIT_LIST_HEAD(&mddev->all_mddevs);//进行各种初始化
add_mddev_mapping(mddev, dev, 0);//添加设备号的映射
md_list_add(&mddev->all_mddevs, &all_mddevs);//把md设备加到设备链中
(2)static void free_mddev (mddev_t *mddev)
del_mddev_mapping//删除md设备对应的设备号
md_list_del(&mddev->all_mddevs); //从设备链表中删除
**************************************************************
***********************设备的重构*****************************
(1)void md_recover_arrays (void)
md_wakeup_thread(md_recovery_thread); //唤醒重构函数进行重构
(2)int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
**************************************************************
*************************设备的容量大小的计算******************
(1)static unsigned int calc_dev_size
这个函数是计算单个设备,也就是磁盘阵列中的的大小,也就是除去了超级块 的剩余磁盘大小
size = calc_dev_sboffset(dev, mddev, persistent);//计算超级块的偏移
(2)static int device_size_calculation (mddev_t * mddev)
计算整个磁盘阵列的大小,
md_size[mdidx(mddev)] = sb->size * data_disks;
其中sb->size是由calc_dev_size计算得来的。
***************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -