linux内核奇遇记之md源代码解读之三

linux内核奇遇记之md源代码解读之三
转载请注明出处:http://blog.csdn.net/liumangxiong
这一节我们阅读阵列的创建过程。
按照常理出牌,我们到ioctl中找阵列创建命令,md对应的ioctl函数是md_ioctl,当找对应的cmd命令字时,却完全没有类似CREATE_ARRAY的命令,那么就说明md设备并不是通过ioctl函数来创建的。其实如果我们仔细阅读一下md_ioctl函数的原型就会发现其实创建md设备根本就不在这个地方,函数原型如下:
   
   
  1. 6303 static int md_ioctl(struct block_device *bdev, fmode_t mode,  
  2. 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:
   
   
  1. 36 /* ioctls */  
  2. 37   
  3. 38 /* status */  
  4. 39 #define RAID_VERSION            _IOR (MD_MAJOR, 0x10, mdu_version_t)  
  5. 40 #define GET_ARRAY_INFO          _IOR (MD_MAJOR, 0x11, mdu_array_info_t)  
  6. 41 #define GET_DISK_INFO           _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)  
  7. 42 #define PRINT_RAID_DEBUG        _IO (MD_MAJOR, 0x13)  
  8. 43 #define RAID_AUTORUN            _IO (MD_MAJOR, 0x14)  
  9. 44 #define GET_BITMAP_FILE         _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)  
  10. 45   
  11. 46 /* configuration */  
  12. 47 #define CLEAR_ARRAY             _IO (MD_MAJOR, 0x20)  
  13. 48 #define ADD_NEW_DISK            _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)  
  14. 49 #define HOT_REMOVE_DISK         _IO (MD_MAJOR, 0x22)  
  15. 50 #define SET_ARRAY_INFO          _IOW (MD_MAJOR, 0x23, mdu_array_info_t)  
  16. 51 #define SET_DISK_INFO           _IO (MD_MAJOR, 0x24)  
  17. 52 #define WRITE_RAID_INFO         _IO (MD_MAJOR, 0x25)  
  18. 53 #define UNPROTECT_ARRAY         _IO (MD_MAJOR, 0x26)  
  19. 54 #define PROTECT_ARRAY           _IO (MD_MAJOR, 0x27)  
  20. 55 #define HOT_ADD_DISK            _IO (MD_MAJOR, 0x28)  
  21. 56 #define SET_DISK_FAULTY         _IO (MD_MAJOR, 0x29)  
  22. 57 #define HOT_GENERATE_ERROR      _IO (MD_MAJOR, 0x2a)  
  23. 58 #define SET_BITMAP_FILE         _IOW (MD_MAJOR, 0x2b, int)  
  24. 59   
  25. 60 /* usage */  
  26. 61 #define RUN_ARRAY               _IOW (MD_MAJOR, 0x30, mdu_param_t)  
  27. 62 /*  0x31 was START_ARRAY  */  
  28. 63 #define STOP_ARRAY              _IO (MD_MAJOR, 0x32)  
  29. 64 #define STOP_ARRAY_RO           _IO (MD_MAJOR, 0x33)  
  30. 65 #define RESTART_ARRAY_RW        _IO (MD_MAJOR, 0x34)  
这个文件为什么不放在md目录而放在include目录下?是因为文件里的内容是用户态跟内核态共用的,如果是内核态单独用的就没有必要放在这里了。
对于阵列的创建流程,最关心的命令字有:
SET_ARRAY_INFO  设置阵列信息
ADD_NEW_DISK     添加磁盘到阵列
RUN_ARRAY           运行阵列
首先看设置阵列信息,这个函数是这三个函数中最简单的一个:
   
   
  1. 6000 /* 
  2. 6001  * set_array_info is used two different ways 
  3. 6002  * The original usage is when creating a new array. 
  4. 6003  * In this usage, raid_disks is > 0 and it together with 
  5. 6004  *  level, size, not_persistent,layout,chunksize determine the 
  6. 6005  *  shape of the array. 
  7. 6006  *  This will always create an array with a type-0.90.0 superblock. 
  8. 6007  * The newer usage is when assembling an array. 
  9. 6008  *  In this case raid_disks will be 0, and the major_version field is 
  10. 6009  *  use to determine which style super-blocks are to be found on the devices. 
  11. 6010  *  The minor and patch _version numbers are also kept incase the 
  12. 6011  *  super_block handler wishes to interpret them. 
  13. 6012  */  
  14. 6013 static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)  
  15. 6014 {  
  16. 6015   
  17. 6016         if (info->raid_disks == 0) {  
  18. 6017                 /* just setting version number for superblock loading */  
  19. 6018                 if (info->major_version < 0 ||  
  20. 6019                     info->major_version >= ARRAY_SIZE(super_types) ||  
  21. 6020                     super_types[info->major_version].name == NULL) {  
  22. 6021                         /* maybe try to auto-load a module? */  
  23. 6022                         printk(KERN_INFO   
  24. 6023                                 "md: superblock version %d not known\n",  
  25. 6024                                 info->major_version);  
  26. 6025                         return -EINVAL;  
  27. 6026                 }  
  28. 6027                 mddev->major_version = info->major_version;  
  29. 6028                 mddev->minor_version = info->minor_version;  
  30. 6029                 mddev->patch_version = info->patch_version;  
  31. 6030                 mddev->persistent = !info->not_persistent;  
  32. 6031                 /* ensure mddev_put doesn't delete this now that there 
  33. 6032                  * is some minimal configuration. 
  34. 6033                  */  
  35. 6034                 mddev->ctime         = get_seconds();  
  36. 6035                 return 0;  
  37. 6036         }  
  38. 6037         mddev->major_version = MD_MAJOR_VERSION;  
  39. 6038         mddev->minor_version = MD_MINOR_VERSION;  
  40. 6039         mddev->patch_version = MD_PATCHLEVEL_VERSION;  
  41. 6040         mddev->ctime         = get_seconds();  
  42. 6041   
  43. 6042         mddev->level         = info->level;  
  44. 6043         mddev->clevel[0]     = 0;  
  45. 6044         mddev->dev_sectors   = 2 * (sector_t)info->size;  
  46. 6045         mddev->raid_disks    = info->raid_disks;  
  47. 6046         /* don't set md_minor, it is determined by which /dev/md* was 
  48. 6047          * openned 
  49. 6048          */  
  50. 6049         if (info->state & (1<<MD_SB_CLEAN))  
  51. 6050                 mddev->recovery_cp = MaxSector;  
  52. 6051         else  
  53. 6052                 mddev->recovery_cp = 0;  
  54. 6053         mddev->persistent    = ! info->not_persistent;  
  55. 6054         mddev->external      = 0;  
  56. 6055   
  57. 6056         mddev->layout        = info->layout;  
  58. 6057         mddev->chunk_sectors = info->chunk_size >> 9;  
  59. 6058   
  60. 6059         mddev->max_disks     = MD_SB_DISKS;  
  61. 6060   
  62. 6061         if (mddev->persistent)  
  63. 6062                 mddev->flags         = 0;  
  64. 6063         set_bit(MD_CHANGE_DEVS, &mddev->flags);  
  65. 6064   
  66. 6065         mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;  
  67. 6066         mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);  
  68. 6067         mddev->bitmap_info.offset = 0;  
  69. 6068   
  70. 6069         mddev->reshape_position = MaxSector;  
  71. 6070   
  72. 6071         /* 
  73. 6072          * Generate a 128 bit UUID 
  74. 6073          */  
  75. 6074         get_random_bytes(mddev->uuid, 16);  
  76. 6075   
  77. 6076         mddev->new_level = mddev->level;  
  78. 6077         mddev->new_chunk_sectors = mddev->chunk_sectors;  
  79. 6078         mddev->new_layout = mddev->layout;  
  80. 6079         mddev->delta_disks = 0;  
  81. 6080         mddev->reshape_backwards = 0;  
  82. 6081   
  83. 6082         return 0;  
  84. 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对应的处理函数:
[cpp]  view plain  copy
  1. 5672 static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)  
  2. 5673 {  
  3. 5674         char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];  
  4. 5675         struct md_rdev *rdev;  
  5. 5676         dev_t dev = MKDEV(info->major,info->minor);  
  6. 5677  
  7. 5678         if (info->major != MAJOR(dev) || info->minor != MINOR(dev))  
  8. 5679                 return -EOVERFLOW;  
  9. 5680  
  10. 5681         if (!mddev->raid_disks) {  
  11. 5682                 int err;  
  12. 5683                 /* expecting a device which has a superblock */  
  13. 5684                 rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);  
  14. 5685                 if (IS_ERR(rdev)) {  
  15. 5686                         printk(KERN_WARNING  
  16. 5687                                 "md: md_import_device returned %ld\n",  
  17. 5688                                 PTR_ERR(rdev));  
  18. 5689                         return PTR_ERR(rdev);  
  19. 5690                 }  
  20. 5691                 if (!list_empty(&mddev->disks)) {  
  21. 5692                         struct md_rdev *rdev0  
  22. 5693                                 = list_entry(mddev->disks.next,  
  23. 5694                                              struct md_rdev, same_set);  
  24. 5695                         err = super_types[mddev->major_version]  
  25. 5696                                 .load_super(rdev, rdev0, mddev->minor_version);  
  26. 5697                         if (err < 0) {  
  27. 5698                                 printk(KERN_WARNING  
  28. 5699                                         "md: %s has different UUID to %s\n",  
  29. 5700                                         bdevname(rdev->bdev,b),  
  30. 5701                                         bdevname(rdev0->bdev,b2));  
  31. 5702                                 export_rdev(rdev);  
  32. 5703                                 return -EINVAL;  
  33. 5704                         }  
  34. 5705                 }  
  35. 5706                 err = bind_rdev_to_array(rdev, mddev);  
  36. 5707                 if (err)  
  37. 5708                         export_rdev(rdev);  
  38. 5709                 return err;  
  39. 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结构,继续跟入到函数中:
   
   
  1. 3236 /* 
  2. 3237  * Import a device. If 'super_format' >= 0, then sanity check the superblock 
  3. 3238  * 
  4. 3239  * mark the device faulty if: 
  5. 3240  * 
  6. 3241  *   - the device is nonexistent (zero size) 
  7. 3242  *   - the device has no valid superblock 
  8. 3243  * 
  9. 3244  * a faulty rdev _never_ has rdev->sb set. 
  10. 3245  */  
  11. 3246 static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)  
  12. 3247 {  
  13. 3248         char b[BDEVNAME_SIZE];  
  14. 3249         int err;  
  15. 3250         struct md_rdev *rdev;  
  16. 3251         sector_t size;  
  17. 3252   
  18. 3253         rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);  
  19. 3254         if (!rdev) {  
  20. 3255                 printk(KERN_ERR "md: could not alloc mem for new device!\n");  
  21. 3256                 return ERR_PTR(-ENOMEM);  
  22. 3257         }  
  23. 3258   
  24. 3259         err = md_rdev_init(rdev);  
  25. 3260         if (err)  
  26. 3261                 goto abort_free;  
  27. 3262         err = alloc_disk_sb(rdev);  
  28. 3263         if (err)  
  29. 3264                 goto abort_free;  
  30. 3265   
  31. 3266         err = lock_rdev(rdev, newdev, super_format == -2);  
  32. 3267         if (err)  
  33. 3268                 goto abort_free;  
  34. 3269   
  35. 3270         kobject_init(&rdev->kobj, &rdev_ktype);  
  36. 3271   
  37. 3272         size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;  
  38. 3273         if (!size) {  
  39. 3274                 printk(KERN_WARNING   
  40. 3275                         "md: %s has zero or unknown size, marking faulty!\n",  
  41. 3276                         bdevname(rdev->bdev,b));  
  42. 3277                 err = -EINVAL;  
  43. 3278                 goto abort_free;  
  44. 3279         }  
  45. 3280   
  46. 3281         if (super_format >= 0) {  
  47. 3282                 err = super_types[super_format].  
  48. 3283                         load_super(rdev, NULL, super_minor);  
  49. 3284                 if (err == -EINVAL) {  
  50. 3285                         printk(KERN_WARNING  
  51. 3286                                 "md: %s does not have a valid v%d.%d "  
  52. 3287                                "superblock, not importing!\n",  
  53. 3288                                 bdevname(rdev->bdev,b),  
  54. 3289                                super_format, super_minor);  
  55. 3290                         goto abort_free;  
  56. 3291                 }  
  57. 3292                 if (err < 0) {  
  58. 3293                         printk(KERN_WARNING   
  59. 3294                                 "md: could not read %s's sb, not importing!\n",  
  60. 3295                                 bdevname(rdev->bdev,b));  
  61. 3296                         goto abort_free;  
  62. 3297                 }  
  63. 3298         }  
  64. 3299         if (super_format == -1)  
  65. 3300                 /* hot-add for 0.90, or non-persistent: so no badblocks */  
  66. 3301                 rdev->badblocks.shift = -1;  
  67. 3302   
  68. 3303         return rdev;  
  69. 3304   
  70. 3305 abort_free:  
  71. 3306         if (rdev->bdev)  
  72. 3307                 unlock_rdev(rdev);  
  73. 3308         md_rdev_clear(rdev);  
  74. 3309         kfree(rdev);  
  75. 3310         return ERR_PTR(err);  
  76. 3311 }  
3252行,创建一个struct md_rdev结构体。
3259行,初始化struct md_rdev结构体。
3262行,申请一个page页,用于存放磁盘超级块信息。
3266行,对磁盘加锁,防止被其他程序操作如mount, 分区等。
3270行,初始化struct md_rdev磁盘kobject结构。
3272行,读磁盘大小,判断是否合法。
3281行,阵列超级块是1.2版本的,进入if分支。
3282行,读入阵列超级块信息,具体调用的函数是:
   
   
  1. 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结构之间的联系,进函数:
[cpp]  view plain  copy
  1. 2077 static int bind_rdev_to_array(struct md_rdev * rdev, struct mddev * mddev)  
  2. 2078 {  
  3. 2079         char b[BDEVNAME_SIZE];  
  4. 2080         struct kobject *ko;  
  5. 2081         char *s;  
  6. 2082         int err;  
  7. 2083   
  8. 2084         if (rdev->mddev) {  
  9. 2085                 MD_BUG();  
  10. 2086                 return -EINVAL;  
  11. 2087         }  
  12. 2088   
  13. 2089         /* prevent duplicates */  
  14. 2090         if (find_rdev(mddev, rdev->bdev->bd_dev))  
  15. 2091                 return -EEXIST;  
  16. 2092   
  17. 2093         /* make sure rdev->sectors exceeds mddev->dev_sectors */  
  18. 2094         if (rdev->sectors && (mddev->dev_sectors == 0 ||  
  19. 2095                         rdev->sectors < mddev->dev_sectors)) {  
  20. 2096                 if (mddev->pers) {  
  21. 2097                         /* Cannot change size, so fail 
  22. 2098                          * If mddev->level <= 0, then we don't care 
  23. 2099                          * about aligning sizes (e.g. linear) 
  24. 2100                          */  
  25. 2101                         if (mddev->level > 0)  
  26. 2102                                 return -ENOSPC;  
  27. 2103                 } else  
  28. 2104                         mddev->dev_sectors = rdev->sectors;  
  29. 2105         }  
  30. 2106   
  31. 2107         /* Verify rdev->desc_nr is unique. 
  32. 2108          * If it is -1, assign a free number, else 
  33. 2109          * check number is not in use 
  34. 2110          */  
  35. 2111         if (rdev->desc_nr < 0) {  
  36. 2112                 int choice = 0;  
  37. 2113                 if (mddev->pers) choice = mddev->raid_disks;  
  38. 2114                 while (find_rdev_nr(mddev, choice))  
  39. 2115                         choice++;  
  40. 2116                 rdev->desc_nr = choice;  
  41. 2117         } else {  
  42. 2118                 if (find_rdev_nr(mddev, rdev->desc_nr))  
  43. 2119                         return -EBUSY;  
  44. 2120         }  
  45. 2121         if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {  
  46. 2122                 printk(KERN_WARNING "md: %s: array is limited to %d devices\n",  
  47. 2123                        mdname(mddev), mddev->max_disks);  
  48. 2124                 return -EBUSY;  
  49. 2125         }  
  50. 2126         bdevname(rdev->bdev,b);  
  51. 2127         while ( (s=strchr(b, '/')) != NULL)  
  52. 2128                 *s = '!';  
  53. 2129   
  54. 2130         rdev->mddev = mddev;  
  55. 2131         printk(KERN_INFO "md: bind<%s>\n", b);  
  56. 2132   
  57. 2133         if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))  
  58. 2134                 goto fail;  
  59. 2135   
  60. 2136         ko = &part_to_dev(rdev->bdev->bd_part)->kobj;  
  61. 2137         if (sysfs_create_link(&rdev->kobj, ko, "block"))  
  62. 2138                 /* failure here is OK */;  
  63. 2139         rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");  
  64. 2140   
  65. 2141         list_add_rcu(&rdev->same_set, &mddev->disks);  
  66. 2142         bd_link_disk_holder(rdev->bdev, mddev->gendisk);  
  67. 2143   
  68. 2144         /* May as well allow recovery to be retried once */  
  69. 2145         mddev->recovery_disabled++;  
  70. 2146   
  71. 2147         return 0;  
  72. 2148   
  73. 2149  fail:  
  74. 2150         printk(KERN_WARNING "md: failed to register dev-%s for %s\n",  
  75. 2151                b, mdname(mddev));  
  76. 2152         return err;  
  77. 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的处理过程具有重要的意义,并且其过程不是三言两语能够说完的,我们把该命令字处理流程放到下一个小节单独来讲。
转载请注明出处:http://blog.csdn.net/liumangxiong
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值