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

📄 md.c.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 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 + -