RAID5 IO处理之重构代码详解

1 作用当阵列降级时,可以添加一块新盘进行重构,以恢复阵列的冗余 。
2 发起重构【RAID5 IO处理之重构代码详解】可以通过以下命令md并发起重构:
mdadm -C /dev/md0 --force --run -l 5 -n 3 -c 128K /dev/sd[b-d] --assum-cleanmdadm --manage -f /dev/md0 /dev/sdbmdadm --manage -a /dev/md0 /dev/sde相关代码逻辑如下:
2.1 设置磁盘异常函数调用关系:
md_ioctl() /* SET_DISK_FAULTY */ \_ set_disk_faulty()\_ md_error()\_ error() /* raid5.c */\_ md_wakeup_thread() /* raid5d */raid5d() \_ md_check_recovery()\_ remove_and_add_spares()这里主要是设置成员磁盘异常的逻辑,代码逻辑如下:
static void error(struct mddev *mddev, struct md_rdev *rdev){ spin_lock_irqsave(&conf->device_lock, flags); /* 清除成员磁盘“同步”状态标记 */ clear_bit(In_sync, &rdev->flags); /* 重新计算md降级状态 */ mddev->degraded = calc_degraded(conf); spin_unlock_irqrestore(&conf->device_lock, flags); /* 打断同步 */ set_bit(MD_RECOVERY_INTR, &mddev->recovery); /* 设置成员磁盘为异常状态 */ set_bit(Blocked, &rdev->flags); set_bit(Faulty, &rdev->flags); /* 设置md发生磁盘状态改变 */ set_bit(MD_CHANGE_DEVS, &mddev->flags);}2.2 添加新盘函数调用关系:
md_ioctl() /* ADD_NEW_DISK */ \_ add_new_disk()\_ md_wakeup_thread() /* raid5d */raid5d() \_ md_check_recovery()\_ remove_and_add_spares()\_ md_register_thread() /* md_do_sync */md_do_sync() \_ sync_request() /* raid5d */这里需要注意,在加盘时没有像前文replacement中描述的那样设置磁盘为WantReplacement状态,所以不会将新的磁盘赋值给旧盘的replacement指针 。主要为设置重构相关标记,逻辑如下:
static int remove_and_add_spares(struct mddev *mddev,struct md_rdev *this){ int spares = 0; rdev_for_each(rdev, mddev) {/* 新添加的磁盘未设置相关标记自增spares */if (rdev->raid_disk >= 0 &&!test_bit(In_sync, &rdev->flags) &&!test_bit(Journal, &rdev->flags) &&!test_bit(Faulty, &rdev->flags))spares++; } return spares;}void md_check_recovery(struct mddev *mddev){ if (mddev_trylock(mddev)) {int spares = 0;/* 如上描述,在remove_and_add_spares返回spares为1 */if ((spares = remove_and_add_spares(mddev, NULL))) {/* 设置md为重构状态 */clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);}if (mddev->pers->sync_request) {if (spares) {/* We are adding a device or devices to an array* which has the bitmap stored on all devices.* So make sure all bitmap pages get written*/bitmap_write_all(mddev->bitmap);}/* 创建重构线程 */mddev->sync_thread = md_register_thread(md_do_sync,mddev,"resync");/* 创建失败则清除相关标记 */if (!mddev->sync_thread) {printk(KERN_ERR "%s: could not start resync"" thread...\n",mdname(mddev));/* leave the spares where they are, it shouldn't hurt */clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);} else {/* 成功则唤醒线程开始执行 */md_wakeup_thread(mddev->sync_thread);}}mddev_unlock(mddev); }}static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipped, int go_faster){ /* 获取一个空闲条带 */ sh = get_active_stripe(conf, sector_nr, 0, 1, 0); if (sh == NULL) {sh = get_active_stripe(conf, sector_nr, 0, 0, 0);schedule_timeout_uninterruptible(1); } /* 设置同步标记 */ set_bit(STRIPE_SYNC_REQUESTED, &sh->state); /* 将条带推入条带状态机处理 */ handle_stripe(sh); release_stripe(sh); return STRIPE_SECTORS;}

经验总结扩展阅读