linux内核奇遇记之md源代码解读之六
转载请注明出处:http://blog.csdn.net/liumangxiong
raid10的run函数与raid5的run函数最大区别在于setup_conf,那就直接深入核心:
[cpp] view plaincopy
  1. 3540 static struct r10conf *setup_conf(struct mddev *mddev)
  2. 3541 {
  3. 3542         struct r10conf *conf = NULL;
  4. 3543         int err = -EINVAL;
  5. 3544         struct geom geo;
  6. 3545         int copies;
  7. 3546
  8. 3547         copies = setup_geo(&geo, mddev, geo_new);
  9. 3548
  10. 3549         if (copies == -2) {
  11. 3550                 printk(KERN_ERR "md/raid10:%s: chunk size must be "
  12. 3551                        "at least PAGE_SIZE(%ld) and be a power of 2.\n",
  13. 3552                        mdname(mddev), PAGE_SIZE);
  14. 3553                 goto out;
  15. 3554         }
  16. 3555
  17. 3556         if (copies < 2 || copies > mddev->raid_disks) {
  18. 3557                 printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
  19. 3558                        mdname(mddev), mddev->new_layout);
  20. 3559                 goto out;
  21. 3560         }
  22. 3561
  23. 3562         err = -ENOMEM;
  24. 3563         conf = kzalloc(sizeof(struct r10conf), GFP_KERNEL);
  25. 3564         if (!conf)
  26. 3565                 goto out;
  27. 3566
  28. 3567         /* FIXME calc properly */
  29. 3568         conf->mirrors = kzalloc(sizeof(struct raid10_info)*(mddev->raid_disks +
  30. 3569                                                             max(0,-mddev->delta_disks)),
  31. 3570                                 GFP_KERNEL);
  32. 3571         if (!conf->mirrors)
  33. 3572                 goto out;
  34. 3573
  35. 3574         conf->tmppage = alloc_page(GFP_KERNEL);
  36. 3575         if (!conf->tmppage)
  37. 3576                 goto out;
  38. 3577
  39. 3578         conf->geo = geo;
  40. 3579         conf->copies = copies;
  41. 3580         conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
  42. 3581                                            r10bio_pool_free, conf);
  43. 3582         if (!conf->r10bio_pool)
  44. 3583                 goto out;
  45. 3584
  46. 3585         calc_sectors(conf, mddev->dev_sectors);
  47. 3586         if (mddev->reshape_position == MaxSector) {
  48. 3587                 conf->prev = conf->geo;
  49. 3588                 conf->reshape_progress = MaxSector;
  50. 3589         } else {
  51. 3590                 if (setup_geo(&conf->prev, mddev, geo_old) != conf->copies) {
  52. 3591                         err = -EINVAL;
  53. 3592                         goto out;
  54. 3593                 }
  55. 3594                 conf->reshape_progress = mddev->reshape_position;
  56. 3595                 if (conf->prev.far_offset)
  57. 3596                         conf->prev.stride = 1 << conf->prev.chunk_shift;
  58. 3597                 else
  59. 3598                         /* far_copies must be 1 */
  60. 3599                         conf->prev.stride = conf->dev_sectors;
  61. 3600         }
  62. 3601         spin_lock_init(&conf->device_lock);
  63. 3602         INIT_LIST_HEAD(&conf->retry_list);
  64. 3603
  65. 3604         spin_lock_init(&conf->resync_lock);
  66. 3605         init_waitqueue_head(&conf->wait_barrier);
  67. 3606
  68. 3607         conf->thread = md_register_thread(raid10d, mddev, "raid10");
  69. 3608         if (!conf->thread)
  70. 3609                 goto out;
  71. 3610
  72. 3611         conf->mddev = mddev;
  73. 3612         return conf;

3547行,设置raid10布局,这个函数代码很简单,但意义很重要,特别是在处理读写流程里要对这个布局十分清楚。看setup_geo函数:

[cpp] view plaincopy
  1. 3498 enum geo_type {geo_new, geo_old, geo_start};
  2. 3499 static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
  3. 3500 {
  4. 3501         int nc, fc, fo;
  5. 3502         int layout, chunk, disks;
  6. 3503         switch (new) {
  7. 3504         case geo_old:
  8. 3505                 layout = mddev->layout;
  9. 3506                 chunk = mddev->chunk_sectors;
  10. 3507                 disks = mddev->raid_disks - mddev->delta_disks;
  11. 3508                 break;
  12. 3509         case geo_new:
  13. 3510                 layout = mddev->new_layout;
  14. 3511                 chunk = mddev->new_chunk_sectors;
  15. 3512                 disks = mddev->raid_disks;
  16. 3513                 break;
  17. 3514         default: /* avoid 'may be unused' warnings */
  18. 3515         case geo_start: /* new when starting reshape - raid_disks not
  19. 3516                          * updated yet. */
  20. 3517                 layout = mddev->new_layout;
  21. 3518                 chunk = mddev->new_chunk_sectors;
  22. 3519                 disks = mddev->raid_disks + mddev->delta_disks;
  23. 3520                 break;
  24. 3521         }
  25. 3522         if (layout >> 18)
  26. 3523                 return -1;
  27. 3524         if (chunk < (PAGE_SIZE >> 9) ||
  28. 3525             !is_power_of_2(chunk))
  29. 3526                 return -2;
  30. 3527         nc = layout & 255;
  31. 3528         fc = (layout >> 8) & 255;
  32. 3529         fo = layout & (1<<16);
  33. 3530         geo->raid_disks = disks;
  34. 3531         geo->near_copies = nc;
  35. 3532         geo->far_copies = fc;
  36. 3533         geo->far_offset = fo;
  37. 3534         geo->far_set_size = (layout & (1<<17)) ? disks / fc : disks;
  38. 3535         geo->chunk_mask = chunk - 1;
  39. 3536         geo->chunk_shift = ffz(~chunk);
  40. 3537         return nc*fc;
  41. 3538 }
raid10有近拷贝和远拷贝的设置,简单地说,近拷贝就是组成raid1的镜像磁盘数,远拷贝就是每个磁盘划分为几部分存镜像数据。
3503行,这里传进来的参数是geo_new,转到3509行。
3510行,raid10的layout,默认是0x102,即near_copies=2, far_copies=1。
3511行,chunk size。
3512行,数据盘个数。
3522-3526行,参数合法性检查。
3527行,计算near_copies。
3528行,计算far_copies。
3529行,计算far_offset。
3537行,返回拷贝数。
从上面的代码可以知道,raid10每一份可以有nc*fc份拷贝,但实际应用中考虑到磁盘的利用率,一般采用nc=2, fc=1。
回到setup_conf函数中,
3563行,申请struct r10conf内存空间。
3568行,申请struct raid10_info内存空间。
3574行,申请一个page页,用于读磁盘的临时空间。
3579行,设置数据拷贝数。
3580行,创建struct r10bio内存池,那为什么要有这样一个新的bio呢?原因是raid10大多数情况下io流分二个步骤,例如写同一份数据到两个磁盘,重建时先读数据再把数据写到另一个磁盘上,所以需要一个大的bio来跟踪io流过程。
3585行,计算磁盘实际用于阵列条带的扇区数和阵列存放远拷贝的跨度大小。假设我们用整个磁盘空间创建阵列raid10,但是由于每个磁盘空间大小有差别,阵列会按最小的磁盘空间来创建,这里实际用于阵列的磁盘空间将小于磁盘空间。再次,如果磁盘空间不是整数倍条块大小,这时多余部分还会被空闲出来。同样地,如果raid10远拷贝为2,这时磁盘条块数不能整除3,那么又有一部分磁盘空间空闲出来。正是因为如此,conf->dev_sectors会小于等于mddev->dev_sectors。理解了这些,那么看calc_sectors函数就容易了:
[cpp] view plaincopy
  1. 3468 static void calc_sectors(struct r10conf *conf, sector_t size)
  2. 3469 {
  3. 3470         /* Calculate the number of sectors-per-device that will
  4. 3471          * actually be used, and set conf->dev_sectors and
  5. 3472          * conf->stride
  6. 3473          */
  7. 3474
  8. 3475         size = size >> conf->geo.chunk_shift;
  9. 3476         sector_div(size, conf->geo.far_copies);
  10. 3477         size = size * conf->geo.raid_disks;
  11. 3478         sector_div(size, conf->geo.near_copies);
  12. 3479         /* 'size' is now the number of chunks in the array */
  13. 3480         /* calculate "used chunks per device" */
  14. 3481         size = size * conf->copies;
  15. 3482
  16. 3483         /* We need to round up when dividing by raid_disks to
  17. 3484          * get the stride size.
  18. 3485          */
  19. 3486         size = DIV_ROUND_UP_SECTOR_T(size, conf->geo.raid_disks);
  20. 3487
  21. 3488         conf->dev_sectors = size << conf->geo.chunk_shift;
  22. 3489
  23. 3490         if (conf->geo.far_offset)
  24. 3491                 conf->geo.stride = 1 << conf->geo.chunk_shift;
  25. 3492         else {
  26. 3493                 sector_div(size, conf->geo.far_copies);
  27. 3494                 conf->geo.stride = size << conf->geo.chunk_shift;
  28. 3495         }
  29. 3496 }
3470行,计算每个磁盘实际使用扇区数,并设置conf->dev_sectors和conf->stride。stride是什么意思呢?大步,跨幅。就是同一磁盘上每个far_copies之间的距离,这里有两个可能,一是远拷贝数据间隔存放,一是远拷贝数据相邻存放。conf->geo.far_offset不为0时表示相邻存放,为0时表示间隔存放,间隔多远呢?就由conf->geo.stride决定。
3475行,函数传入参数size为磁盘空间大小,这里转换为条块数。
3476行,除以远拷贝数,转换为单份数据空间大小。
3477-3478行,乘以数据盘数,再除以近拷贝数,转换为总数据空间大小(没有拷贝)。
3481行,乘以拷贝数,可用阵列空间大小。
3486行,除以数据盘数,每个磁盘用于阵列的实际使用空间大小。
3488行,乘以条块大小,单位由条块数转换为扇区数。
这里为什么又乘又除的呢?这就好比有一张长方形的纸,我们要用这张纸分出四个最大的正方形出来,那么就选个角按45度折起来,然后把之外的部分裁掉。
3490行,远拷贝是相邻存放的,那么跨幅就是一个条块。
3493行,远拷贝是间隔存放的,那么跨幅就是磁盘实际使用空间大小size除以远拷贝数。
再次返回到setup_conf函数中。
3586行,没有reshape操作,reshape等于MaxSector。
3601-3611行,conf初始化。
3607行,创建raid10d主线程。
这样setup_conf函数就结束了,run函数剩余部分都是按步就班。
小结一下,各种级别阵列运行函数建立与磁盘之间的关联,建立数据流通道,申请数据流所需要的资源。不同的是,由于阵列级别差异,阵列与磁盘之间关联不一样,申请资源也不一样。
阵列已经运行起来了,那么第一件事情就是同步了。下一节开始介绍阵列同步。
转载请注明出处:http://blog.csdn.net/liumangxiong

linux内核奇遇记之md源代码解读之六相关推荐

  1. linux内核奇遇记之md源代码解读之八阵列同步二

    linux内核奇遇记之md源代码解读之八阵列同步二 转载请注明出处:http://blog.csdn.net/liumangxiong 在上一小节里讲到启动同步线程: 7824 mddev->s ...

  2. linux内核奇遇记之md源代码解读之十二raid读写

    linux内核奇遇记之md源代码解读之十二raid读写 转载请注明出处:http://blog.csdn.net/liumangxiong 我们都知道,对一个linux块设备来说,都有一个对应的请求队 ...

  3. 复制linux内核,linux内核写时复制机制源代码解读

    作者简介 写时复制技术(一下简称COW)是linux内核比较重要的一种机制,我们都知道:父进程fork子进程的时候,子进程会和父进程会以只读的方式共享所有私有的可写页,当有一方将要写的时候会发生COW ...

  4. 高通linux内核目录,高通 android 源代码以及目标系统目录结构

    下面为高通android源代码结构 build/ – Build 环境建立和makefiles生成4 bionic/ – Android C 库 dalvik/ – Android Java 虚拟机 ...

  5. xilinx linux内核,Xilinx-Zynq Linux内核源码编译过程

    本文内容依据http://www.wiki.xilinx.com网址编写,编译所用操作系统为ubuntu 14 1.交叉编译环境的安装配置 2.uboot的编译 1)下载uboot源代码 下载uboo ...

  6. Linux内核调试方法【转】

    转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...

  7. Linux内核移植之一:内核源码结构与Makefile分析

    内容来自 韦东山<嵌入式Linux应用开发完全手册> 一.内核介绍 1.版本及其特点 Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如下面几行它们构成了Linu ...

  8. linux 内核移植和根文件系统的制作【转载】

    原文地址:http://www.cnblogs.com/hnrainll/archive/2011/06/09/2076214.html 1.1 Linux内核基础知识 在动手进行Linux内核移植之 ...

  9. linux内核源码lxr,配置glimpse与LXR读取linux内核源码

    配置glimpse与LXR读取linux内核源码 1.安装 源代码编译glimpse sudo apt-get install flex sudo apt-get install lxr 2.设置Ap ...

  10. zynq linux内核出错,Xilinx Zynq Linux内核源码编译过程

    1.交叉编译环境的安装配置 1) +Xilinx+Tools 2.uboot的编译 1)下载uboot源代码 下载uboot源代码,务必要下载tar.gz格式的文件,地址: https://githu ...

最新文章

  1. 学习Docker容器网络模型 - 搭建分布式Zookeeper集群
  2. 常见的水平居中布局方式
  3. v9更新栏目缓存提示PHP has encountered a Stack overflow解决方法
  4. mvdr波束形成原理_5G的“波束赋形”技术是什么东东?
  5. 群晖ffmpeg_群晖Video station支持DTS和EAC3
  6. 华为P50系列即将发布:麒麟9000E/9000处理器有戏?
  7. 我的 2020 总结:跌宕起伏
  8. Go语言中的单引号、双引号、反引号
  9. 百度换肤,表单全选案例
  10. 必看 | 机器视觉基础入门
  11. qpython3使用_用qpython3写一个最简单的发送短信的程序
  12. 模仿元气森林:为什么会是画虎画皮难画骨?
  13. 计算机学院考研动员大会,青春正当时,奋进当有为——学院顺利举办2018级考研动员大会...
  14. 概率论由相关性求数学期望和方差的公式_概率论与数理统计(马涛)第4章——数学期望与方差.ppt...
  15. 要想增加流量需要做的几点,淘宝运营新手必看的免费流量小知识
  16. 前端展示图片-处理图片拉伸
  17. 思岚科技Athena打破机器人底盘价格极限
  18. 图像处理中常用的彩色模型
  19. Hinton:胶囊网络的专利是我的了
  20. RISC-V 指令格式

热门文章

  1. putty+Xming使用方法
  2. android编译framework架包运行报错 (转)
  3. 程序开发基础学习五(json配置、解析文件,c++篇)
  4. 分布式通用爬虫管理平台Crawlab
  5. Azure实践之通过automation管理资产
  6. Picnic Planning
  7. SAS 146GB*8 RAID5数据恢复过程(HP 双循环)
  8. 互联网企业安全高级指南3.7 如何看待SDL
  9. php教程 TTP中GET与POST的区别
  10. java io 字符流操作工具类