Chinaunix首页 | 论坛 | 博客
  • 博客访问: 92386
  • 博文数量: 26
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 345
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-10 15:51
文章分类

全部博文(26)

文章存档

2011年(1)

2009年(25)

我的朋友

分类: LINUX

2009-08-14 09:17:09

同步的大流程是先读,后写。所以是分两个阶段,sync_request完成第一个阶段,sync_request_write完成第二个阶段。第一个阶段由MD发起,第二个阶段由守护进程发起。

sync_request函数在MD进行同步操作时调用,作用是对设备上指定的块(或者说条带)进行数据同步。入参go_faster指示是否应该更快速进行同步。该函数完成如下工作:

1.      如果同步缓存的mempool没有设置,则此时创建。

2.      如果同步位置不在磁阵内,可能已经完成同步,或者同步出错了。结束同步过程。

3.      如果没有指定bitmap,或者磁阵没有必要进行同步(对于RAID1而言,只有一个磁盘正常工作时设置了mddev->recovery_cp = MaxSector),或者bitmapbitmap_start_sync)认为无需同步,则设置该段数据跳过,返回。

4.      如果当前设备请求队列忙于处理其他非同步类的访问,或者同步的速度已经比较快了,就稍微延时等待一下。

5.      在磁阵上设置障碍,保证磁阵的同步操作不受其他操作打扰。(该障碍在同步结束后end_sync_write中调用put_buf清除)

6.      申请raid-bio,将其状态设置为同步状态。

7.      对于磁阵中可用的磁盘,如果磁盘不为为In_sync状态,则就是同步过程写入的对象,否则就是同步过程中读的目标。如果没有读目标或者写目标,说明磁阵没有必要同步操作,返回。

8.      构建raid-bio中每个biobi_io_vec,将缓存页申请并添加到数组中。直到数组满或者达到一个同步操作要求的数据长度。

9.      如果是用户发起的同步(通过sysfs写入“repair”),则对所有读对象都发起读请求;如果不是,则只发起一个可读的磁盘的读就可以了。

 

同步读操作结束后,调用end_sync_read,如果读成功,该函数设置raid-bio的状态为update态。如果raid-bio中所有读都完成了,则调用reschedule_retryraid-bio插入到磁阵的retry队列中(队列头为confretry_list,队列元素为raid-bioretry_list),唤醒守护进程。

 

在守护进程中,如果发现磁阵的retry队列不为空,则取出raid-bio,如果该bio为同步状态,说明是同步产生的bio,调用sync_request_write进行处理。

 

sync_request_write函数中,完成如下操作:

1.      如果同步是用户发起的。

a)       前面对所有可以读的对象都发出了读请求,而且也已经读完成了。只要其中一个读成功,则raid-bio的状态会被设置为Update,如果此时raid-bio仍然不为update,说明所有的读都失败了,此时设置所有读的盘为故障,并且结束同步过程,返回。

b)       找到读成功的第一个盘,并且其与从其他盘读的数据比较,如果发现有的盘和第一个读成功的盘数据不同,则将这些盘也列为写入对象,将读成功的第一个盘的数据拷贝到这些盘的对应bio中,继续下面的处理(其实是下面的3)。

2.      如果读失败,则进行恢复尝试,具体是这样的:尝试通过同步访问接口sync_page_io从所有可能的磁盘读出数据块;如果读成功,则对这个同步操作的读失败的磁盘,尝试进行一次写,进行一次读(都使用同步访问接口),如果都成功,则说明错误已经被纠正,否则将读失败的盘打入死牢。

3.      最后,将所有需要写的盘上的同步bio进行提交。设置bio结束操作为end_sync_write,返回。

4.      那么,读的数据要写入,应该由读的缓存区拷贝到写的缓存区中,在用户发起的同步中,我们看到是在1.a中执行的,但对于非用户发起的同步而言,这个操作是什么时候完成的呢?这个答案要在r1buf_pool_alloc函数中找,还记得函数sync_request的第一步创建的mempool吗?在

r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO);

这个语句中调用,mempoll会调用r1buf_pool_alloc进行实际的内存分配,具体可以去google一下mempool

这个函数在分配raid-bio的缓存区时,除分配了其中的bio数组外,还分配了bio中的bvec页,对于用户发起的同步操作,是每个bio都分配了RESYNC_PAGES个页;对于非用户发起的同步操作,则是分配了RESYNC_PAGES个页,所有的biobvec都指向它们。这就是说,对于非用户发起的同步操作,读和写的缓存区是同一个,所以不需要单独的拷贝操作。

 

最后,同步写操作完成,调用end_sync_write函数,清除磁阵障碍,释放raid-bio缓存区,唤醒障碍上等待的任务。如果写出错,设置磁盘错误,并且调用bitmap_end_sync将本次同步操作的所有条带对应的bitmap设置为需要进行同步(Needed_mask)操作,下次同步时会尝试恢复这个写错误。

阅读(1458) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~