MD中bitmap源代码分析--设置流程

1. 同步/异步刷磁盘

  Bitmap文件写磁盘分同步和异步两种:

  1) 同步置位:当盘阵有写请求时,对应的bitmap文件相应bit被置位,bitmap内存页被设置了DIRTY标志。而在下发写请求给磁盘之前,必须保证bitmap文件下刷完成后才向磁盘发送写请求。这种情况需要等待写bitmap磁盘文件完成,因此是同步的。(由bitmap_unplug()完成)

  之所以写bit要在写chunk数据之前就同步刷磁盘,因为如果写请求先下发了,而写bit在这之后刷磁盘的话,当写磁盘过程中发生故障,比如掉电,此时数据是不一致的,而磁盘的bitmap文件中由于还没来得及记录写bit在内存中置位的结果,导致之后会错误的认为数据是一致的。在通过bitmap_statrwrite()和bitmap_unplug()两步实现了bitmap中的bit批量下刷的情况下,实现了同步置位,是为了保证正确性。

  2) 异步清零:当下发磁盘的写请求完成后,需要将bitmap内存页中相应的bit清零,然后把bitmap文件下刷。而这个过程不需要等待写bitmap磁盘文件完成,因此是异步的。(由bitmap_daemon_work()完成)

  而清bit可以在写请求完成之后异步来做,因为就算是写失败,也不会影响正确性,只是会带来一次额外的同步。异步清零的机制好处在于,在还未清零或者内存位图清0但没有刷到磁盘的时候,又有对该页的写请求到来,就只用增加bmc计数器或者只是把内存位图置位,而不用再写到外存的位图文件中,从而减少了一次写外存位图的io。另外,异步清零也实现了bitmap中的bit批量下刷。

2. 写流程Bitmap的设置

  在Raid1的写流程中,bitmap的设置操作主要在bitmap_statrwrite()、bitmap_unplug()、bitmap_endwrite()。

  bitmap_statrwrite(),该函数在raid1中的make_request()中调用。在提交每个盘的bio到pending_bio_list之前调用该函数。

  bitmap_statrwrite()的主要工作:

    1. 是对写请求的chunk对应bit置1;
    2. 设置对应bit的bitmap_attr为BITMAP_PAGE_DIRTY;
    3. 用*bmc来做尚未完成的写请求计数。

  具体流程如下图所示:

  1. 如果是延迟写,则增加延迟写计数;
  2. 由于一个写操作涉及的数据段可能对应多个数据块(bitmap-chunk指定的大小),对于每个这样的数据块:

    a) 获取该数据块的bitmap内存结构,即bp数组指向的内容;

    b) 如果该数据块对应的counter达到最大值,说明盘阵上该数据区进行的写访问已经太多,盘阵等待太久,此时需要启动设备的队列处理;

    c) 如果该数据块上没有正在进行的写操作(*bmc为0),设置filemap对应的bit,设置该bitmap页对应的bitmap_attr属性为BITMAP_PAGE_DIRTY,计数该页上有多少脏的chunk,将该数据块对应的计数*bmc直接设置为2;

    d) 如果该数据块的内存位图已经置位,则将*bmc直接是设置为2;

    e) 对应的bmc计数累加。

  bitmap_unplug()的主要工作,遍历bitmap的所有filemap页:

  1. 如果页属性为BITMAP_PAGE_DIRTY,则将该页写入磁盘,同时清除BITMAP_PAGE_DIRTY。等待写入结束后返回。
  2. 如果页属性为BITMAP_PAGE_NEEDWRITE,则将该页写入磁盘,同时清除BITMAP_PAGE_NEEDWRITE。返回。

  这里需要注意的是,如果只有BITMAP_PAGE_NEEDWRITE标记的页,是不需要等待的,因为bit的清除并不是很关键,即使这个信息丢失,最多不过是多余的同步操作而已,没有副作用。而bit的设置,则需要保证写入磁盘的“可靠”后,才能进行盘阵chunk的写入;否则在chunk数据写入磁盘时,对应的bitmap中的bit写入磁盘前,盘阵出现异常,则可能导致数据不一致而bitmap不能发觉。

bitmap_unplug()函数实现了下面两种机制:

  实现bitmap同步刷磁盘

  1. unplug函数的执行在写下发之前进行。raid1守护进程执行flush_pending_writes(),这个流程首先调用bitmap_unplug()处理,调用generic_make_request()下发chunk数据的写请求;
  2. bit写盘完全结束之后,才退出unplug函数。页属性BITMAP_PAGE_DIRTY 时,bitmap_unplug()是等待write_page()写盘完成之后才退出的。实现了bitmap同步刷磁盘,确保了数据的可靠性。

  实现bitmap批量刷磁盘

  1. bitmap_startwrite和bitmap_unplug两步实现。bitmap_unplug要遍历所有bitmap file缓存的page,bitmap_startwrite只针对一次写操作对应的bitmap file缓存的page。

  bitmap_endwrite()写完成后,取出对应数据段的bitmap内存结构:

  1. COUNT递减;
  2. 如果COUNT<=2,则设置对应filemap页的BITMAP_PAGE_CLEAN属性;
  3. 如果有chunk写失败,则设置对应bitmap的*bmc的NEEDED标志。表示需要同步。

  具体的函数代码流程如下图所示:

3. 同步流程Bitmap的设置

  bitmap_start_sync()。在chunk同步操作开始时,调用该函数。这个函数获取bitmap的内存结构:

  1. 如果NEEDED标志或者RESYNC标志被设置,就认为该数据块需要同步;
  2. 此时如果盘阵工作完好,则清除NEEDED标志,设置RESYNC标志;
  3. 如果NEEDED和RESYNC都没有设置,则认为该数据块不需要同步。

  bitmap_end_sync()。chunk同步完成后,调用该函数。这个函数获取bitmap的内存结构:

  1. 如果RESYNC标志被设置,则清除该标志;
  2. 如果同步是失败的,则设置NEED位;
  3. 如果同步成功,并且COUNT<=2,则设置该页属性为BITMAP_PAGE_CLEAN,表示该页存在需要清除的bit位。

转载请注明出处:http://www.cnblogs.com/fangpei/

时间: 2024-12-05 17:45:54

MD中bitmap源代码分析--设置流程的相关文章

MD中bitmap源代码分析--清除流程

bitmap的清零是由bitmap_daemon_work()来实现的.Raid1守护进程定期执行时调用md_check_recovery,然后md_check_recovery会调用bitmap_daemon_work根据各种状态进行清零的操作.Bitmap_daemon_work的实现比较复杂,bitmap的清理需要两次调用bitmap_daemon_work来完成的.下面主要以图的形式逐步分析bitmap清除的全部过程. 刚进入这个函数的时候内存bitmap file的页bitmap_at

MD中bitmap源代码分析--入题概述

在MD模块中,各级raid都使用的一份bitmap的源码,也就是说共用一种bitmap的流程,下面以raid1的使用为例来分析bitmap的工作原理. 在使用raid1磁盘阵列的时候,对于数据的可靠性有很高的要求.在写的过程中,有可能存在不稳定的因素,比如磁盘损坏.掉电/宕机.网络故障.系统故障等,这样导致写入失败,在系统恢复后,raid也需要进行恢复,如果磁盘比较大,那同步恢复的过程会很长.以raid1来说,在发生故障时,可能盘阵的数据很多都是已经一致的了,其实只有少部分不一致,所以就没必要进

MD中bitmap源代码分析--状态机实例

1. page_attrs的状态转换关系 之前说过,bitmap的优化核心是:bitmap设置后批量写入:bitmap延时清除.写bit用bitmap_statrwrite() + bitmap_unplug()两个函数,实现了bitmap设置后的批量写入:清bit用bitmap_endwrite()+两轮bitmap_deamon_work()实现了bitmap延迟清除.   2. 一个实例分析 下面以一个写请求实例来进行分析.假设写之前的chunk的数据都是一致的,还是以写3*4096*8(

Raid1源代码分析--读流程

我阅读的代码的linux内核版本是2.6.32.61.刚进实验室什么都不懂,处于摸索阶段,近期的任务就是阅读raid1的源码.第一次接触raid相关的东西,网上分析源码的资料又比较少,不详细.逐行阅读代码,做了笔记.如果要对raid1的读流程有个整体上的把握,需要将笔记中的主线提炼出来,这里不写了.理解不足或者有误之处,希望批评指正. 读流程主要涉及以下函数: 请求函数make_request 读均衡read_balance 回调函数raid1_end_read_request 读出错处理rai

Raid1源代码分析--初始化流程

初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些初始化的操作.主要是对RAID1中的conf进行初始化.run函数在md.c的do_md_run中被调用.   run函数的具体流程 0.传入参数mddev就是指RAID1所处的MD设备. 1.  定义相关变量. 1.1  定义conf指针,类型为raid1_private_data_s,是raid

Raid1源代码分析--同步流程

同步的大流程是先读,后写.所以是分两个阶段,sync_request完成第一个阶段,sync_request_write完成第二个阶段.第一个阶段由MD发起(md_do_sync),第二个阶段由守护进程发起. 如果是用户发起的同步请求.该请求下发到raid1层,首先进入同步读函数sync_request.在正常的成员盘中,将所有active可用的盘(rdev->flags中有In_sync标记)设置为read盘,而所有不可用的盘不做设置.对每一个可用盘对应的bios[]都单独申请页结构,对所有的

Raid1源代码分析--写流程

正确写流程的总体步骤是,raid1接收上层的写bio,申请一个r1_bio结构,将其中的所有bios[]指向该bio.假设盘阵中有N块盘.然后克隆N份上层的bio结构,并分别将每个bios[]指向克隆出来一个bio结构,然后进行相应设置. 对于没有Write Behind模式而言,之后将所有这些bios[](共用页结构)放入队列pending_list中,对内存bitmap置位.接着由守护进程摘取pending_list链中的bio,然后将内存bitmap同步下刷到磁盘,紧接着立即一次性下发bi

IC设计中的功耗分析的流程

首先声明本文所讲的范围,在这篇文章中,是采用synopsys的设计流程,对数字电路进行功耗分析,生成功耗分析报告的流程.分析的对象是逻辑综合之后布局布线之前的功耗分析,以及布局布线之后的功耗分析. Synopsys做功耗分析使用到的工具是:Primetime PX, Prime Rail.PTPX可以在逻辑综合之后就进行功耗预估.PrimeTime PX是集成在PrimeTime里面的工具,虽然他可以做功耗分析,但是毕竟不是sign-off工具.真正到最后的sign-off,如果对功耗的要求很高

openVswitch(OVS)源代码分析之工作流程(数据包处理)

上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到key值和skb数据包进行流表的匹配:第三.根据匹配到的流表做相应的action操作(若没匹配到则调用函数往用户空间传递数据包):其具体的代码实现在 datapath/datapath.c 中的,函数为: void ovs_dp_process_received_packet(struct vpor