📄 raid1.c
字号:
static void end_sync_read(struct buffer_head *bh, int uptodate){ struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); /* we have read a block, now it needs to be re-written, * or re-read if the read failed. * We don't do much here, just schedule handling by raid1d */ if (!uptodate) md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); else set_bit(R1BH_Uptodate, &r1_bh->state); raid1_reschedule_retry(r1_bh);}static void end_sync_write(struct buffer_head *bh, int uptodate){ struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); if (!uptodate) md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); if (atomic_dec_and_test(&r1_bh->remaining)) { mddev_t *mddev = r1_bh->mddev; unsigned long sect = bh->b_blocknr * (bh->b_size>>9); int size = bh->b_size; raid1_free_buf(r1_bh); sync_request_done(sect, mddev_to_conf(mddev)); md_done_sync(mddev,size>>10, uptodate); }}/* * This will catch the scenario in which one of the mirrors was * mounted as a normal device rather than as a part of a raid set. * * check_consistency is very personality-dependent, eg. RAID5 cannot * do this check, it uses another method. */static int __check_consistency (mddev_t *mddev, int row){ raid1_conf_t *conf = mddev_to_conf(mddev); int disks = MD_SB_DISKS; kdev_t dev; struct buffer_head *bh = NULL; int i, rc = 0; char *buffer = NULL; for (i = 0; i < disks; i++) { printk("(checking disk %d)\n",i); if (!conf->mirrors[i].operational) continue; printk("(really checking disk %d)\n",i); dev = conf->mirrors[i].dev; set_blocksize(dev, 4096); if ((bh = bread(dev, row / 4, 4096)) == NULL) break; if (!buffer) { buffer = (char *) __get_free_page(GFP_KERNEL); if (!buffer) break; memcpy(buffer, bh->b_data, 4096); } else if (memcmp(buffer, bh->b_data, 4096)) { rc = 1; break; } bforget(bh); fsync_dev(dev); invalidate_buffers(dev); bh = NULL; } if (buffer) free_page((unsigned long) buffer); if (bh) { dev = bh->b_dev; bforget(bh); fsync_dev(dev); invalidate_buffers(dev); } return rc;}static int check_consistency (mddev_t *mddev){ if (__check_consistency(mddev, 0))/* * we do not do this currently, as it's perfectly possible to * have an inconsistent array when it's freshly created. Only * newly written data has to be consistent. */ return 0; return 0;}#define INVALID_LEVEL KERN_WARNING \"raid1: md%d: raid level not set to mirroring (%d)\n"#define NO_SB KERN_ERR \"raid1: disabled mirror %s (couldn't access raid superblock)\n"#define ERRORS KERN_ERR \"raid1: disabled mirror %s (errors detected)\n"#define NOT_IN_SYNC KERN_ERR \"raid1: disabled mirror %s (not in sync)\n"#define INCONSISTENT KERN_ERR \"raid1: disabled mirror %s (inconsistent descriptor)\n"#define ALREADY_RUNNING KERN_ERR \"raid1: disabled mirror %s (mirror %d already operational)\n"#define OPERATIONAL KERN_INFO \"raid1: device %s operational as mirror %d\n"#define MEM_ERROR KERN_ERR \"raid1: couldn't allocate memory for md%d\n"#define SPARE KERN_INFO \"raid1: spare disk %s\n"#define NONE_OPERATIONAL KERN_ERR \"raid1: no operational mirrors for md%d\n"#define RUNNING_CKRAID KERN_ERR \"raid1: detected mirror differences -- running resync\n"#define ARRAY_IS_ACTIVE KERN_INFO \"raid1: raid set md%d active with %d out of %d mirrors\n"#define THREAD_ERROR KERN_ERR \"raid1: couldn't allocate thread for md%d\n"#define START_RESYNC KERN_WARNING \"raid1: raid set md%d not clean; reconstructing mirrors\n"static int raid1_run (mddev_t *mddev){ raid1_conf_t *conf; int i, j, disk_idx; struct mirror_info *disk; mdp_super_t *sb = mddev->sb; mdp_disk_t *descriptor; mdk_rdev_t *rdev; struct md_list_head *tmp; int start_recovery = 0; MOD_INC_USE_COUNT; if (sb->level != 1) { printk(INVALID_LEVEL, mdidx(mddev), sb->level); goto out; } /* * copy the already verified devices into our private RAID1 * bookkeeping area. [whatever we allocate in raid1_run(), * should be freed in raid1_stop()] */ conf = kmalloc(sizeof(raid1_conf_t), GFP_KERNEL); mddev->private = conf; if (!conf) { printk(MEM_ERROR, mdidx(mddev)); goto out; } memset(conf, 0, sizeof(*conf)); ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) { printk(ERRORS, partition_name(rdev->dev)); } else { if (!rdev->sb) { MD_BUG(); continue; } } if (rdev->desc_nr == -1) { MD_BUG(); continue; } descriptor = &sb->disks[rdev->desc_nr]; disk_idx = descriptor->raid_disk; disk = conf->mirrors + disk_idx; if (disk_faulty(descriptor)) { disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; disk->head_position = 0; continue; } if (disk_active(descriptor)) { if (!disk_sync(descriptor)) { printk(NOT_IN_SYNC, partition_name(rdev->dev)); continue; } if ((descriptor->number > MD_SB_DISKS) || (disk_idx > sb->raid_disks)) { printk(INCONSISTENT, partition_name(rdev->dev)); continue; } if (disk->operational) { printk(ALREADY_RUNNING, partition_name(rdev->dev), disk_idx); continue; } printk(OPERATIONAL, partition_name(rdev->dev), disk_idx); disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 1; disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; disk->head_position = 0; conf->working_disks++; } else { /* * Must be a spare disk .. */ printk(SPARE, partition_name(rdev->dev)); disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 1; disk->used_slot = 1; disk->head_position = 0; } } conf->raid_disks = sb->raid_disks; conf->nr_disks = sb->nr_disks; conf->mddev = mddev; conf->device_lock = MD_SPIN_LOCK_UNLOCKED; conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; init_waitqueue_head(&conf->wait_buffer); init_waitqueue_head(&conf->wait_done); init_waitqueue_head(&conf->wait_ready); if (!conf->working_disks) { printk(NONE_OPERATIONAL, mdidx(mddev)); goto out_free_conf; } /* pre-allocate some buffer_head structures. * As a minimum, 1 r1bh and raid_disks buffer_heads * would probably get us by in tight memory situations, * but a few more is probably a good idea. * For now, try 16 r1bh and 16*raid_disks bufferheads * This will allow at least 16 concurrent reads or writes * even if kmalloc starts failing */ if (raid1_grow_r1bh(conf, 16) < 16 || raid1_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) { printk(MEM_ERROR, mdidx(mddev)); goto out_free_conf; } for (i = 0; i < MD_SB_DISKS; i++) { descriptor = sb->disks+i; disk_idx = descriptor->raid_disk; disk = conf->mirrors + disk_idx; if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && !disk->used_slot) { disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = MKDEV(0,0); disk->operational = 0; disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; disk->head_position = 0; } } /* * find the first working one and use it as a starting point * to read balancing. */ for (j = 0; !conf->mirrors[j].operational && j < MD_SB_DISKS; j++) /* nothing */; conf->last_used = j; if (conf->working_disks != sb->raid_disks) { printk(KERN_ALERT "raid1: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); start_recovery = 1; } if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { /* * we do sanity checks even if the device says * it's clean ... */ if (check_consistency(mddev)) { printk(RUNNING_CKRAID); sb->state &= ~(1 << MD_SB_CLEAN); } } { const char * name = "raid1d"; conf->thread = md_register_thread(raid1d, conf, name); if (!conf->thread) { printk(THREAD_ERROR, mdidx(mddev)); goto out_free_conf; } } if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { const char * name = "raid1syncd"; conf->resync_thread = md_register_thread(raid1syncd, conf,name); if (!conf->resync_thread) { printk(THREAD_ERROR, mdidx(mddev)); goto out_free_conf; } printk(START_RESYNC, mdidx(mddev)); conf->resync_mirrors = 1; md_wakeup_thread(conf->resync_thread); } /* * Regenerate the "device is in sync with the raid set" bit for * each device. */ for (i = 0; i < MD_SB_DISKS; i++) { mark_disk_nonsync(sb->disks+i); for (j = 0; j < sb->raid_disks; j++) { if (!conf->mirrors[j].operational) continue; if (sb->disks[i].number == conf->mirrors[j].number) mark_disk_sync(sb->disks+i); } } sb->active_disks = conf->working_disks; if (start_recovery) md_recover_arrays(); printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); /* * Ok, everything is just fine now */ return 0;out_free_conf: raid1_shrink_r1bh(conf); raid1_shrink_bh(conf, conf->freebh_cnt); raid1_shrink_buffers(conf); kfree(conf); mddev->private = NULL;out: MOD_DEC_USE_COUNT; return -EIO;}#undef INVALID_LEVEL#undef NO_SB#undef ERRORS#undef NOT_IN_SYNC#undef INCONSISTENT#undef ALREADY_RUNNING#undef OPERATIONAL#undef SPARE#undef NONE_OPERATIONAL#undef RUNNING_CKRAID#undef ARRAY_IS_ACTIVEstatic int raid1_stop_resync (mddev_t *mddev){ raid1_conf_t *conf = mddev_to_conf(mddev); if (conf->resync_thread) { if (conf->resync_mirrors) { conf->resync_mirrors = 2; md_interrupt_thread(conf->resync_thread); printk(KERN_INFO "raid1: mirror resync was not fully finished, restarting next time.\n"); return 1; } return 0; } return 0;}static int raid1_restart_resync (mddev_t *mddev){ raid1_conf_t *conf = mddev_to_conf(mddev); if (conf->resync_mirrors) { if (!conf->resync_thread) { MD_BUG(); return 0; } conf->resync_mirrors = 1; md_wakeup_thread(conf->resync_thread); return 1; } return 0;}static int raid1_stop (mddev_t *mddev){ raid1_conf_t *conf = mddev_to_conf(mddev); md_unregister_thread(conf->thread); if (conf->resync_thread) md_unregister_thread(conf->resync_thread); raid1_shrink_r1bh(conf); raid1_shrink_bh(conf, conf->freebh_cnt); raid1_shrink_buffers(conf); kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; return 0;}static mdk_personality_t raid1_personality={ name: "raid1", make_request: raid1_make_request, run: raid1_run, stop: raid1_stop, status: raid1_status, error_handler: raid1_error, diskop: raid1_diskop, stop_resync: raid1_stop_resync, restart_resync: raid1_restart_resync, sync_request: raid1_sync_request};static int md__init raid1_init (void){ return register_md_personality (RAID1, &raid1_personality);}static void raid1_exit (void){ unregister_md_personality (RAID1);}module_init(raid1_init);module_exit(raid1_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -