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