md源代码解析-part1
最近花了一段时间认真地学习了一下md代码,并且在原代码的基础上开发了一系列的新功能,这些新功能让md更完善、更适合于企业大容量存储,通过增加阵列缓存和bitmap优化大大提升了存储速度,提高了数据的可靠性,在任何掉电的情况下保证数据一致性,超级块异常情况下完全不影响阵列使用,完全控制了踢盘问题,简化了用户操作。简单地概括一下,就是让存储不再有门槛。说了这么多,其实想表达的意思就是md的学习之路并非十分顺利,特此写此博文与所有兄弟姐妹们共享一下我的学习经验,如果您看完之后能有所收获,那就不枉费我下功夫写这些技术文章,同时您的感想和回复也将是我能够继续写下去的最大动力。
md代码在内核树中十多年经久不衰,跟作者neil brown,一位久经考验的开源战士,是分不开的。neil brown的博客地址是http://blog.neil.brown.name/,这个网址非常重要,因为我发现自己遇到疑难问题的时候80%问题都能在这里找到答案,所以有空的时间从到头到尾扫一遍,可以解决许多“为什么要这样做”的问题。
最初我看内核代码都是从module_init开始看的,可是自从学习了kconfig之后,我就改变了一下习惯,从kconfig和Makefile开始看代码了,如果谁有更好的办法请分享一下谢谢。
下面就来看一下drivers/md/Kconfig
[cpp] view plain copy
- #
- # Block device driver configuration
- #
- menuconfig MD
- bool "Multiple devices driver support (RAID and LVM)"
- depends on BLOCK
- help
- Support multiple physical spindles through a single logical device.
- Required for RAID and logical volume management.
- if MD
- config BLK_DEV_MD
- tristate "RAID support"
- ---help---
- #...省略若干
- endif # MD
menuconfig这个单词已经很熟悉了,因为自从开始学习编译内核的时候就有这样一个命令make menuconfig,当我们在内核源代码目录下敲下这个命令时,就会出现一个文本配置界面,在文本配置界面中可以选择需要编译到内核的模块,那有了这里的menuconfig MD,文本配置界面中才会有MD的一项,当选中MD之后,文本配置界面才会出现config BLK_DEV_MD和之后的选项,这些选项一般有两种状态,一个是tristate,表示内建、模块、移除三种状态,另一个是bool,表示选中或不选中。depends on表示正向依赖,如果选上了这个模块,那么正向依赖的模块也会自动选上,正向依赖模块递归所依赖的模块也会选上。一般把这些驱动模块选择为按模块加载,可以方便修改调试。
知道了Kconfig的基本配置,就可以按需定制内核,把不需要的统统去掉,也明白了为什么有时候系统的lib/module/下面为什么没有对应的模块了。
而对于阅读源代码来说,知道了哪些源代码编译进了内核,哪些源代码编译进了模块,哪些源代码没有编译,这样就可以按需阅读源代码了。另外在源代码中有一些编译选项类似:
#ifdef CONFIG_*
//code
#endif
那么*号就是对应这里Kconfig中config后面的选项,如果这里选项选上,那么编译选项就为真。这些编译选项还用于对应的Makefile文件中,如md对应的Makefile文件有:
[cpp] view plain copy
- obj-$(CONFIG_MD_RAID0) += raid0.o
- obj-$(CONFIG_MD_RAID1) += raid1.o
- obj-$(CONFIG_MD_RAID10) += raid10.o
- obj-$(CONFIG_MD_RAID456) += raid456.o
- obj-$(CONFIG_MD_MULTIPATH) += multipath.o
- obj-$(CONFIG_MD_FAULTY) += faulty.o
- obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
如果在Kconfig中选中了config BLK_DEV_MD,那么Makefile就要编译生成md-mod.ko模块,那这个模块由哪几个文件生成的呢?看Makefile中定义:
md-mod-y += md.o bitmap.o
raid456-y += raid5.o
就是说在Kconfig中选中了config BLK_DEV_MD,md.c, bitmap.c就会被编译。同理,config MD_RAID456被选中,raid5.c就会被编译。这里,我们也可以知道,哪一个模块对应着哪几个源文件。例如要加载md-mod.ko,那么就需要md.c, bitmap.c。修改raid5代码时,只需要重新编译raid5.c一个文件就可以了。
md源代码解析-part2
在编译完成linux内核源代码的时候,drivers/md目录下会生成多个ko文件,那么这些内核模块哪一个先加载,哪一个后加载的呢?例如md-mod.ko, raid5.ko, raid10.ko,这些模块是一起加载的呢,还是有先后顺序呢?如果熟悉linux内核编程的话,知道有一个request_module函数,这个函数用于请求加载一个模块,但这个函数并不能说明一个模块对另一个模块的依赖关系。准确的信息还是来自于Kconfig,这里只抽取Kconfig中相关的部分:
config BLK_DEV_MD
tristate "RAID support"
config MD_RAID10
tristate "RAID-10 (mirrored striping) mode"
depends on BLK_DEV_MD
config MD_RAID456
tristate "RAID-4/RAID-5/RAID-6 mode"
depends on BLK_DEV_MD
从这里我们可以看出,raid5.ko, raid10.ko都是依赖于md-mod.ko的(参见如上标红部分的关联),这就决定了我们的阅读方向是从md-mod.ko中开始的。
那么md-mod.ko中又是从哪个文件开始的呢?这就要找module_init函数,这个函数在md.c中定义的,那么就从这里入手。
8416 static int __init md_init(void)
8417 {
8418 int ret = -ENOMEM;
8419
8420 md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0);
8421 if (!md_wq)
8422 goto err_wq;
8423
8424 md_misc_wq = alloc_workqueue("md_misc", 0, 0);
8425 if (!md_misc_wq)
8426 goto err_misc_wq;
8427
8428 if ((ret = register_blkdev(MD_MAJOR, "md")) < 0)
8429 goto err_md;
8430
8431 if ((ret = register_blkdev(0, "mdp")) < 0)
8432 goto err_mdp;
8433 mdp_major = ret;
8434
8435 blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE,
8436 md_probe, NULL, NULL);
8437 blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
8438 md_probe, NULL, NULL);
8439
8440 register_reboot_notifier(&md_notifier);
8441 raid_table_header = register_sysctl_table(raid_root_table);
8442
8443 md_geninit();
8444 return 0;
8445
8446 err_mdp:
8447 unregister_blkdev(MD_MAJOR, "md");
8448 err_md:
8449 destroy_workqueue(md_misc_wq);
8450 err_misc_wq:
8451 destroy_workqueue(md_wq);
8452 err_wq:
8453 return ret;
8454 }
模块的初始化过程看起来异常地简单,这就像有些人表面看起来十分普通,内心里却无比地强大,所以不要只看外表,还要听其言观其行。内在的美丽比外表的荣华更具吸引力和持久性。
8420和8424行,分别创建了工作队列,md_wq是用于flush命令的,另一个md_misc_wq,misc是miscellaneous的简写,是杂项的意思,用于处理一些零零碎碎的事情。
8428和8431行,创建了两个块设备,刚开始我只注意md的设备,压根没在意mdp,搜索变量mdp_major,在函数autorun_devices中使用了这个变量:
5474 if (part) {
5475 dev = MKDEV(mdp_major,
5476 rdev0->preferred_minor << MdpMinorShift);
5477 unit = MINOR(dev) >> MdpMinorShift;
5478 } else {
5479 dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
5480 unit = MINOR(dev);
5481 }
5474行,变量part是函数传入参数,表示磁盘第几个分区,那么就知道mdp_major中字母p是表示part的意思,而mdp_major就表示用磁盘分区创建的阵列。
8435和8437行,创建了两个region,这两个函数的作用是在用户态创建了一个/dev/md*设备时,内核态就会对应调用md_probe创建一个mddev结构体,之后在用户态对/dev/md*的操作到内核态就相应地对mddev的操作了。
8440行,注册关机回调函数,主要作用是停止阵列线程,刷数据操作。
8441行,注册sysctl函数,用于控制阵列最小和最大的sync速度。
8443行,注册proc函数,于是有了目录/proc/mdstat,该目录的显示由函数md_seq_show控制。
md初始化代码就这样轻松地完成了,可是回到我们的初衷,仍然对md设备一无所知。那么md设备是如何创建的呢?创建的过程又是怎么的呢?一个阵列拥有哪些资源?下一节我们直入核心,开始阅读阵列创建的过程。
md源代码解析-part3
按照常理出牌,我们到ioctl中找阵列创建命令,md对应的ioctl函数是md_ioctl,当找对应的cmd命令字时,却完全没有类似CREATE_ARRAY的命令,那么就说明md设备并不是通过ioctl函数来创建的。其实如果我们仔细阅读一下md_ioctl函数的原型就会发现其实创建md设备根本就不在这个地方,函数原型如下:
6303 static int md_ioctl(struct block_device *bdev, fmode_t mode,
6304 unsigned int cmd, unsigned long arg)
6303行,第一个参数是struct block_device*,就是说对一个块设备下发的命令,可是我们在创建md设备之前就没有对应的md块设备。到此,线索就断了,创建设备的入口到底是在哪里呢?
此路不通,我们换一条路走。创建md设备总是要创建struct mddev结构吧,那就找哪里申请了struct mddev内存结构不就可以了吗?这个方法是可行的,可是struct mddev结构体是用kmalloc申请的,这是怎么知道的呢?因为在函数md_init中根本就没有申请struct mddev内存池的代码,只好用kmalloc申请了。我们在md.c文件中搜索kmalloc再根据结果一条条找就能找出struct mddev创建的位置。但这里我们使用一个更简便的方法,那就是申请到了struct mddev结构总要进行初始化的吧,初始化函数是mddev_init,搜索这个函数,md.c文件中只有函数mddev_find()一处调用到,很显然已经找到了struct mddev结构的创建入口了,那就接着往上层调用去找创建md设备的入口函数吧。
我们可以找到这样的调用关系,箭头表示调用关系:
mddev_find() <--- md_alloc() <--- md_probe()
md_probe()函数就是在模块初始化函数md_init()中调用的blk_register_region()函数中的传入参数,熟悉blk层的同学都知道,只要在用户态创建了一个md设备,就会相应调用到内核probe()函数,而这里传入的probe()函数正是md_probe()。所以创建struct mddev结构体是由用户态触发的,而不是由内核态直接进行的。如果到了今天这个时代,还把这种琐碎的事情放在内核态去做,你都不好意思说你是做linux开发的。做linux开发就是要引导时尚,崇尚简单才是美。linux内核只提供机制,不提供具体实现策略。跟机制不相关的控制命令就需要从内核搬到用户态,一方面简化了内核,突出重点,方便了内核维护,另一方面在用户态维护策略让应用程序更加灵活并且方便了调试。
这样我们就从内核态杀到了用户态,用户态程序就是大名鼎鼎的mdadm,网上随便一搜就是一大堆人云亦云的文章,但最好的文章不是在网上,而是用命令man mdadm。用命令mdadm create来创建一个阵列,这里不去阅读mdadm的代码,因为这是用户态程序不是我们阅读的重点,其次这些代码也很简单基本上学过初中英语的同学都能看得懂。我们需要知道的是mdadm create命令最终会调用mknod()函数来创建一个/dev/md*设备,这样内核也就相应有了struct mddev结构体,这时这个结构体还是一个空结构体,空的意思就是说这个阵列没有设置属性,没有对应的物理磁盘,没有运行阵列。
到这个时候既然已经有了md设备,那就轮到md_ioctl上场的时候了,这个函数对应的ioctl命令字在文件include\linux\raid\md_u.h:
36 /* ioctls */
37
38 /* status */
39 #define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t)
40 #define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
41 #define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
42 #define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13)
43 #define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
44 #define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
45
46 /* configuration */
47 #define CLEAR_ARRAY _IO (MD_MAJOR, 0x20)
48 #define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
49 #define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22)
50 #define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, mdu_array_info_t)
51 #define SET_DISK_INFO _IO (MD_MAJOR, 0x24)
52 #define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25)
53 #define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26)
54 #define PROTECT_ARRAY _IO (MD_MAJOR, 0x27)
55 #define HOT_ADD_DISK _IO (MD_MAJOR, 0x28)
56 #define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29)
57 #define HOT_GENERATE_ERROR _IO (MD_MAJOR, 0x2a)
58 #define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int)
59
60 /* usage */
61 #define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
62 /* 0x31 was START_ARRAY */
63 #define STOP_ARRAY _IO (MD_MAJOR, 0x32)
64 #define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33)
65 #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
这个文件为什么不放在md目录而放在include目录下?是因为文件里的内容是用户态跟内核态共用的,如果是内核态单独用的就没有必要放在这里了。
对于阵列的创建流程,最关心的命令字有:
SET_ARRAY_INFO 设置阵列信息
ADD_NEW_DISK 添加磁盘到阵列
RUN_ARRAY 运行阵列
首先看设置阵列信息,这个函数是这三个函数中最简单的一个:
6000 /*
6001 * set_array_info is used two different ways
6002 * The original usage is when creating a new array.
6003 * In this usage, raid_disks is > 0 and it together with
6004 * level, size, not_persistent,layout,chunksize determine the
6005 * shape of the array.
6006 * This will always create an array with a type-0.90.0 superblock.
6007 * The newer usage is when assembling an array.
6008 * In this case raid_disks will be 0, and the major_version field is
6009 * use to determine which style super-blocks are to be found on the devices.
6010 * The minor and patch _version numbers are also kept incase the
6011 * super_block handler wishes to interpret them.
6012 */
6013 static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
6014 {
6015
6016 if (info->raid_disks == 0) {
6017 /* just setting version number for superblock loading */
6018 if (info->major_version < 0 ||
6019 info->major_version >= ARRAY_SIZE(super_types) ||
6020 super_types[info->major_version].name == NULL) {
6021 /* maybe try to auto-load a module? */
6022 printk(KERN_INFO
6023 "md: superblock version %d not known\n",
6024 info->major_version);
6025 return -EINVAL;
6026 }
6027 mddev->major_version = info->major_version;
6028 mddev->minor_version = info->minor_version;
6029 mddev->patch_version = info->patch_version;
6030 mddev->persistent = !info->not_persistent;
6031 /* ensure mddev_put doesn't delete this now that there
6032 * is some minimal configuration.
6033 */
6034 mddev->ctime = get_seconds();
6035 return 0;
6036 }
6037 mddev->major_version = MD_MAJOR_VERSION;
6038 mddev->minor_version = MD_MINOR_VERSION;
6039 mddev->patch_version = MD_PATCHLEVEL_VERSION;
6040 mddev->ctime = get_seconds();
6041
6042 mddev->level = info->level;
6043 mddev->clevel[0] = 0;
6044 mddev->dev_sectors = 2 * (sector_t)info->size;
6045 mddev->raid_disks = info->raid_disks;
6046 /* don't set md_minor, it is determined by which /dev/md* was
6047 * openned
6048 */
6049 if (info->state & (1<<MD_SB_CLEAN))
6050 mddev->recovery_cp = MaxSector;
6051 else
6052 mddev->recovery_cp = 0;
6053 mddev->persistent = ! info->not_persistent;
6054 mddev->external = 0;
6055
6056 mddev->layout = info->layout;
6057 mddev->chunk_sectors = info->chunk_size >> 9;
6058
6059 mddev->max_disks = MD_SB_DISKS;
6060
6061 if (mddev->persistent)
6062 mddev->flags = 0;
6063 set_bit(MD_CHANGE_DEVS, &mddev->flags);
6064
6065 mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
6066 mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
6067 mddev->bitmap_info.offset = 0;
6068
6069 mddev->reshape_position = MaxSector;
6070
6071 /*
6072 * Generate a 128 bit UUID
6073 */
6074 get_random_bytes(mddev->uuid, 16);
6075
6076 mddev->new_level = mddev->level;
6077 mddev->new_chunk_sectors = mddev->chunk_sectors;
6078 mddev->new_layout = mddev->layout;
6079 mddev->delta_disks = 0;
6080 mddev->reshape_backwards = 0;
6081
6082 return 0;
6083 }
首先看注释,这个函数有两种用途,一是用于创建阵列,当创建阵列时,raid_disk>0,另一种用途是assemble阵列,这时raid_disk==0。
那这里的raid_disk到底是多少呢?注释里又有这样的一句话,如果raid_disk>0,那么直接创建0.90阵列超级块,很显然,我们要创建的阵列超级块是1.2的,所以6037-6080只是用于兼容老版本的阵列的,需要阅读的代码只有6016行if语句中的那几行代码。
6027-6029行,设置阵列超级块版本号。
6030行,设置persistent属性,就是说超级块是保存在磁盘上还是只放在内存中啊,这里我们都是保存在磁盘上,以后看到这个属性就永远为true。
6034行,设置阵列创建时间。
那么是在什么时候才开始设置阵列属性呢?比如说阵列级别?别急,好戏还在后头。
接着看ADD_NEW_DISK对应的处理函数:
5672 static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
5673 {
5674 char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
5675 struct md_rdev *rdev;
5676 dev_t dev = MKDEV(info->major,info->minor);
5677
5678 if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
5679 return -EOVERFLOW;
5680
5681 if (!mddev->raid_disks) {
5682 int err;
5683 /* expecting a device which has a superblock */
5684 rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
5685 if (IS_ERR(rdev)) {
5686 printk(KERN_WARNING
5687 "md: md_import_device returned %ld\n",
5688 PTR_ERR(rdev));
5689 return PTR_ERR(rdev);
5690 }
5691 if (!list_empty(&mddev->disks)) {
5692 struct md_rdev *rdev0
5693 = list_entry(mddev->disks.next,
5694 struct md_rdev, same_set);
5695 err = super_types[mddev->major_version]
5696 .load_super(rdev, rdev0, mddev->minor_version);
5697 if (err < 0) {
5698 printk(KERN_WARNING
5699 "md: %s has different UUID to %s\n",
5700 bdevname(rdev->bdev,b),
5701 bdevname(rdev0->bdev,b2));
5702 export_rdev(rdev);
5703 return -EINVAL;
5704 }
5705 }
5706 err = bind_rdev_to_array(rdev, mddev);
5707 if (err)
5708 export_rdev(rdev);
5709 return err;
5710 }
这个函数只截取了一部分,因为这一次添加磁盘流程只会走到这一部分代码,首先注意到函数的参数:第一个参数是struct mddev结构体,这个结构体域比较多,我们会在后面用到具体域时再讲,第二个参数是表示一个要加入阵列的磁盘,这里用到了该结构体的两个域,major和minor,表示磁盘主设备号和次设备号。
5676行,根据主设备号和次设备号算出dev_t。
5678行,这里为什么还要再检查一下呢?返回的错误码叫溢出,意思是说很久很久以前linux中设备还不是很多的时候dev_t只要用16位来表示就可以了,然而随着linux服务器单一种类外设数量越来越多,dev_t扩展到32位,所以这里检查保证输入major,minor的正确。
5681行,这里还未添加磁盘,所以进入这个if分支。
5684行,创建磁盘struct md_rdev结构,继续跟入到函数中:
3236 /*
3237 * Import a device. If 'super_format' >= 0, then sanity check the superblock
3238 *
3239 * mark the device faulty if:
3240 *
3241 * - the device is nonexistent (zero size)
3242 * - the device has no valid superblock
3243 *
3244 * a faulty rdev _never_ has rdev->sb set.
3245 */
3246 static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
3247 {
3248 char b[BDEVNAME_SIZE];
3249 int err;
3250 struct md_rdev *rdev;
3251 sector_t size;
3252
3253 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
3254 if (!rdev) {
3255 printk(KERN_ERR "md: could not alloc mem for new device!\n");
3256 return ERR_PTR(-ENOMEM);
3257 }
3258
3259 err = md_rdev_init(rdev);
3260 if (err)
3261 goto abort_free;
3262 err = alloc_disk_sb(rdev);
3263 if (err)
3264 goto abort_free;
3265
3266 err = lock_rdev(rdev, newdev, super_format == -2);
3267 if (err)
3268 goto abort_free;
3269
3270 kobject_init(&rdev->kobj, &rdev_ktype);
3271
3272 size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
3273 if (!size) {
3274 printk(KERN_WARNING
3275 "md: %s has zero or unknown size, marking faulty!\n",
3276 bdevname(rdev->bdev,b));
3277 err = -EINVAL;
3278 goto abort_free;
3279 }
3280
3281 if (super_format >= 0) {
3282 err = super_types[super_format].
3283 load_super(rdev, NULL, super_minor);
3284 if (err == -EINVAL) {
3285 printk(KERN_WARNING
3286 "md: %s does not have a valid v%d.%d "
3287 "superblock, not importing!\n",
3288 bdevname(rdev->bdev,b),
3289 super_format, super_minor);
3290 goto abort_free;
3291 }
3292 if (err < 0) {
3293 printk(KERN_WARNING
3294 "md: could not read %s's sb, not importing!\n",
3295 bdevname(rdev->bdev,b));
3296 goto abort_free;
3297 }
3298 }
3299 if (super_format == -1)
3300 /* hot-add for 0.90, or non-persistent: so no badblocks */
3301 rdev->badblocks.shift = -1;
3302
3303 return rdev;
3304
3305 abort_free:
3306 if (rdev->bdev)
3307 unlock_rdev(rdev);
3308 md_rdev_clear(rdev);
3309 kfree(rdev);
3310 return ERR_PTR(err);
3311 }
3252行,创建一个struct md_rdev结构体。
3259行,初始化struct md_rdev结构体。
3262行,申请一个page页,用于存放磁盘超级块信息。
3266行,对磁盘加锁,防止被其他程序操作如mount, 分区等。
3270行,初始化struct md_rdev磁盘kobject结构。
3272行,读磁盘大小,判断是否合法。
3281行,阵列超级块是1.2版本的,进入if分支。
3282行,读入阵列超级块信息,具体调用的函数是:
1450 static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_version)
这个函数很简单,根据超级块版本从磁盘上读入阵列超级块信息并保存到md_rdev->sb_page中,查做一些基本的校验和检,并将超级块信息保存到struct md_rdev结构中。到这里就返回到add_new_disk函数,
5684行返回的rdev就含有从磁盘上加载的超级块信息。
5691行,由于阵列中还没有磁盘,所以list_empty(&mddev->disks)成立,不会进入if分支。
5706行,建立阵列struct mddev和磁盘struct md_rdev结构之间的联系,进函数:
2077 static int bind_rdev_to_array(struct md_rdev * rdev, struct mddev * mddev)
2078 {
2079 char b[BDEVNAME_SIZE];
2080 struct kobject *ko;
2081 char *s;
2082 int err;
2083
2084 if (rdev->mddev) {
2085 MD_BUG();
2086 return -EINVAL;
2087 }
2088
2089 /* prevent duplicates */
2090 if (find_rdev(mddev, rdev->bdev->bd_dev))
2091 return -EEXIST;
2092
2093 /* make sure rdev->sectors exceeds mddev->dev_sectors */
2094 if (rdev->sectors && (mddev->dev_sectors == 0 ||
2095 rdev->sectors < mddev->dev_sectors)) {
2096 if (mddev->pers) {
2097 /* Cannot change size, so fail
2098 * If mddev->level <= 0, then we don't care
2099 * about aligning sizes (e.g. linear)
2100 */
2101 if (mddev->level > 0)
2102 return -ENOSPC;
2103 } else
2104 mddev->dev_sectors = rdev->sectors;
2105 }
2106
2107 /* Verify rdev->desc_nr is unique.
2108 * If it is -1, assign a free number, else
2109 * check number is not in use
2110 */
2111 if (rdev->desc_nr < 0) {
2112 int choice = 0;
2113 if (mddev->pers) choice = mddev->raid_disks;
2114 while (find_rdev_nr(mddev, choice))
2115 choice++;
2116 rdev->desc_nr = choice;
2117 } else {
2118 if (find_rdev_nr(mddev, rdev->desc_nr))
2119 return -EBUSY;
2120 }
2121 if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
2122 printk(KERN_WARNING "md: %s: array is limited to %d devices\n",
2123 mdname(mddev), mddev->max_disks);
2124 return -EBUSY;
2125 }
2126 bdevname(rdev->bdev,b);
2127 while ( (s=strchr(b, '/')) != NULL)
2128 *s = '!';
2129
2130 rdev->mddev = mddev;
2131 printk(KERN_INFO "md: bind<%s>\n", b);
2132
2133 if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
2134 goto fail;
2135
2136 ko = &part_to_dev(rdev->bdev->bd_part)->kobj;
2137 if (sysfs_create_link(&rdev->kobj, ko, "block"))
2138 /* failure here is OK */;
2139 rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
2140
2141 list_add_rcu(&rdev->same_set, &mddev->disks);
2142 bd_link_disk_holder(rdev->bdev, mddev->gendisk);
2143
2144 /* May as well allow recovery to be retried once */
2145 mddev->recovery_disabled++;
2146
2147 return 0;
2148
2149 fail:
2150 printk(KERN_WARNING "md: failed to register dev-%s for %s\n",
2151 b, mdname(mddev));
2152 return err;
2153 }
2090行,检查是否磁盘已经加入阵列了,加过就不必重复添加。
2094-2105行,比较磁盘大小,记录最小的磁盘空间。
2111行,desc_nr分配,这个号只描述加入阵列的早晚。
2130行,建立struct md_rdev到mddev的关联。
2133-2139行,建立sysfs相关状态和链接。
2141行,建立mddev到struct md_rdev的关联。
add_new_disk就这么快结束了,简单地说就是创建struct md_rdev结构并与struct mddev结构之间创建联系。第三个命令字RUN_ARRAY的处理过程具有重要的意义,并且其过程不是三言两语能够说完的,我们把该命令字处理流程放到下一个小节单独来讲。
md源代码解析-part4
运行阵列意味着阵列经历从无到有,建立了作为一个raid应有的属性(如同步重建),并为随后的读写做好的铺垫。那么运行阵列的时候到底做了哪些事情,让原来的磁盘像变形金刚一样组成一个新的巨无霸。现在就来看阵列运行处理流程:
5158 static int do_md_run(struct mddev *mddev)
5159 {
5160 int err;
5161
5162 err = md_run(mddev);
5163 if (err)
5164 goto out;
5165 err = bitmap_load(mddev);
5166 if (err) {
5167 bitmap_destroy(mddev);
5168 goto out;
5169 }
5170
5171 md_wakeup_thread(mddev->thread);
5172 md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */5173
5174 set_capacity(mddev->gendisk, mddev->array_sectors);
5175 revalidate_disk(mddev->gendisk);
5176 mddev->changed = 1;
5177 kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
5178 out:
5179 return err;
5180 }
如果说运行阵列的过程是一本书,那么这个函数就是这本书的目录,每一个目录中都隐含着一个深刻的故事。
5162行,md_run运行阵列,这个函数比较长,我们按一段一段来分析:
4956 int md_run(struct mddev *mddev)
4957 {
4958 int err;
4959 struct md_rdev *rdev;
4960 struct md_personality *pers;
4961
4962 if (list_empty(&mddev->disks))
4963 /* cannot run an array with no devices.. */
4964 return -EINVAL;
4965
4966 if (mddev->pers)
4967 return -EBUSY;
4968 /* Cannot run until previous stop completes properly */
4969 if (mddev->sysfs_active)
4970 return -EBUSY;
4971
4972 /*
4973 * Analyze all RAID superblock(s)
4974 */
4975 if (!mddev->raid_disks) {
4976 if (!mddev->persistent)
4977 return -EINVAL;
4978 analyze_sbs(mddev);
4979 }
4962-4969行检查,阵列还没运行,所以直接到4978行。
4978行,analyze_sbs,分析超级块,依次分析每一个磁盘的超级块,不符合阵列需求的磁盘将会被踢出阵列。
3310 static void analyze_sbs(struct mddev * mddev)
3311 {
3312 int i;
3313 struct md_rdev *rdev, *freshest, *tmp;
3314 char b[BDEVNAME_SIZE];
3315
3316 freshest = NULL;
3317 rdev_for_each_safe(rdev, tmp, mddev)
3318 switch (super_types[mddev->major_version].
3319 load_super(rdev, freshest, mddev->minor_version)) {
3320 case 1:
3321 freshest = rdev;
3322 break;
3323 case 0:
3324 break;
3325 default:
3326 printk( KERN_ERR \
3327 "md: fatal superblock inconsistency in %s"
3328 " -- removing from array\n",
3329 bdevname(rdev->bdev,b));
3330 kick_rdev_from_array(rdev);
3331 }
3332
3333
3334 super_types[mddev->major_version].
3335 validate_super(mddev, freshest);
3336
3337 i = 0;
3338 rdev_for_each_safe(rdev, tmp, mddev) {
3339 if (mddev->max_disks &&
3340 (rdev->desc_nr >= mddev->max_disks ||
3341 i > mddev->max_disks)) {
3342 printk(KERN_WARNING
3343 "md: %s: %s: only %d devices permitted\n",
3344 mdname(mddev), bdevname(rdev->bdev, b),
3345 mddev->max_disks);
3346 kick_rdev_from_array(rdev);
3347 continue;
3348 }
3349 if (rdev != freshest)
3350 if (super_types[mddev->major_version].
3351 validate_super(mddev, rdev)) {
3352 printk(KERN_WARNING "md: kicking non-fresh %s"
3353 " from array!\n",
3354 bdevname(rdev->bdev,b));
3355 kick_rdev_from_array(rdev);
3356 continue;
3357 }
3358 if (mddev->level == LEVEL_MULTIPATH) {
3359 rdev->desc_nr = i++;
3360 rdev->raid_disk = rdev->desc_nr;
3361 set_bit(In_sync, &rdev->flags);
3362 } else if (rdev->raid_disk >= (mddev->raid_disks - min(0, mddev->delta_disks))) {
3363 rdev->raid_disk = -1;
3364 clear_bit(In_sync, &rdev->flags);
3365 }
3366 }
3367 }
3316-3331行,依次对阵列中每一个磁盘加载超级块,如果是最新的超级块则保存对应的struct md_rdev在freshest指针中,如果是不符合条件的超级块,将会踢出阵列。3319行,我们用1.2版本的超级块,那么对应这里load_super为super_1_load函数,这个级函数就是把超块信息从磁盘读出来,然后保存在md_rdev->sb_page中。然而这个函数还额外做了一件事情,就是比较哪个磁盘的超级块最新,看函数原型:
1433 static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_version)
第一个参数就是要加载超级块的磁盘,第二个参数是目前为止最新的超级块,第一次比较时为空。当返回值为1时表示rdev为最新,当返回为0时表示rdfdev仍然为最新超级块,小于0表示非法超级块。
3330行,将非法超级块的磁盘踢出阵列。
3334行,对应的validate_super函数为super_1_validate,这个函数根据最新超级块信息初始化了阵列struct mddev信息,这略了不相关的if分支:里代码省
1600 static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1601 {
1602 struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
1603 __u64 ev1 = le64_to_cpu(sb->events);
1604
1605 rdev->raid_disk = -1;
1606 clear_bit(Faulty, &rdev->flags);
1607 clear_bit(In_sync, &rdev->flags);
1608 clear_bit(WriteMostly, &rdev->flags);
1609
1610 if (mddev->raid_disks == 0) {
1611 mddev->major_version = 1;
1612 mddev->patch_version = 0;
1613 mddev->external = 0;
1614 mddev->chunk_sectors = le32_to_cpu(sb->chunksize);
1615 mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
1616 mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
1617 mddev->level = le32_to_cpu(sb->level);
1618 mddev->clevel[0] = 0;
1619 mddev->layout = le32_to_cpu(sb->layout);
1620 mddev->raid_disks = le32_to_cpu(sb->raid_disks);
1621 mddev->dev_sectors = le64_to_cpu(sb->size);
1622 mddev->events = ev1;
1623 mddev->bitmap_info.offset = 0;
1624 mddev->bitmap_info.space = 0;
1625 /* Default location for bitmap is 1K after superblock
1626 * using 3K - total of 4K
1627 */
1628 mddev->bitmap_info.default_offset = 1024 >> 9;
1629 mddev->bitmap_info.default_space = (4096-1024) >> 9;
1630 mddev->reshape_backwards = 0;
1631
1632 mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
1633 memcpy(mddev->uuid, sb->set_uuid, 16);
1634
1635 mddev->max_disks = (4096-256)/2;
1636
1637 if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
1638 mddev->bitmap_info.file == NULL) {
1639 mddev->bitmap_info.offset =
1640 (__s32)le32_to_cpu(sb->bitmap_offset);
1641 /* Metadata doesn't record how much space is available.
1642 * For 1.0, we assume we can use up to the superblock
1643 * if before, else to 4K beyond superblock.
1644 * For others, assume no change is possible.
1645 */
1646 if (mddev->minor_version > 0)
1647 mddev->bitmap_info.space = 0;
1648 else if (mddev->bitmap_info.offset > 0)
1649 mddev->bitmap_info.space =
1650 8 - mddev->bitmap_info.offset;
1651 else
1652 mddev->bitmap_info.space =
1653 -mddev->bitmap_info.offset;
1654 }
1655
1656 if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
1657 mddev->reshape_position = le64_to_cpu(sb->reshape_position);
1658 mddev->delta_disks = le32_to_cpu(sb->delta_disks);
1659 mddev->new_level = le32_to_cpu(sb->new_level);
1660 mddev->new_layout = le32_to_cpu(sb->new_layout);
1661 mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
1662 if (mddev->delta_disks < 0 ||
1663 (mddev->delta_disks == 0 &&
1664 (le32_to_cpu(sb->feature_map)
1665 & MD_FEATURE_RESHAPE_BACKWARDS)))
1666 mddev->reshape_backwards = 1;
1667 } else {
1668 mddev->reshape_position = MaxSector;
1669 mddev->delta_disks = 0;
1670 mddev->new_level = mddev->level;
1671 mddev->new_layout = mddev->layout;
1672 mddev->new_chunk_sectors = mddev->chunk_sectors;
1673 }
1674
1675 }
...
1695 if (mddev->level != LEVEL_MULTIPATH) {
1696 int role;
1697 if (rdev->desc_nr < 0 ||
1698 rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
1699 role = 0xffff;
1700 rdev->desc_nr = -1;
1701 } else
1702 role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
1703 switch(role) {
1704 case 0xffff: /* spare */
1705 break;
1706 case 0xfffe: /* faulty */
1707 set_bit(Faulty, &rdev->flags);
1708 break;
1709 default:
1710 if ((le32_to_cpu(sb->feature_map) &
1711 MD_FEATURE_RECOVERY_OFFSET))
1712 rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
1713 else
1714 set_bit(In_sync, &rdev->flags);
1715 rdev->raid_disk = role;
1716 break;
1717 }
1718 if (sb->devflags & WriteMostly1)
1719 set_bit(WriteMostly, &rdev->flags);
1720 if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
1721 set_bit(Replacement, &rdev->flags);
1722 } else /* MULTIPATH are always insync */
1723 set_bit(In_sync, &rdev->flags);
1724
1725 return 0;
1726 }
1602行,获取磁盘对应的超级块信息。
1610行,if分支成立,进入初始化struct mddev结构体,就是将阵列磁盘中最新超级块信息赋给struct mddev。
1695行,设置rdev->raid_disk和rdev->recovery_offset信息,注意这里的role有几个特殊值,0xffff表示热备盘,0xfffe表示faulty盘。recovery_offset顾名思义就是已重建偏移,In_sync表示磁盘在同步状态,WriteMostly表示优先读只用于raid1阵列。
又回到analyze_sbs函数中,
3338行,这个循环遍历阵列所有磁盘,依次validate每一个磁盘。validate的作用就是给每一个磁盘定一个身份,到底是数据盘啊还是热备盘,当然还有些磁盘超级块信息检查不合格,要淘汰出阵列的。
3350行,再一次进入validate_super函数,不过上一次主要作用是初始化struct mddev信息,这一次主要鉴定磁盘身份信息。
1600 static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1601 {
1602 struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
1603 __u64 ev1 = le64_to_cpu(sb->events);
1604
1605 rdev->raid_disk = -1;
1606 clear_bit(Faulty, &rdev->flags);
1607 clear_bit(In_sync, &rdev->flags);
1608 clear_bit(WriteMostly, &rdev->flags);
1609
1610 if (mddev->raid_disks == 0) {
...
1675 } else if (mddev->pers == NULL) {
1676 /* Insist of good event counter while assembling, except for
1677 * spares (which don't need an event count) */
1678 ++ev1;
1679 if (rdev->desc_nr >= 0 &&
1680 rdev->desc_nr < le32_to_cpu(sb->max_dev) &&
1681 le16_to_cpu(sb->dev_roles[rdev->desc_nr]) < 0xfffe)
1682 if (ev1 < mddev->events)
1683 return -EINVAL;
1684 }
1695 if (mddev->level != LEVEL_MULTIPATH) {
1696 int role;
1697 if (rdev->desc_nr < 0 ||
1698 rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
1699 role = 0xffff;
1700 rdev->desc_nr = -1;
1701 } else
1702 role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
1703 switch(role) {
1704 case 0xffff: /* spare */
1705 break;
1706 case 0xfffe: /* faulty */
1707 set_bit(Faulty, &rdev->flags);
1708 break;
1709 default:
1710 if ((le32_to_cpu(sb->feature_map) &
1711 MD_FEATURE_RECOVERY_OFFSET))
1712 rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
1713 else
1714 set_bit(In_sync, &rdev->flags);
1715 rdev->raid_disk = role;
1716 break;
1717 }
1718 if (sb->devflags & WriteMostly1)
1719 set_bit(WriteMostly, &rdev->flags);
1720 if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
1721 set_bit(Replacement, &rdev->flags);
1722 } else /* MULTIPATH are always insync */
1723 set_bit(In_sync, &rdev->flags);
1724
1725 return 0;
1726 }
1610行,经过上一次struct mddev的初始化,这时raid_disk已经不为0了。
1675行,阵列还未运行起来,if成立进入分支。
1679行,先判断rdev->desc_nr是否合法,再判断是否为数据盘。
1682行,如果为数据盘,则判断时间戳是否为最新,不是最新的超级块,数据也不是最新的,就不能继续留在阵列中了。
1695行,设置rdev->raid_disk和rdev->recovery_offset信息。
analyze_sbs函数已经完成,返回到md_run函数中继续往下看:
4981 if (mddev->level != LEVEL_NONE)
4982 request_module("md-level-%d", mddev->level);
4983 else if (mddev->clevel[0])
4984 request_module("md-%s", mddev->clevel);
4985
4986 /*
4987 * Drop all container device buffers, from now on
4988 * the only valid external interface is through the md
4989 * device.
4990 */
4991 rdev_for_each(rdev, mddev) {
4992 if (test_bit(Faulty, &rdev->flags))
4993 continue;
4994 sync_blockdev(rdev->bdev);
4995 invalidate_bdev(rdev->bdev);
4996
4997 /* perform some consistency tests on the device.
4998 * We don't want the data to overlap the metadata,
4999 * Internal Bitmap issues have been handled elsewhere.
5000 */
5001 if (rdev->meta_bdev) {
5002 /* Nothing to check */;
5003 } else if (rdev->data_offset < rdev->sb_start) {
5004 if (mddev->dev_sectors &&
5005 rdev->data_offset + mddev->dev_sectors
5006 > rdev->sb_start) {
5007 printk("md: %s: data overlaps metadata\n",
5008 mdname(mddev));
5009 return -EINVAL;
5010 }
5011 } else {
5012 if (rdev->sb_start + rdev->sb_size/512
5013 > rdev->data_offset) {
5014 printk("md: %s: metadata overlaps data\n",
5015 mdname(mddev));
5016 return -EINVAL;
5017 }
5018 }
5019 sysfs_notify_dirent_safe(rdev->sysfs_state);
5020 }
4981-4984行,用于请求内核模块加载,因为linux内核模块可以按需加载,只有在需要该模块的时候再加载这样比较节约资源。
4991行,首先看注释,丢掉原磁盘设置的缓存,从现在开始这些磁盘只能由md访问了。就好像一个人要去当兵了,进入部队之后原来的身份证作废,新发了一个军人证,并且这个人以后只归部队管了,地方政府法庭不能管。
4992行,判断为faulty盘,坏盘就不用多费心思了。
4994行,刷磁盘buffer。
4995行,注销掉原来的身份证。
4997行,看注释,基本检查,看磁盘上数据部分与超级块是否overlap。rdev->data_offset表示磁盘上数据区开始偏移,rdev->sb_start表示超级块开始偏移,mddev->dev_sectors表示磁盘用于阵列的空间,rdev->sb_size表示超级块大小。
5019行,更新sysfs文件中磁盘state状态。
5022 if (mddev->bio_set == NULL)
5023 mddev->bio_set = bioset_create(BIO_POOL_SIZE, 0);
5024
5025 spin_lock(&pers_lock);
5026 pers = find_pers(mddev->level, mddev->clevel);
5027 if (!pers || !try_module_get(pers->owner)) {
5028 spin_unlock(&pers_lock);
5029 if (mddev->level != LEVEL_NONE)
5030 printk(KERN_WARNING "md: personality for level %d is not loaded!\n",
5031 mddev->level);
5032 else
5033 printk(KERN_WARNING "md: personality for level %s is not loaded!\n",
5034 mddev->clevel);
5035 return -EINVAL;
5036 }
5037 mddev->pers = pers;
5038 spin_unlock(&pers_lock);
5039 if (mddev->level != pers->level) {
5040 mddev->level = pers->level;
5041 mddev->new_level = pers->level;
5042 }
5043 strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
5044
5045 if (mddev->reshape_position != MaxSector &&
5046 pers->start_reshape == NULL) {
5047 /* This personality cannot handle reshaping... */
5048 mddev->pers = NULL;
5049 module_put(pers->owner);
5050 return -EINVAL;
5051 }
5052
5053 if (pers->sync_request) {
5054 /* Warn if this is a potentially silly
5055 * configuration.
5056 */
5057 char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
5058 struct md_rdev *rdev2;
5059 int warned = 0;
5060
5061 rdev_for_each(rdev, mddev)
5062 rdev_for_each(rdev2, mddev) {
5063 if (rdev < rdev2 &&
5064 rdev->bdev->bd_contains ==
5065 rdev2->bdev->bd_contains) {
5066 printk(KERN_WARNING
5067 "%s: WARNING: %s appears to be"
5068 " on the same physical disk as"
5069 " %s.\n",
5070 mdname(mddev),
5071 bdevname(rdev->bdev,b),
5072 bdevname(rdev2->bdev,b2));
5073 warned = 1;
5074 }
5075 }
5076
5077 if (warned)
5078 printk(KERN_WARNING
5079 "True protection against single-disk"
5080 " failure might be compromised.\n");
5081 }
5082
5083 mddev->recovery = 0;
5084 /* may be over-ridden by personality */
5085 mddev->resync_max_sectors = mddev->dev_sectors;
5086
5087 mddev->ok_start_degraded = start_dirty_degraded;
5088
5089 if (start_readonly && mddev->ro == 0)
5090 mddev->ro = 2; /* read-only, but switch on first write */
5022行,创建bio内存池,用于读写时克隆保存原始bio。
5026行,查找对应阵列级别的struct md_personality是否存在,经过我们在4982行的request_module之后,新加载的模块会调用register_md_personality函数注册struct md_personality结构体,所以这里可以找到需要的pers。
5037行,将找到的pers赋值给mddev->pers。
5053行,这个if分支用于检查阵列中是否有两个struct md_rdev位于同一物理磁盘上。因为创建阵列可以用分区来创建,所以这里需要检查一下。如果两个struct md_rdev位于同一物理磁盘上,导致阵列性能很差。既然要玩raid就没有必要那么小气嘛,直接用整个磁盘,没有必要用磁盘分区。
5083行,初始化阵列sync标记。
5085行,初始化阵列最大同步偏移。
5087行,是否自动运行降级的脏阵列。可别小看了简简单单的一行代码,却代表了一个raid5阵列很复杂的问题。当一个raid5/6为脏并且降级时,就可能有数据错误的风险。为脏就是校验盘数据未经过同步,再加上降级就表示这一条带数据无法通过重建来恢复。所以md就不直接去运行阵列,而是由系统管理员手动运行。然而如果根文件系统是建立在raid上的时候,就会导致系统无法启动,所以就提供一个内核模块参数start_dirty_degraded来控制强制运行这样的阵列。
但实际上情况并没有看起来那么严重,例如在一个raid5阵列上建立一个ext4文件系统,为脏部分代表阵列还没有同步,而没有同步的条带是没有文件存储在条带上的(如果存储代表已经写过,写过的条带是同步的),所以这个时候强制运行降级的脏阵列是没有问题的。
5089行,在很多用户的环境里,经常会遇到一个问题,就是系统重启之后查看cat /proc/mdstat目录下阵列resync=pending状态,解决这个问题有两个方法,一是使用命令mdadm --read-write /dev/md*,另一个是设置模块参数/sys/module/md_mod/parameters/start_ro为0。那么为什么要设置这样一个状态呢?代码作者neil brown,是为了解决在Debian系统启动时要做一个重要的事情,所以让阵列进入这个临时状态。还好只要有读写阵列就会自动解除这个临时状态,对于正常使用没有影响。
5092 err = mddev->pers->run(mddev);
5093 if (err)
5094 printk(KERN_ERR "md: pers->run() failed ...\n");
5095 else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) {
5096 WARN_ONCE(!mddev->external_size, "%s: default size too small,"
5097 " but 'external_size' not in effect?\n", __func__);
5098 printk(KERN_ERR
5099 "md: invalid array_size %llu > default size %llu\n",
5100 (unsigned long long)mddev->array_sectors / 2,
5101 (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2);
5102 err = -EINVAL;
5103 mddev->pers->stop(mddev);
5104 }
5105 if (err == 0 && mddev->pers->sync_request &&
5106 (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
5107 err = bitmap_create(mddev);
5108 if (err) {
5109 printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
5110 mdname(mddev), err);
5111 mddev->pers->stop(mddev);
5112 }
5113 }
5114 if (err) {
5115 module_put(mddev->pers->owner);
5116 mddev->pers = NULL;
5117 bitmap_destroy(mddev);
5118 return err;
5119 }
5092行,毫无疑问一看函数名就知道这一行是重中之重。这里选择raid1的run作示例,因为raid1是比较简单的,raid5和raid10在后面小节单独讲解。在讲run之前先简要说明一下mddev->pers->run是怎么调用到各个模块的run函数的?
首先每个模块初始化的时候都会调用到register_md_persionality函数,向md模块注册各自的struct md_personality结构,
7158 int register_md_personality(struct md_personality *p)
7159 {
7160 spin_lock(&pers_lock);
7161 list_add_tail(&p->list, &pers_list);
7162 printk(KERN_INFO "md: %s personality registered for level %d\n", p->name, p->level);
7163 spin_unlock(&pers_lock);
7164 return 0;
7165 }
在md_run函数中根据mddev->level初始化mddev->pers,如果level为1,这里pers就指向raid1的struct md_personality raid1_personality,那么这里调用的run函数也就是raid1中的run函数。接着看raid1中的run函数:
2769 static int run(struct mddev *mddev)
2770 {
2771 struct r1conf *conf;
2772 int i;
2773 struct md_rdev *rdev;
2774 int ret;
2775 bool discard_supported = false;
2776
2777 if (mddev->level != 1) {
2778 printk(KERN_ERR "md/raid1:%s: raid level not set to mirroring (%d)\n",
2779 mdname(mddev), mddev->level);
2780 return -EIO;
2781 }
2782 if (mddev->reshape_position != MaxSector) {
2783 printk(KERN_ERR "md/raid1:%s: reshape_position set but not supported\n",
2784 mdname(mddev));
2785 return -EIO;
2786 }
2787 /*
2788 * copy the already verified devices into our private RAID1
2789 * bookkeeping area. [whatever we allocate in run(),
2790 * should be freed in stop()]
2791 */
2792 if (mddev->private == NULL)
2793 conf = setup_conf(mddev);
2794 else
2795 conf = mddev->private;
2796
2797 if (IS_ERR(conf))
2798 return PTR_ERR(conf);
2799
2800 if (mddev->queue)
2801 blk_queue_max_write_same_sectors(mddev->queue, 0);
2802
2803 rdev_for_each(rdev, mddev) {
2804 if (!mddev->gendisk)
2805 continue;
2806 disk_stack_limits(mddev->gendisk, rdev->bdev,
2807 rdev->data_offset << 9);
2808 if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
2809 discard_supported = true;
2810 }
2811
2812 mddev->degraded = 0;
2813 for (i=0; i < conf->raid_disks; i++)
2814 if (conf->mirrors[i].rdev == NULL ||
2815 !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
2816 test_bit(Faulty, &conf->mirrors[i].rdev->flags))
2817 mddev->degraded++;
2818
2819 if (conf->raid_disks - mddev->degraded == 1)
2820 mddev->recovery_cp = MaxSector;
2821
2822 if (mddev->recovery_cp != MaxSector)
2823 printk(KERN_NOTICE "md/raid1:%s: not clean"
2824 " -- starting background reconstruction\n",
2825 mdname(mddev));
2826 printk(KERN_INFO
2827 "md/raid1:%s: active with %d out of %d mirrors\n",
2828 mdname(mddev), mddev->raid_disks - mddev->degraded,
2829 mddev->raid_disks);
2830
2831 /*
2832 * Ok, everything is just fine now
2833 */
2834 mddev->thread = conf->thread;
2835 conf->thread = NULL;
2836 mddev->private = conf;
2837
2838 md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
2839
2840 if (mddev->queue) {
2841 mddev->queue->backing_dev_info.congested_fn = raid1_congested;
2842 mddev->queue->backing_dev_info.congested_data = mddev;
2843 blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
2844
2845 if (discard_supported)
2846 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
2847 mddev->queue);
2848 else
2849 queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD,
2850 mddev->queue);
2851 }
2852
2853 ret = md_integrity_register(mddev);
2854 if (ret)
2855 stop(mddev);
2856 return ret;
2857 }
2777-2786行,基本检查。
2792行,域private未赋值,进入if分支。
2793行,配置raid1环境。俗话说,国有国法,家有家规。如果说struct mddev是国法,那么setup_conf要建立的struct r1conf就是家规了,同样对于raid5和raid10都有自己有家规struct r5conf和struct r10conf。struct mddev存放是所有阵列共同的属性,而各自struct r*conf存放是私有的属性,而这些私有属性就是为了管理好各自管辖的磁盘。进入setup_conf函数:
2648 static struct r1conf *setup_conf(struct mddev *mddev)
2649 {
2650 struct r1conf *conf;
2651 int i;
2652 struct raid1_info *disk;
2653 struct md_rdev *rdev;
2654 int err = -ENOMEM;
2655
2656 conf = kzalloc(sizeof(struct r1conf), GFP_KERNEL);
2657 if (!conf)
2658 goto abort;
2659
2660 conf->mirrors = kzalloc(sizeof(struct raid1_info)
2661 * mddev->raid_disks * 2,
2662 GFP_KERNEL);
2663 if (!conf->mirrors)
2664 goto abort;
2665
2666 conf->tmppage = alloc_page(GFP_KERNEL);
2667 if (!conf->tmppage)
2668 goto abort;
2669
2670 conf->poolinfo = kzalloc(sizeof(*conf->poolinfo), GFP_KERNEL);
2671 if (!conf->poolinfo)
2672 goto abort;
2673 conf->poolinfo->raid_disks = mddev->raid_disks * 2;
2674 conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
2675 r1bio_pool_free,
2676 conf->poolinfo);
2677 if (!conf->r1bio_pool)
2678 goto abort;
2679
2680 conf->poolinfo->mddev = mddev;
2681
2682 err = -EINVAL;
2683 spin_lock_init(&conf->device_lock);
2684 rdev_for_each(rdev, mddev) {
2685 struct request_queue *q;
2686 int disk_idx = rdev->raid_disk;
2687 if (disk_idx >= mddev->raid_disks
2688 || disk_idx < 0)
2689 continue;
2690 if (test_bit(Replacement, &rdev->flags))
2691 disk = conf->mirrors + mddev->raid_disks + disk_idx;
2692 else
2693 disk = conf->mirrors + disk_idx;
2694
2695 if (disk->rdev)
2696 goto abort;
2697 disk->rdev = rdev;
2698 q = bdev_get_queue(rdev->bdev);
2699 if (q->merge_bvec_fn)
2700 mddev->merge_check_needed = 1;
2701
2702 disk->head_position = 0;
2703 disk->seq_start = MaxSector;
2704 }
2705 conf->raid_disks = mddev->raid_disks;
2706 conf->mddev = mddev;
2707 INIT_LIST_HEAD(&conf->retry_list);
2708
2709 spin_lock_init(&conf->resync_lock);
2710 init_waitqueue_head(&conf->wait_barrier);
2711
2712 bio_list_init(&conf->pending_bio_list);
2713 conf->pending_count = 0;
2714 conf->recovery_disabled = mddev->recovery_disabled - 1;
2715
2716 err = -EIO;
2717 for (i = 0; i < conf->raid_disks * 2; i++) {
2718
2719 disk = conf->mirrors + i;
2720
2721 if (i < conf->raid_disks &&
2722 disk[conf->raid_disks].rdev) {
2723 /* This slot has a replacement. */
2724 if (!disk->rdev) {
2725 /* No original, just make the replacement
2726 * a recovering spare
2727 */
2728 disk->rdev =
2729 disk[conf->raid_disks].rdev;
2730 disk[conf->raid_disks].rdev = NULL;
2731 } else if (!test_bit(In_sync, &disk->rdev->flags))
2732 /* Original is not in_sync - bad */
2733 goto abort;
2734 }
2735
2736 if (!disk->rdev ||
2737 !test_bit(In_sync, &disk->rdev->flags)) {
2738 disk->head_position = 0;
2739 if (disk->rdev &&
2740 (disk->rdev->saved_raid_disk < 0))
2741 conf->fullsync = 1;
2742 }
2743 }
2744
2745 err = -ENOMEM;
2746 conf->thread = md_register_thread(raid1d, mddev, "raid1");
2747 if (!conf->thread) {
2748 printk(KERN_ERR
2749 "md/raid1:%s: couldn't allocate thread\n",
2750 mdname(mddev));
2751 goto abort;
2752 }
2753
2754 return conf;
2656-2680行,申请与读写相关的资源,后面讲读写的时候再深入。
2684行,对每个阵列中数据盘,在struct r1conf中建立关联,读写时用到。
2697行,建立struct r1conf到struct md_rdev关联。
2717行,磁盘replacement机制,这是阵列的高级特性,这里先不关注。
2746行,注册阵列处理线程。每个运行阵列都有这样的一个主线程,主要负责检查同步重建(只检查由另一线程负责具体处理),数据流处理。
小结一下,setup_conf函数主要作用是初始化struct r1conf,建立阵列数据流处理的上下文环境。
继续回到raid1的run函数中。
2803行,对阵列中每一个磁盘设置struct queue_limit,每个块设备都有一个struct queue_limit,表示块设备队列物理特性。这里主要作用是让磁盘请求队列根据阵列请求队列调整请求块大小和对齐。
2812-2817行,计算阵列降级磁盘数。
2834行,设置mddev->thread。
2836行,设置mddev->private为struct r1conf。
2838行,设置阵列大小。
2840-2851行,设置拥塞处理函数和请求合并函数。
2853行,块设备integrity,有兴趣可查看内核文档的integrity说明。
run函数就结束了,小结一下,run函数的主要作用是建立阵列读写的上下文环境,包括struct r1conf,阵列主线程等等。
继续回到md_run函数中。
5107行,创建阵列bitmap,具体过程在bitmap章节里再详细阅读。
接下来就是一些sysfs的显示和链接,最有欣赏价值的是mddev->safemode,什么是安全模式呢?没有写(包括同步和重建写)的时候就是安全模式,反之正在写的时候就不安全。因为对于有数据冗余的阵列来说,每一份数据都至少要写入两个物理磁盘中,在写的过程中程序异常或者系统掉电异常都会导致数据不一致,为了保证数据一致性,必须要在系统重启之后做全盘同步。然而全盘同步需要花费很长时间,bitmap的出现在一定程度上解决了这个问题,但却对阵列性能产生一定的消极作用。
经过了这么长的跋山涉水,终于又回到do_md_run的温暖怀抱了。这个函数不长,我们不厌其烦地再贴一次代码:
5158 static int do_md_run(struct mddev *mddev)
5159 {
5160 int err;
5161
5162 err = md_run(mddev);
5163 if (err)
5164 goto out;
5165 err = bitmap_load(mddev);
5166 if (err) {
5167 bitmap_destroy(mddev);
5168 goto out;
5169 }
5170
5171 md_wakeup_thread(mddev->thread);
5172 md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
5173
5174 set_capacity(mddev->gendisk, mddev->array_sectors);
5175 revalidate_disk(mddev->gendisk);
5176 mddev->changed = 1;
5177 kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
5178 out:
5179 return err;
5180 }
5165行,加载bitmap,同样留到bitmap章节再详解。
5171行,唤醒阵列主线程。
5172行,唤醒阵列同步线程。
5174行,设置虚拟gendisk磁盘大小。
5175行,运行磁盘,让磁盘为系统可见。
5176行,设置md改变标志。
5177行,上报磁盘信息到udev。
do_md_run完成,RUN_ARRAY命令也就执行完成了。
小结一下,do_md_run函数的作用就是向上虚拟一个块设备,向下包装磁盘,建立读写请求的通道,将对md设备的请求能够转发到磁盘上去。