📄 md.c
字号:
*/ if (mddev->pers->stop_resync) if (mddev->pers->stop_resync(mddev)) resync_interrupted = 1; if (mddev->recovery_running) md_interrupt_thread(md_recovery_thread); /* * This synchronizes with signal delivery to the * resync or reconstruction thread. It also nicely * hangs the process if some reconstruction has not * finished. */ down(&mddev->recovery_sem); up(&mddev->recovery_sem); invalidate_device(dev, 1); if (ro) { if (mddev->ro) OUT(-ENXIO); mddev->ro = 1; } else { if (mddev->ro) set_device_ro(dev, 0); if (mddev->pers->stop(mddev)) { if (mddev->ro) set_device_ro(dev, 1); OUT(-EBUSY); } if (mddev->ro) mddev->ro = 0; } if (mddev->sb) { /* * mark it clean only if there was no resync * interrupted. */ if (!mddev->recovery_running && !resync_interrupted) { printk(KERN_INFO "md: marking sb clean...\n"); mddev->sb->state |= 1 << MD_SB_CLEAN; } mddev->sb_dirty = 1; md_update_sb(mddev); } if (ro) set_device_ro(dev, 1); } /* * Free resources if final stop */ if (!ro) { printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev)); free_mddev(mddev); } else printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev));out: return err;}#undef OUT/* * We have to safely support old arrays too. */int detect_old_array(mdp_super_t *sb){ if (sb->major_version > 0) return 0; if (sb->minor_version >= 90) return 0; return -EINVAL;}static void autorun_array(mddev_t *mddev){ mdk_rdev_t *rdev; struct md_list_head *tmp; int err; if (mddev->disks.prev == &mddev->disks) { MD_BUG(); return; } printk(KERN_INFO "md: running: "); ITERATE_RDEV(mddev,rdev,tmp) { printk("<%s>", partition_name(rdev->dev)); } printk("\n"); err = do_md_run (mddev); if (err) { printk(KERN_WARNING "md :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(KERN_INFO "md: autorun ...\n"); while (pending_raid_disks.next != &pending_raid_disks) { rdev0 = md_list_entry(pending_raid_disks.next, mdk_rdev_t, pending); printk(KERN_INFO "md: 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(KERN_WARNING "md: %s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); continue; } printk(KERN_INFO "md: 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(KERN_WARNING "md: 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) { printk(KERN_ERR "md: cannot allocate memory for md drive.\n"); break; } if (md_kdev == countdev) atomic_inc(&mddev->active); printk(KERN_INFO "md: 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(KERN_INFO "md: ... 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(KERN_WARNING "md: 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(KERN_WARNING "md: 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(KERN_WARNING "md: array version is too old to be autostarted ," "use raidtools 0.90 mkraid --upgrade to 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(KERN_WARNING "md: 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 AUTORUNNINGstatic 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) { MD_BUG(); 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 >= MD_SB_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(KERN_WARNING "md: 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(KERN_WARNING "md: 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(KERN_WARNING "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(KERN_WARNING "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) { MD_BUG(); 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(KERN_WARNING "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(KERN_INFO "md: nonpersistent superblock ...\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_generate_error(mddev_t * mddev, kdev_t dev){ struct request_queue *q; mdk_rdev_t *rdev; mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; printk(KERN_INFO "md: trying to generate %s error in md%d ... \n", partition_name(dev), mdidx(mddev)); rdev = find_rdev(mddev, dev); if (!rdev) { MD_BUG(); return -ENXIO; } if (rdev->desc_nr == -1) { MD_BUG(); return -EINVAL; } disk = &mddev->sb->disks[rdev->desc_nr]; if (!disk_active(disk)) return -ENODEV; q = blk_get_queue(rdev->dev); if (!q) { MD_BUG(); return -ENODEV; } printk(KERN_INFO "md: okay, generating error!\n");// q->oneshot_error = 1; // disabled for now return 0;}static 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(KERN_INFO "md: trying to remove %s from md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { printk(KERN_WARNING "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)) { MD_BUG(); goto busy; } if (disk_removed(disk)) { MD_BUG(); return -EINVAL; } err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); if (err == -EBUSY) { MD_BUG(); 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(KERN_WARNING "md: 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(KERN_INFO "md: trying to hot-add %s to md%d ... \n", partition_name(dev), mdidx(mddev)); if (!mddev->pers->diskop) { printk(KERN_WARNING "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(KERN_WARNING "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(KERN_WARNING "md: error, md_import_device() returned %d\n", err); return -EINVAL; } rdev = find_rdev_all(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -