源文件
linux/include/uapi/linux/raid/md_p.h
linux/include/uapi/linux/raid/md_u.h
linux/drivers/md/md.h
linux/drivers/md/md.c
md 是 multiple devices 的縮寫,實現了 MD RAID Framework。它將 RAID drivers 跟上層的 block layer 連接在一起,這樣可以通過 block layer 訪問到底層的 RAID drivers,比如 RAID1/RAID5 driver。同時它作為一個 RAID driver 之上的抽象層,也完成了大量的工作,比如對 superblock 的操作;當然,比較細節的工作還是需要由 RAID driver 自己來完成,畢竟不同 RAID driver 有自己的 RAID 算法需要實現。
md 對上層的接口定義在 md_fops 中:
static const struct block_device_operations md_fops = { .owner = THIS_MODULE, .open = md_open, .release = md_release, .ioctl = md_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = md_compat_ioctl, #endif .getgeo = md_getgeo, .media_changed = md_media_changed, .revalidate_disk = md_revalidate, };
struct mddev 表示陣列設備,struct md_rdev 表示陣列中的單個磁盤設備。md 通過結構 struct md_personality 定義了底層 RAID drivers 的接口,RAID driver 模塊只需要將自己的 md_pers 注冊到 pers_list 列表中,上層通過 md 就可以驅動底層 RAID driver 的具體操作。md 中的大量代碼也是操作這 3 個核心數據結構,還有支持大量 sysfs 系統文件的 show/store 函數。
所有的 active md 陣列鏈接到 all_mddevs 列表中。
關於 superblock
md 有自己的 superblock,存放關於磁盤陣列的元數據信息,比如 RAID level。不同版本的 superblock 有不同的格式,在磁盤上有不同的存放位置(https://raid.wiki.kernel.org/index.php/RAID_superblock_formats 和 linux/include/uapi/linux/raid/md_p.h)。缺省版本為 1.2
superblock 最初是由用戶態工具寫入的 mdadm。在內核態,md 可以對 superblock 進行讀/更新操作。為了支持不同版本的 superblock,md 定義了 super_type 接口:
978struct super_type { 979 char *name; 980 struct module *owner; 981 int (*load_super)(struct md_rdev *rdev, 982 struct md_rdev *refdev, 983 int minor_version); 984 int (*validate_super)(struct mddev *mddev, 985 struct md_rdev *rdev); 986 void (*sync_super)(struct mddev *mddev, 987 struct md_rdev *rdev); 988 unsigned long long (*rdev_size_change)(struct md_rdev *rdev, 989 sector_t num_sectors); 990 int (*allow_new_offset)(struct md_rdev *rdev, 991 unsigned long long new_offset); 992}; 956 * int load_super(struct md_rdev *dev, struct md_rdev *refdev, int minor_version) 957 * loads and validates a superblock on dev. 958 * if refdev != NULL, compare superblocks on both devices 959 * Return: 960 * 0 - dev has a superblock that is compatible with refdev 961 * 1 - dev has a superblock that is compatible and newer than refdev 962 * so dev should be used as the refdev in future 963 * -EINVAL superblock incompatible or invalid 964 * -othererror e.g. -EIO 965 * 966 * int validate_super(struct mddev *mddev, struct md_rdev *dev) 967 * Verify that dev is acceptable into mddev. 968 * The first time, mddev->raid_disks will be 0, and data from 969 * dev should be merged in. Subsequent calls check that dev 970 * is new enough. Return 0 or -EINVAL 971 * 972 * void sync_super(struct mddev *mddev, struct md_rdev *dev) 973 * Update the superblock for rdev with data in mddev 974 * This does not write to disc.
當前實現了 2 個接口,以支持 2 類版本的 superblock:
static struct super_type super_types[] = { [0] = { .name = "0.90.0", .owner = THIS_MODULE, .load_super = super_90_load, .validate_super = super_90_validate, .sync_super = super_90_sync, .rdev_size_change = super_90_rdev_size_change, .allow_new_offset = super_90_allow_new_offset, }, [1] = { .name = "md-1", 支持 1.0/1.1/1.2 版本 .owner = THIS_MODULE, .load_super = super_1_load, .validate_super = super_1_validate, .sync_super = super_1_sync, .rdev_size_change = super_1_rdev_size_change, .allow_new_offset = super_1_allow_new_offset, }, };
從 super_90_load/super_1_load 可以看到不同版本的 superblock,其存放位置、占用空間大小都是不一樣的。
md 相關的系統文件
static const struct file_operations md_seq_fops --- /proc/mdstat static struct attribute *md_default_attrs[] /sys/block/mdX/md/ static struct attribute *rdev_default_attrs[] /sys/block/mdX/md/[disk]/ /proc/sys/dev/raid/speed_limit_min # sysctl 變量 static int sysctl_speed_limit_min = 1000 /proc/sys/dev/raid/speed_limit_max # sysctl 變量 static int sysctl_speed_limit_max = 200000
/sys/block/mdX/md/sync_speed_{min,max} # mddev->sync_speed_min 和 mddev->sync_speed_max
事件計數
static atomic_t md_event_count
* We have a system wide 'event count' that is incremented * on any 'interesting' event, and readers of /proc/mdstat * can use 'poll' or 'select' to find out when the event * count increases. * * Events are: * start array, stop array, error, add device, remove device, * start build, activate spare
ioctl
md 支持的 ioctl 命令在 linux/include/uapi/linux/raid/md_u.h 中定義:
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 初始化流程
* 編譯進內核:autostart_arrays 搜索 rdev "Autodetecting RAID arrays" -> autorun_devices 根據 rdev 列表構建 mddev 結構 -> autorun_array 啟動 mddev 陣列 -> ... 運行 ...
* 編譯成模塊:md_open -> static const struct block_device_operations md_fops -> ... 運行 ...
md 內核線程
md 一些工作是由內核線程完成的,比如 ->thread/->sync_thread,->sync_thread 通常運行的是函數 md_do_sync,而 ->thread 多運行 RAID mode 自己提供的函數,比如 RAID1 提供了 raid1d,RAID5 提供了 raid5d,RAID10 提供了 raid10d。
小結
md 只是扮演了一個 framework 的角色,通過橋梁作用,讓底層的 RAID mode 模塊向上層提供 RAID 算法。要更好的理解 md,需要結合具體的 RAID 算法來看。
* 尚未弄明白的問題
* mdadm 寫 superblock 時是對所有 real device 都寫嗎?還是不同 RAID mode 有不同的副本管理?
* 內核 md 只是實現了比較基礎的功能,而 mdadm 在用戶態實現了大量的邏輯,以支持復雜的操作
需要好好看看 mdadm 實現 :-)
* bitmap 在 md 中起什么作用? [linear/raid0 不使用 bitmap]
* superblock 在 md 中就可以加載/更新,不需要各 RAID mode 提供專門的處理函數
* 不同 RAID mode 在 reshape 時會怎么運作?
* 什么條件下做 resync?有沒有內核線程來自動做 resync,運行頻率是怎樣的?
* reconstruction 什么時候做,跟 resync 的區別在哪里?有沒有專門的線程來做?
如果有磁盤故障,則會對第 1 個 spare disk 做 reconstruction 操作
* md 中有多少內核線程,分別做什么?
* 不同 RAID mode 對 badblocks 是如何檢測、處理的?
* takeove 什么時候發生?具體會有哪些改變?