源文件
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 什么时候发生?具体会有哪些改变?