Raid1源代码分析--开篇总述
前段时间由于一些事情耽搁了,最近将raid1方面的各流程整理了一遍。网上和书上,能找到关于MD下的raid1的文档资料比较少。决定开始写一个系列的关于raid1的博客,之前写过的一篇读流程也会在之后加一些修改,我阅读的代码的linux内核版本是2.6.32.61。进入实验室的时间不长,关于磁盘管理等内核方面的理解不足或者有误之处,希望批评指正。
一、Raid1简介
Raid1又称为镜像磁盘阵列。由两块或者多块盘构成这样一个阵列,并且每块盘所存储的内容都是完全一致的。意思就是盘与盘之间互为镜像,而在上层看来只有一块盘。比如说,如果现在有两块1T的盘,做成一个raid1阵列,那么在用户看来只有一块1T的盘。
这样虽然明显降低了磁盘的利用率,但是却提高了数据的安全性。如果其中有一块盘坏了,数据仍然没有丢失,因为数据在其他盘中还有备份。只是盘阵会处于降级状态,那么这种情况,只需要用热备盘来替换损坏盘即可。
Raid1中的流程可以分为三大部分:读、写、同步。读请求会选择盘阵中的一块盘中进行读操作,写请求会对盘阵中每一块盘进行写操作,同步请求会将最新数据的盘内容读取出来,然后写入其他盘中,达到同步效果。
下面将从以下几个部分来进行展开介绍:
- Raid1相关数据结构
- Raid1相关策略
- 初始化流程分析
- 读流程分析
- 写流程分析
- 同步流程分析
- raid1d函数流程分析
- bitmap相关分析(bitmap会在后续单独分析)
二、Raid1相关数据结构
1) r1_bio结构
struct r1bio_s {
atomic_t remaining; //未完成的请求数
atomic_t behind_remaining; //延迟写的未完成请求数
sector_t sector; //请求扇区号
int sectors; //请求扇区数
unsigned long state; //状态
mddev_t *mddev; //raid1设备
struct bio *master_bio; //记录上层下发的bio
int read_disk; //读请求的盘号
struct list_head retry_list; //重试请求链表
struct bitmap_update *bitmap_update; //没啥用
struct bio *bios[0]; //指向盘阵中每个盘的bio
};
这里的r1_bio主要用来管理raid1中相关的bio。通过最后一个*bios[0]柔性数组来达到管理raid1下发到每个盘的bio,通过*master_bio来管理raid1接收到上层的bio。
remaining字段和behind_remaining字段,对于延迟写的判断起到了重要作用,在写流程中会有具体分析。
bitmap_update字段没什么用,在更高的代码版本中,直接将这个字段删除了。
2)conf结构
struct r1_private_data_s {
mddev_t *mddev; //raid1设备
mirror_info_t *mirrors; //盘阵的首地址指针
int raid_disks; //盘数
int last_used; //最后一次读操作的盘号
sector_t next_seq_sect; //顺序的下一个扇区
spinlock_t device_lock; //设备锁
struct list_head retry_list; //重试请求链表
struct bio_list pending_bio_list; //正常的读写请求链表
struct bio_list flushing_bio_list;
spinlock_t resync_lock; //同步锁
int nr_pending; //pending队列请求数
int nr_waiting; //等待请求数
int nr_queued; //retry队列的请求数
int barrier; //是否设置屏障,raid1自己的一套barrier
sector_t next_resync; //下一个要同步的扇区
int fullsync; //设置是否全部同步
wait_queue_head_t wait_barrier; //进程队列,通过这个切换回守护进程
struct pool_info *poolinfo;
struct page *tmppage; //临时页
mempool_t *r1bio_pool; //正常请求的r1bio结构的缓冲池
mempool_t *r1buf_pool; //同步请求的r1bio结构的缓冲池
};
这里r1_private_data_s是用来管理整个raid1本身的。其中的pending_bio_list和retry_bio_list两个队列是守护进程与其他进程交互的“纽带”,守护进程只需处理这两个队列即可。
flushing_bio_lsit字段没什么用,在更高的代码版本中,直接将这个字段删除了。
三、Raid1相关策略
1)WriteMostly
WriteMostly是对raid1成员盘设置的一种属性,用户决定哪些成员盘是否设置为WriteMostly盘,或者一个盘也不设置WriteMostly。WriteMostly盘认为是“慢盘”。对于设置了WriteMostly的盘,尽量避免从该盘中读数据。在read balance中有体现,是优先读非WriteMostly盘。假如镜像的速度很慢,这样的设置是非常有效的。
可以只设置WriteMostly盘而不设置Write Behind模式,设置WriteMostly盘是Write Behind的前提。是否启动write behind模式,取决于超级块的设置。
2)Write Behind
只有设置了WriteMostly盘,Write Behind才有意义。Write Behind模式意味着,只要数据写入了非WriteMostly模式的磁盘,就认为写入成功返回。如果没有设置write behind模式的话,则需要写入所有盘后才能认为写入成功。
设置Write Behind模式后,如果所有非WriteMostly盘写入成功,则通知上层“所有磁盘写入成功”,raid1层接收的上层bio即可结束返回。但实际情况并非上层“看到”的这样,因为还有可能存在WriteMostly盘还未完成写操作。所以一定存在Behind pages与WriteMostly盘对应,这是在raid1中保存的接受上层的bio的页结构的一份拷贝数据,在所有盘的写请求都成功返回后,才能把behind pages这份拷贝释放,并释放r1_bio结构。Behind pages用来保证写请求能最终完成,是写请求完整性和正确性的一个必要的保障。
例如,raid1中有两个成员盘。一个成员盘是本地磁盘,另一个成员盘是局域网中的一块盘,则将局域网的磁盘设置WriteMostly盘(因为比较“慢”),然后开启write behind模式。这样在写入数据时,本地磁盘数据写完后,raid则认为该次写操作已完成。
3)Read balance
Read balance是读均衡算法。在读请求的时候,通过read balance来选取一块盘进行读操作。读均衡算法达到了在尽量避免从WriteMostly盘读数据的前提下,对于其他每个成员盘读请求负载尽量一致,并且提高读取速度。具体流程分析在“Raid1源代码分析--读流程(重新整理)”文中有详细说明。
4)barrier
在raid1中有两种barrier。一种是接收到上层的bio所具有的barrier属性,一种是raid1自身实现的一套barrier。
对于接收到上层的具有barrier属性的bio,该barrier属性由用户决定是否设置,只有在写操作的时候会出现。当md收到一个barrier bio请求时,md会先把在该barrier bio之前到达的bio完成,然后再完成barrier bio,之后再处理在barrier bio之后到达的bio。通过bio中的标记为BIO_RW_BARRIER来判断是否设置了barrier。
对于raid1自身实现的一套barrier,只有在raid1进行同步操作的时候设置,而且同步时一定会设置。因为在同步过程中是不能让其他读写请求进入raid1层“打扰”同步操作的,所以raid1会自己设计一套barrier,来满足该需求。通过conf->barrier的增减,来控制barrier的设置,并通过判断conf->barrier是否为0,来决定是否阻拦读写操作,而让读写操作进入等待状态。
5)bitmap
Bitmap主要是为了保证数据的可靠性。在写的过程中,有可能存在不稳定的因素,比如磁盘损坏,系统故障等,这样导致写入失败,在系统恢复后,raid1也需要进行恢复,传统的恢复方式就是全盘扫描计算校验或者全量同步,如果磁盘比较大,那同步恢复的过程会很长,有可能再发生其他故障,这样就会对业务有比较大的影响。以raid1来说,在发生故障时,其实两块盘的数据很多都是已经一致的了,可能只有少部分不一致,所以就没必要进行全盘扫描,但是系统并不知道两块盘哪些数据是一致的,这就需要在某个地方记录哪些是已同步的,为此,就诞生了bitmap,简单来说,bitmap就是记录raid中哪些数据是一致的,哪些是不一致的,这样在raid进行恢复的时候就不用全量同步,而是增量同步了,从而减少了恢复的时间。
bitmap的一个bit对应盘阵的一个chunk,在盘阵数据写入前,设置该chunk对应的bit,盘阵写入完成,则清除该bit。要进行同步时,参照bitmap,只有置位的bit对应的chunk才需要进行同步,这样缩短了同步的时间,提高了效率。这是最简单的一种思路。
注:bitmap小节的两段,参考资料 http://www.bitstech.net/2014/01/27/linux软raid的bitmap分析/
http://blog.csdn.net/qincp/article/details/4396517
6)pending_list与retry_list
pending_list为正常请求的队列,retry_list为重试请求队列,这两个队列是守护进程与其他进程交互的枢纽。其他进程将bio或者r1_bio添加队列中就完成了自己的任务,唤醒守护进程;守护进程只操作这两个队列,先将pending_list中的请求一次下发,然后逐一处理retry_list中的请求。只有在两个队列都为空的情况下,守护进程才会退出。pending_list中的每一项为bio,retry_list中的每一项为r1_bio,因为pending_list中的存放的是正常请求,所以直接是bio结构下发即可,而retry_list是重试请求,需要对整个盘阵的bio进行重新处理,所以是r1_bio结构。
本文来自fangpei的博客,转载请标明出处:http://www.cnblogs.com/fangpei/
Raid1源代码分析--开篇总述的更多相关文章
- Raid1源代码分析--Barrier机制
本想就此结束Raid1的专题博客,但是觉得Raid1中自己构建的一套barrier机制的设计非常巧妙,值得单独拿出来分析.它保证了同步流程和正常读写流程的并发性,也为设备冻结/解冻(freeze/un ...
- Raid1源代码分析--一些补充
Raid1的源码的读.写.同步,在本系列博客中都已经分析完成.除了barrier机制要专门拿出来分析(下一篇会写)以外,有一些问题值得思考和注意,分析如下. 1.freeze_array是如何做的? ...
- Raid1源代码分析--同步流程
同步的大流程是先读,后写.所以是分两个阶段,sync_request完成第一个阶段,sync_request_write完成第二个阶段.第一个阶段由MD发起(md_do_sync),第二个阶段由守护进 ...
- Raid1源代码分析--写流程
正确写流程的总体步骤是,raid1接收上层的写bio,申请一个r1_bio结构,将其中的所有bios[]指向该bio.假设盘阵中有N块盘.然后克隆N份上层的bio结构,并分别将每个bios[]指向克隆 ...
- Raid1源代码分析--读流程(重新整理)
五.Raid1读流程分析 两个月前,刚刚接触raid1,就阅读了raid1读流程的代码,那个时候写了一篇博客.现在回过头看看,那篇的错误很多,并且很多地方没有表述清楚.所以还是决定重新写一篇以更正之前 ...
- Raid1源代码分析--初始化流程
初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些 ...
- Raid1源代码分析--读流程
这篇博文不足之处较多,重新整理了一下,链接:http://www.cnblogs.com/fangpei/p/3890873.html 我阅读的代码的linux内核版本是2.6.32.61.刚进实验室 ...
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- Android4.42-Settings源代码分析之蓝牙模块Bluetooth总体实现(总)
本文为博主原创,转载请注明出处:http://blog.csdn.net/zrf1335348191/article/details/50995466 蓝牙相关代码已在另两篇文章中介绍,有须要的能够查 ...
随机推荐
- JS点击按钮弹出窗口
由于没有系统学习过JS,遇到一个需求:点击按钮,弹出一个独立的窗口. 在网上百度了一下,并没有找到满意的结果,最重要的是各种方法很复杂.最终,仔细研究了一下,原来只是需要只要一个简单的函数就能满足自己 ...
- JS 中的引用
首先有一个全局变量 JsonArry={"key":"value"}; 假设这个object为{"你好":"引用"} ...
- nexus5 root教程
转载自: http://www.inexus.co/article-1280-1.html http://www.pc6.com/edu/71016.html https://download.cha ...
- Linux下编译安装Apache及模块
Apache是时下最流行的Webserver软件之中的一个,支持多平台,可高速搭建web服务,并且稳定可靠.并可通过简单的API扩充.就能够集成PHP/Python等语言解释器. 文章这里解说怎样在l ...
- Set Windows IP by Batch
netsh interface ip set address name="Local" static 192.168.1.55 255.255.255.0 192.168.1.1 ...
- django: db - admin
本讲演示简单使用 Django Admin 功能. 一,修改 settings.py,添加 admin 应用: INSTALLED_APPS = ( 'django.contrib.auth', 'd ...
- 一步步启动linux
可以一步一步启动linux. 在Ubantu刚一启动时,按c健即进入Grub>提示符状态,在此状态下输入(我用的是Ubuntu 13) grub>linux /vmlinuz grub&g ...
- (转)js 中{},[]中括号,大括号使用详解
一.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数. 如:var LangShen = {"Name":"Langshen",&qu ...
- \r \r\n \t 的区别
http://www.360doc.com/content/12/0530/15/16538_214756101.shtml \n 软回车: 在Windows 中表示换行且回到下一行的最开 ...
- (原)python使用ctypes调用C/C++接口
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6135514.html 参考网址: https://docs.python.org/2/library/ ...