📄 md.c
字号:
printk("do_md_run() returned %d\n", err); /* * prevent the writeback of an unrunnable array */ mddev->sb_dirty = 0; do_md_stop (mddev, 0); }}/* * lets try to run arrays based on all disks that have arrived * until now. (those are in the ->pending list) * * the method: pick the first pending disk, collect all disks with * the same UUID, remove all from the pending list and put them into * the 'same_array' list. Then order this list based on superblock * update time (freshest comes first), kick out 'old' disks and * compare superblocks. If everything's fine then run it. * * If "unit" is allocated, then bump its reference count */static void autorun_devices (kdev_t countdev){ struct md_list_head candidates; struct md_list_head *tmp; mdk_rdev_t *rdev0, *rdev; mddev_t *mddev; kdev_t md_kdev; printk("autorun ...\n"); while (pending_raid_disks.next != &pending_raid_disks) { rdev0 = md_list_entry(pending_raid_disks.next, mdk_rdev_t, pending); printk("considering %s ...\n", partition_name(rdev0->dev)); MD_INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) { if (uuid_equal(rdev0, rdev)) { if (!sb_equal(rdev0->sb, rdev->sb)) { printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); continue; } printk(" adding %s ...\n", partition_name(rdev->dev)); md_list_del(&rdev->pending); md_list_add(&rdev->pending, &candidates); } } /* * now we have a set of devices, with all of them having * mostly sane superblocks. It's time to allocate the * mddev. */ md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); mddev = kdev_to_mddev(md_kdev); if (mddev) { printk("md%d already running, cannot run %s\n", mdidx(mddev), partition_name(rdev0->dev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) export_rdev(rdev); continue; } mddev = alloc_mddev(md_kdev); if (mddev == NULL) { printk("md: cannot allocate memory for md drive.\n"); break; } if (md_kdev == countdev) atomic_inc(&mddev->active); printk("created md%d\n", mdidx(mddev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { bind_rdev_to_array(rdev, mddev); md_list_del(&rdev->pending); MD_INIT_LIST_HEAD(&rdev->pending); } autorun_array(mddev); } printk("... autorun DONE.\n");}/* * import RAID devices based on one partition * if possible, the array gets run as well. */#define BAD_VERSION KERN_ERR \"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n"#define OUT_OF_MEM KERN_ALERT \"md: out of memory.\n"#define NO_DEVICE KERN_ERR \"md: disabled device %s\n"#define AUTOADD_FAILED KERN_ERR \"md: auto-adding devices to md%d FAILED (error %d).\n"#define AUTOADD_FAILED_USED KERN_ERR \"md: cannot auto-add device %s to md%d, already used.\n"#define AUTORUN_FAILED KERN_ERR \"md: auto-running md%d FAILED (error %d).\n"#define MDDEV_BUSY KERN_ERR \"md: cannot auto-add to md%d, already running.\n"#define AUTOADDING KERN_INFO \"md: auto-adding devices to md%d, based on %s's superblock.\n"#define AUTORUNNING KERN_INFO \"md: auto-running md%d.\n"static int autostart_array (kdev_t startdev, kdev_t countdev){ int err = -EINVAL, i; mdp_super_t *sb = NULL; mdk_rdev_t *start_rdev = NULL, *rdev; if (md_import_device(startdev, 1)) { printk("could not import %s!\n", partition_name(startdev)); goto abort; } start_rdev = find_rdev_all(startdev); if (!start_rdev) { MD_BUG(); goto abort; } if (start_rdev->faulty) { printk("can not autostart based on faulty %s!\n", partition_name(startdev)); goto abort; } md_list_add(&start_rdev->pending, &pending_raid_disks); sb = start_rdev->sb; err = detect_old_array(sb); if (err) { printk("array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); goto abort; } for (i = 0; i < MD_SB_DISKS; i++) { mdp_disk_t *desc; kdev_t dev; desc = sb->disks + i; dev = MKDEV(desc->major, desc->minor); if (dev == MKDEV(0,0)) continue; if (dev == startdev) continue; if (md_import_device(dev, 1)) { printk("could not import %s, trying to run array nevertheless.\n", partition_name(dev)); continue; } rdev = find_rdev_all(dev); if (!rdev) { MD_BUG(); goto abort; } md_list_add(&rdev->pending, &pending_raid_disks); } /* * possibly return codes */ autorun_devices(countdev); return 0;abort: if (start_rdev) export_rdev(start_rdev); return err;}#undef BAD_VERSION#undef OUT_OF_MEM#undef NO_DEVICE#undef AUTOADD_FAILED_USED#undef AUTOADD_FAILED#undef AUTORUN_FAILED#undef AUTOADDING#undef AUTORUNNINGstruct { int set; int noautodetect;} raid_setup_args md__initdata = { 0, 0 };void md_setup_drive(void) md__init;/* * Searches all registered partitions for autorun RAID arrays * at boot time. */#ifdef CONFIG_AUTODETECT_RAIDstatic int detected_devices[128] md__initdata = { 0, };static int dev_cnt=0;void md_autodetect_dev(kdev_t dev){ if (dev_cnt >= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev;}#endifint md__init md_run_setup(void){#ifdef CONFIG_AUTODETECT_RAID mdk_rdev_t *rdev; int i; if (raid_setup_args.noautodetect) printk(KERN_INFO "skipping autodetection of RAID arrays\n"); else { printk(KERN_INFO "autodetecting RAID arrays\n"); for (i=0; i<dev_cnt; i++) { kdev_t dev = detected_devices[i]; if (md_import_device(dev,1)) { printk(KERN_ALERT "could not import %s!\n", partition_name(dev)); continue; } /* * Sanity checks: */ rdev = find_rdev_all(dev); if (!rdev) { MD_BUG(); continue; } if (rdev->faulty) { MD_BUG(); continue; } md_list_add(&rdev->pending, &pending_raid_disks); } autorun_devices(-1); } dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */#endif#ifdef CONFIG_MD_BOOT md_setup_drive();#endif return 0;}static int get_version (void * arg){ mdu_version_t ver; ver.major = MD_MAJOR_VERSION; ver.minor = MD_MINOR_VERSION; ver.patchlevel = MD_PATCHLEVEL_VERSION; if (md_copy_to_user(arg, &ver, sizeof(ver))) return -EFAULT; return 0;}#define SET_FROM_SB(x) info.x = mddev->sb->xstatic int get_array_info (mddev_t * mddev, void * arg){ mdu_array_info_t info; if (!mddev->sb) return -EINVAL; SET_FROM_SB(major_version); SET_FROM_SB(minor_version); SET_FROM_SB(patch_version); SET_FROM_SB(ctime); SET_FROM_SB(level); SET_FROM_SB(size); SET_FROM_SB(nr_disks); SET_FROM_SB(raid_disks); SET_FROM_SB(md_minor); SET_FROM_SB(not_persistent); SET_FROM_SB(utime); SET_FROM_SB(state); SET_FROM_SB(active_disks); SET_FROM_SB(working_disks); SET_FROM_SB(failed_disks); SET_FROM_SB(spare_disks); SET_FROM_SB(layout); SET_FROM_SB(chunk_size); if (md_copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}#undef SET_FROM_SB#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].xstatic int get_disk_info (mddev_t * mddev, void * arg){ mdu_disk_info_t info; unsigned int nr; if (!mddev->sb) return -EINVAL; if (md_copy_from_user(&info, arg, sizeof(info))) return -EFAULT; nr = info.number; if (nr >= mddev->sb->nr_disks) return -EINVAL; SET_FROM_SB(major); SET_FROM_SB(minor); SET_FROM_SB(raid_disk); SET_FROM_SB(state); if (md_copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}#undef SET_FROM_SB#define SET_SB(x) mddev->sb->disks[nr].x = info->xstatic int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info){ int err, size, persistent; mdk_rdev_t *rdev; unsigned int nr; kdev_t dev; dev = MKDEV(info->major,info->minor); if (find_rdev_all(dev)) { printk("device %s already used in a RAID array!\n", partition_name(dev)); return -EBUSY; } if (!mddev->sb) { /* expecting a device which has a superblock */ err = md_import_device(dev, 1); if (err) { printk("md error, md_import_device returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); if (!rdev) { MD_BUG(); return -EINVAL; } if (mddev->nb_dev) { mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next, mdk_rdev_t, same_set); if (!uuid_equal(rdev0, rdev)) { printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); export_rdev(rdev); return -EINVAL; } if (!sb_equal(rdev0->sb, rdev->sb)) { printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); export_rdev(rdev); return -EINVAL; } } bind_rdev_to_array(rdev, mddev); return 0; } nr = info->number; if (nr >= mddev->sb->nr_disks) return -EINVAL; SET_SB(number); SET_SB(major); SET_SB(minor); SET_SB(raid_disk); SET_SB(state); if ((info->state & (1<<MD_DISK_FAULTY))==0) { err = md_import_device (dev, 0); if (err) { printk("md: error, md_import_device() returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); if (!rdev) { MD_BUG(); return -EINVAL; } rdev->old_dev = dev; rdev->desc_nr = info->number; bind_rdev_to_array(rdev, mddev); persistent = !mddev->sb->not_persistent; if (!persistent) printk("nonpersistent superblock ...\n"); if (!mddev->sb->chunk_size) printk("no chunksize?\n"); size = calc_dev_size(dev, mddev, persistent); rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); if (!mddev->sb->size || (mddev->sb->size > size)) mddev->sb->size = size; } /* * sync all other superblocks with the main superblock */ sync_sbs(mddev); return 0;}#undef SET_SBstatic int hot_remove_disk (mddev_t * mddev, kdev_t dev){ int err; mdk_rdev_t *rdev; mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; printk("trying to remove %s from md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { printk("md%d: personality does not support diskops!\n", mdidx(mddev)); return -EINVAL; } rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; if (rdev->desc_nr == -1) { MD_BUG(); return -EINVAL; } disk = &mddev->sb->disks[rdev->desc_nr]; if (disk_active(disk)) goto busy; if (disk_removed(disk)) { MD_BUG(); return -EINVAL; } err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); if (err == -EBUSY) goto busy; if (err) { MD_BUG(); return -EINVAL; } remove_descriptor(disk, mddev->sb); kick_rdev_from_array(rdev); mddev->sb_dirty = 1; md_update_sb(mddev); return 0;busy: printk("cannot remove active disk %s from md%d ... \n", partition_name(dev), mdidx(mddev)); return -EBUSY;}static int hot_add_disk (mddev_t * mddev, kdev_t dev){ int i, err, persistent; unsigned int size; mdk_rdev_t *rdev; mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; printk("trying to hot-add %s to md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { printk("md%d: personality does not support diskops!\n", mdidx(mddev)); return -EINVAL; } persistent = !mddev->sb->not_persistent; size = calc_dev_size(dev, mddev, persistent); if (size < mddev->sb->size) { printk("md%d: disk size %d blocks < array size %d\n", mdidx(mddev), size, mddev->sb->size); return -ENOSPC; } rdev = find_rdev(mddev, dev); if (rdev) return -EBUSY; err = md_import_device (dev, 0); if (err) { printk("md: error, md_import_device() returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev); if (!rdev) { MD_BUG(); return -EINVAL; } if (rdev->faulty) { printk("md: can not hot-add faulty %s disk to md%d!\n", partition_name(dev), mdidx(mddev)); err = -EINVAL; goto abort_export; } bind_rdev_to_array(rdev, mddev); /* * The rest should better be atomic, we can have disk failures * noticed in interrupt contexts ... */ rdev->old_dev = dev; rdev->size = size; rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); disk = mddev->sb->disks + mddev->sb->raid_disks; for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { disk = mddev->sb->disks + i; if (!disk->major && !disk->minor) break; if (disk_removed(disk)) break; } if (i == MD_SB_DISKS) { printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); err = -EBUSY; goto abort_unbind_export; } if (disk_removed(disk)) { /* * reuse slot */ if (disk->number != i) { MD_BUG(); err = -EINVAL; goto abort_unbind_export; } } else { disk->number = i; } disk->raid_disk = disk->number; disk->major = MAJOR(dev); disk->minor = MINOR(dev); if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { MD_BUG(); err = -EINVAL; goto abort_unbind_export; } mark_disk_spare(disk); mddev->sb->nr_disks++; mddev->sb->spare_disks++; mddev->sb->working_disks++; mddev->sb_dirty = 1; md_update_sb(mddev); /* * Kick recovery, maybe this spare has to be added to the * array immediately. */ md_recover_arrays(); return 0;abort_unbind_export: unbind_rdev_from_array(rdev);abort_export: export_rdev(rdev); return err;}#define SET_SB(x) mddev->sb->x = info->xstatic int set_array_info (mddev_t * mddev, mdu_array_info_t *info){ if (alloc_array_sb(mddev)) return -ENOMEM; mddev->sb->major_version = MD_MAJOR_VERSION; mddev->sb->minor_version = MD_MINOR_VERSION; mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; mddev->sb->ctime = CURRENT_TIME; SET_SB(level);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -