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

📄 raid5.c.txt

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

相关文件
	

********************守护线程************************
这是raid5的核心态守护线程,他扫描整那些可以被处理的stripe并处理他们。
(1)static void raid5d (void *data)
	 while (!list_empty(&conf->handle_list)) {
                handle_stripe(sh);	//最主要的功能就是处理stripe
                release_stripe(sh);
        }

这是一个内核线程,用来进行奇偶重构,重构到空闲的磁盘上
(2)static void raid5syncd (void *data)
	md_do_sync(mddev,NULL)	//主要调用的是md的操作函数
****************************************************


***********************基本的raid5的操作*************************
(1)static int raid5_run (mddev_t *mddev)	//主要的运行函数,在md中调用
	raid5_conf_t *conf;

	mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL);
	conf = mddev->private
	//设置conf中的一些参数,也就相当于设置private中的参数,包含设置hash表
	//,一些信号量,一些头指针
	……
	conf->thread = md_register_thread(raid5d, conf, name);

	//注册一些必要的内核线程,如raid5syncd
	if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN)))	
		conf->resync_thread = md_register_thread(raid5syncd, 						conf,name);	
		md_wakeup_thread(conf->resync_thread);
	//如果需要同步,就唤醒相应的重构线程进行重构。		

	if (start_recovery)	//如果需要重构
                md_recover_arrays();	//调用重构函数
*****************************************************************


********************request的生成过程*****************************
static int raid5_make_request (mddev_t *mddev, int rw, struct buffer_head * 				bh)
	这是整个raid5系统中最为重要的一个函数
	new_sector = raid5_compute_sector	//计算新的扇区号
	sh = get_active_stripe(conf, new_sector, bh->b_size, read_ahead);	
						//得到活动的扇区
	add_stripe_bh(sh, bh, dd_idx, rw);	//这一步很重要,将bh加入到条
						//纹中去
        handle_stripe(sh);
        release_stripe(sh);	//处理这些扇区
******************************************************************


*******************buffer_head请求如何和stripe条纹关联的***********
static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh,
 			int dd_idx, int rw)
	将数据buffer加入到相应的链表中,sh->bh_read,sh->bh_write等中去。但不会加入到writen队列中去。这一步只是为系统的进一步处理提供方便。

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


**********************扇区的重定位********************************
static unsigned long raid5_compute_sector(unsigned long r_sector, unsigned 
			int raid_disks,
                        unsigned int data_disks, unsigned int * dd_idx,
                        unsigned int * pd_idx, raid5_conf_t *conf)
	这个函数的作用是重新计算扇区的编号。
	chunk_number = r_sector / sectors_per_chunk;
        chunk_offset = r_sector % sectors_per_chunk;//线计算扇区处于那个块
	
	stripe = chunk_number / data_disks;//在计算块属于那个条纹
	
	switch (conf->algorithm) {
		case ALGORITHM_LEFT_SYMMETRIC:
			*pd_idx = data_disks - stripe % raid_disks;
                        *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks;
			//分别计算该扇区所处块在那个以盘上,以及同一个条纹中
			//的校验盘的号码
	new_sector = stripe * sectors_per_chunk + chunk_offset;
	//重新计算扇区号分组以后的扇区号
	
	屏幕洁图
	###########################
	raid5:buffer_size is 1024
	raid5:chunk_size is 32768
	raid5:bh->b_rsector is 4856
	raid5:raid_disks is 3
	raid5:algorithm is 2
	raid5:chunk_number is 75
	raid5:chunk_offset is 56
	raid5:stripe is 37
	raid5:new_sector is 2424
	raid5:*pd_idx is 1
	raid5:*dd_idx is 0

	该阵列的结构图				
			 0   1	 2	盘号
		0	32k,32k,32k
		1	32k,32k,32k
		2	32k,32k,32k
		……		
		37	32k,32k,32k
			dd  pd
   	            new_sector
	###########################
*******************************************************************



**********************条纹的获取和释放******************************
stripe_head是有一定的数量的,每次使用stripe_head要申请,用完后要释放

分配实在函数get_active_stripe中
	wait_event_lock_irq(conf->wait_for_stripe,conf->buffer_size,
                            conf->device_lock);
	如果得不到相应的stripe_head,要在系统上等待


释放是在函数__release_stripe中
	wake_up(&conf->wait_for_stripe);
	唤醒等待的进程
********************************************************************


**************************处理stripe********************************
这是最为重要的一个函数,所有的stripe的处理都在这里完成
static void handle_stripe(struct stripe_head *sh)
	int action[MD_SB_DISKS];//没一个磁盘都有一个行动的指标,也就是		
		//READ,WRITE,READA这些

	clear_bit(STRIPE_HANDLE, &sh->state);//第一件事情就是清除这一位。因为之所以调用这个函数的原因就是由于设置了这一位的原因。

	if (buffer_uptodate(bh) && sh->bh_read[i])
		//如果cache中的数据已经被更新了,并且在bh_read中有队列在等待	
		请求,则可以直接将数据传出来,注意,这里使用了return_ok这个buffer链表,如果在cache中游数据的话,就复制到bh_read中,另外有一点要说明,由于可能有几个请求,就都复制出去,分别复制到每一个请求当中,这些请求由bh中的b_reqnext连结起来,然后从stripe_head中的bh_read中卸载下来(至一点很重要),这些卸载下来的buffer就链接在return_ok后面,注意,所有的盘的读数据都一次连结到return_ok后面的。

	if (buffer_locked(bh)) locked++;
	if (buffer_uptodate(bh)) uptodate++;
        if (sh->bh_read[i]) to_read++;
        if (sh->bh_write[i]) to_write++;
        if (sh->bh_written[i]) written++;
        if (!conf->disks[i].operational) {
                 failed++;
                 failed_num = i;
        }//分别计算磁盘所对应的读写buffer和cache buffer的数量

	if (failed > 1 && to_read+to_write) 
		{……
		}//如果磁盘阵列中错误数量大于2,而且有数据处于读写状态,那么		//进行相应的处理
	

	 if (to_write)	//如果是有数据要写的话
		


	bh = sh->bh_cache[sh->pd_idx];
	if ( written && ( (conf->disks[sh->pd_idx].operational && !buffer_locked(bh) && buffer_uptodate(bh)) || (failed == 1 && failed_num == sh->pd_idx)))
		while (wbh) {
                            wbh2 = wbh->b_reqnext;
                            wbh->b_reqnext = return_ok;
                            return_ok = wbh;
                            wbh = wbh2;
                }
注意这里的处理方法和bh_read完全不同,在bh_read中,使每一个bh都连结到return_ok中的,而这里,只是最后的一个连结到return_ok中,很显然,因为读写往磁盘上写的时候,只用写一次就够了。
********************************************************************


********************读操作的完成函数********************************
static void raid5_end_read_request (struct buffer_head * bh, int uptodate)
	for (i=0 ; i<disks; i++)
                if (bh == sh->bh_cache[i])
                        break;	//先找到相应的读取得数据的buffer_head

	buffers = sh->bh_read[i];
        sh->bh_read[i] = NULL;	//再把上层的读请求的buffer_head取下来。	
	set_bit(BH_Uptodate, &bh->b_state);//设置update位
	raid5_end_buffer_read(buffers, bh);//将从盘中读取得数据送到buffers中
	clear_bit(BH_Lock, &bh->b_state);//清除lock伟,这是bh中的位就是		//!lock,update了,也就是和磁盘中的数据是一致的
	set_bit(STRIPE_HANDLE, &sh->state);//设置条纹的状态为stripe_handle,使得下面的release_stripe函数可以唤醒相应的守护进程来对数据进行处理。
	 __release_stripe(conf, sh);//释放条纹

static inline void raid5_end_buffer_read(struct buffer_head *blist, struct buffer_head *bh)
	while (blist) {
                struct buffer_head *new = blist;
                blist = new->b_reqnext;
                memcpy(new->b_data, bh->b_data, bh->b_size);
                new->b_end_io(new, 1);
        }//将bh中的数据复制到buffers中,并且,完成new的io操作。这一点很重要,	//每一个buffer_head都要完成相应的end_io操作。注意,这里的每一个读请求的buffer的数据都复制成为cache中的数据。
********************************************************************



***************raid5系统中的一次读操作的流程************************
(1)首先,当读请求的buffer_head传导raid5_make_request中后,先经过compute_setctor进行对扇区的重定位,然后通过调用函数get_active_stripe得到相应的扇区所处的条纹,再将这个buffer_head加入到这个条纹中,通过函数add_stripe_bh。
(2)第一次进入handle_stripe函数,此时只有bh_read有数据,所以只会执行包含在条件if (to_read || (syncing && (uptodate+failed < disks)))中的语句。
如果cache中的buffer_head没有枷锁,也没有更新,说明是空的,可以使用,这是对这个buffer_head加锁,并把相应的action[i]设置为READ+1(为以后的判断方便),并且对整个条纹设置STRIPE_HANDLE锁。
(3)在handle_stripe函数的末尾,再对action[i]中的数据进行逐一的处理。如果是读操作的话,则设置bh->b_end_io的函数指针为raid5_end_read_request,设置bh的各种参数,调用generic_make_request进行实际的读操作。
(4)读写完毕之后,数据已经在bh中了,但是,请注意,这是的数据并不是在传入到make_request中的bh中,而是在sh->bh_cache中,也就是说在缓存中存放。并没有真正地传给用户。这是会调用bh->b_end_io,也就是调用raid5_end_read_request。
(5)注意,这是的raid5_end_read_request和函数raid5_make_request中的下一个函数realease_stripe是同步进行的。
(6)再raidt5_end_read_request中,系统会将从cache中得到的数据复制到真正请求的buffer_head中,并完成相应的请求,同时调用release_stripe来释放条纹,在释放条纹的过程中,会唤醒raid5d内核进程,再raid5d中会第二次调用handle_stripe。
(7)在进入handle_stripe中以后,什么也不作,因为所有的东西都已经设置好了,同时cache中的数据也是从磁盘中读的,并且是update and !lock,是最新的数据。所要做的所有的事情就是把stripe的STRIPE_HANDLE位清空。


总结
	总体来看,RAID5系统中的数据传递是分两步的,第一步:当请求的读请求来的时候,首先将他链结到相应的条纹的相应的盘的bh_read队列中进行等待。然后,检查cache中的buffer_head,如果是已经更新的了,和磁盘上的数据一致的话,就直接将数据复制到读请求的buffer_head中,否则的话,就进行第二步:就吧cache中的buffer_head调用generice_make_request,启动普通的硬盘读写程序,将数据读入到cache中去,再返回函数raid5_end_read_request中吧数据从cache的buffer中复制到条纹中的相应的请求队列中去,有几个请求的buffer就都复制成为当前的值。然后,调用他们end_io函数结束请求。
********************************************************************



************************奇偶校验函数*****************************
static void compute_parity(struct stripe_head *sh, int method)
	
*****************************************************************









⌨️ 快捷键说明

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