md.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,796 行 · 第 1/5 页
C
2,796 行
mddev->pers = pers[pnum]; spin_unlock(&pers_lock); mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ err = mddev->pers->run(mddev); if (err) { printk(KERN_ERR "md: pers->run() failed ...\n"); module_put(mddev->pers->owner); mddev->pers = NULL; return -EINVAL; } atomic_set(&mddev->writes_pending,0); mddev->safemode = 0; mddev->safemode_timer.function = md_safemode_timeout; mddev->safemode_timer.data = (unsigned long) mddev; mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ mddev->in_sync = 1; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); if (mddev->sb_dirty) md_update_sb(mddev); set_capacity(disk, mddev->array_size<<1); /* If we call blk_queue_make_request here, it will * re-initialise max_sectors etc which may have been * refined inside -> run. So just set the bits we need to set. * Most initialisation happended when we called * blk_queue_make_request(..., md_fail_request) * earlier. */ mddev->queue->queuedata = mddev; mddev->queue->make_request_fn = mddev->pers->make_request; mddev->queue->issue_flush_fn = md_flush_all; mddev->changed = 1; return 0;}static int restart_array(mddev_t *mddev){ struct gendisk *disk = mddev->gendisk; int err; /* * Complain if it has no devices */ err = -ENXIO; if (list_empty(&mddev->disks)) goto out; if (mddev->pers) { err = -EBUSY; if (!mddev->ro) goto out; mddev->safemode = 0; mddev->ro = 0; set_disk_ro(disk, 0); printk(KERN_INFO "md: %s switched to read-write mode.\n", mdname(mddev)); /* * Kick recovery or resync if necessary */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); err = 0; } else { printk(KERN_ERR "md: %s has no personality assigned.\n", mdname(mddev)); err = -EINVAL; }out: return err;}static int do_md_stop(mddev_t * mddev, int ro){ int err = 0; struct gendisk *disk = mddev->gendisk; if (mddev->pers) { if (atomic_read(&mddev->active)>2) { printk("md: %s still in use.\n",mdname(mddev)); return -EBUSY; } if (mddev->sync_thread) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); md_unregister_thread(mddev->sync_thread); mddev->sync_thread = NULL; } del_timer_sync(&mddev->safemode_timer); invalidate_partition(disk, 0); if (ro) { err = -ENXIO; if (mddev->ro) goto out; mddev->ro = 1; } else { if (mddev->ro) set_disk_ro(disk, 0); blk_queue_make_request(mddev->queue, md_fail_request); mddev->pers->stop(mddev); module_put(mddev->pers->owner); mddev->pers = NULL; if (mddev->ro) mddev->ro = 0; } if (!mddev->in_sync) { /* mark array as shutdown cleanly */ mddev->in_sync = 1; md_update_sb(mddev); } if (ro) set_disk_ro(disk, 1); } /* * Free resources if final stop */ if (!ro) { struct gendisk *disk; printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); export_array(mddev); mddev->array_size = 0; disk = mddev->gendisk; if (disk) set_capacity(disk, 0); mddev->changed = 1; } else printk(KERN_INFO "md: %s switched to read-only mode.\n", mdname(mddev)); err = 0;out: return err;}static void autorun_array(mddev_t *mddev){ mdk_rdev_t *rdev; struct list_head *tmp; int err; if (list_empty(&mddev->disks)) { MD_BUG(); return; } printk(KERN_INFO "md: running: "); ITERATE_RDEV(mddev,rdev,tmp) { char b[BDEVNAME_SIZE]; printk("<%s>", bdevname(rdev->bdev,b)); } printk("\n"); err = do_md_run (mddev); if (err) { printk(KERN_WARNING "md :do_md_run() returned %d\n", err); do_md_stop (mddev, 0); }}/* * lets try to run arrays based on all disks that have arrived * until now. (those are in pending_raid_disks) * * 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(int part){ struct list_head candidates; struct list_head *tmp; mdk_rdev_t *rdev0, *rdev; mddev_t *mddev; char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: autorun ...\n"); while (!list_empty(&pending_raid_disks)) { dev_t dev; rdev0 = list_entry(pending_raid_disks.next, mdk_rdev_t, same_set); printk(KERN_INFO "md: considering %s ...\n", bdevname(rdev0->bdev,b)); INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) if (super_90_load(rdev, rdev0, 0) >= 0) { printk(KERN_INFO "md: adding %s ...\n", bdevname(rdev->bdev,b)); list_move(&rdev->same_set, &candidates); } /* * now we have a set of devices, with all of them having * mostly sane superblocks. It's time to allocate the * mddev. */ if (rdev0->preferred_minor < 0 || rdev0->preferred_minor >= MAX_MD_DEVS) { printk(KERN_INFO "md: unit number in %s is bad: %d\n", bdevname(rdev0->bdev, b), rdev0->preferred_minor); break; } if (part) dev = MKDEV(mdp_major, rdev0->preferred_minor << MdpMinorShift); else dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); md_probe(dev, NULL, NULL); mddev = mddev_find(dev); if (!mddev) { printk(KERN_ERR "md: cannot allocate memory for md drive.\n"); break; } if (mddev_lock(mddev)) printk(KERN_WARNING "md: %s locked, cannot run\n", mdname(mddev)); else if (mddev->raid_disks || mddev->major_version || !list_empty(&mddev->disks)) { printk(KERN_WARNING "md: %s already running, cannot run %s\n", mdname(mddev), bdevname(rdev0->bdev,b)); mddev_unlock(mddev); } else { printk(KERN_INFO "md: created %s\n", mdname(mddev)); ITERATE_RDEV_GENERIC(candidates,rdev,tmp) { list_del_init(&rdev->same_set); if (bind_rdev_to_array(rdev, mddev)) export_rdev(rdev); } autorun_array(mddev); mddev_unlock(mddev); } /* on success, candidates will be empty, on error * it won't... */ ITERATE_RDEV_GENERIC(candidates,rdev,tmp) export_rdev(rdev); mddev_put(mddev); } printk(KERN_INFO "md: ... autorun DONE.\n");}/* * import RAID devices based on one partition * if possible, the array gets run as well. */static int autostart_array(dev_t startdev){ char b[BDEVNAME_SIZE]; int err = -EINVAL, i; mdp_super_t *sb = NULL; mdk_rdev_t *start_rdev = NULL, *rdev; start_rdev = md_import_device(startdev, 0, 0); if (IS_ERR(start_rdev)) return err; /* NOTE: this can only work for 0.90.0 superblocks */ sb = (mdp_super_t*)page_address(start_rdev->sb_page); if (sb->major_version != 0 || sb->minor_version != 90 ) { printk(KERN_WARNING "md: can only autostart 0.90.0 arrays\n"); export_rdev(start_rdev); return err; } if (start_rdev->faulty) { printk(KERN_WARNING "md: can not autostart based on faulty %s!\n", bdevname(start_rdev->bdev,b)); export_rdev(start_rdev); return err; } list_add(&start_rdev->same_set, &pending_raid_disks); for (i = 0; i < MD_SB_DISKS; i++) { mdp_disk_t *desc = sb->disks + i; dev_t dev = MKDEV(desc->major, desc->minor); if (!dev) continue; if (dev == startdev) continue; if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor) continue; rdev = md_import_device(dev, 0, 0); if (IS_ERR(rdev)) continue; list_add(&rdev->same_set, &pending_raid_disks); } /* * possibly return codes */ autorun_devices(0); return 0;}static int get_version(void __user * arg){ mdu_version_t ver; ver.major = MD_MAJOR_VERSION; ver.minor = MD_MINOR_VERSION; ver.patchlevel = MD_PATCHLEVEL_VERSION; if (copy_to_user(arg, &ver, sizeof(ver))) return -EFAULT; return 0;}static int get_array_info(mddev_t * mddev, void __user * arg){ mdu_array_info_t info; int nr,working,active,failed,spare; mdk_rdev_t *rdev; struct list_head *tmp; nr=working=active=failed=spare=0; ITERATE_RDEV(mddev,rdev,tmp) { nr++; if (rdev->faulty) failed++; else { working++; if (rdev->in_sync) active++; else spare++; } } info.major_version = mddev->major_version; info.minor_version = mddev->minor_version; info.patch_version = 1; info.ctime = mddev->ctime; info.level = mddev->level; info.size = mddev->size; info.nr_disks = nr; info.raid_disks = mddev->raid_disks; info.md_minor = mddev->md_minor; info.not_persistent= !mddev->persistent; info.utime = mddev->utime; info.state = 0; if (mddev->in_sync) info.state = (1<<MD_SB_CLEAN); info.active_disks = active; info.working_disks = working; info.failed_disks = failed; info.spare_disks = spare; info.layout = mddev->layout; info.chunk_size = mddev->chunk_size; if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}static int get_disk_info(mddev_t * mddev, void __user * arg){ mdu_disk_info_t info; unsigned int nr; mdk_rdev_t *rdev; if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; nr = info.number; rdev = find_rdev_nr(mddev, nr); if (rdev) { info.major = MAJOR(rdev->bdev->bd_dev); info.minor = MINOR(rdev->bdev->bd_dev); info.raid_disk = rdev->raid_disk; info.state = 0; if (rdev->faulty) info.state |= (1<<MD_DISK_FAULTY); else if (rdev->in_sync) { info.state |= (1<<MD_DISK_ACTIVE); info.state |= (1<<MD_DISK_SYNC); } } else { info.major = info.minor = 0; info.raid_disk = -1; info.state = (1<<MD_DISK_REMOVED); } if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0;}static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info){ char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; mdk_rdev_t *rdev; dev_t dev = MKDEV(info->major,info->minor); if (info->major != MAJOR(dev) || info->minor != MINOR(dev)) return -EOVERFLOW; if (!mddev->raid_disks) { int err; /* expecting a device which has a superblock */ rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: md_import_device returned %ld\n", PTR_ERR(rdev)); return PTR_ERR(rdev); } if (!list_empty(&mddev->disks)) { mdk_rdev_t *rdev0 = list_entry(mddev->disks.next, mdk_rdev_t, same_set); int err = super_types[mddev->major_version] .load_super(rdev, rdev0, mddev->minor_version); if (err < 0) { printk(KERN_WARNING "md: %s has different UUID to %s\n", bdevname(rdev->bdev,b), bdevname(rdev0->bdev,b2)); export_rdev(rdev); return -EINVAL; } } err = bind_rdev_to_array(rdev, mddev); if (err) export_rdev(rdev); return err; } /* * add_new_disk can be used once the array is assembled * to add "hot spares". They must already have a superblock * written */ if (mddev->pers) { int err; if (!mddev->pers->hot_add_disk) { printk(KERN_WARNING "%s: personality does not support diskops!\n", mdname(mddev)); return -EINVAL; } rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: md_import_device returned %ld\n", PTR_ERR(rdev)); return PTR_ERR(rdev); } rdev->in_sync = 0; /* just to be sure */ rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); if (err) export_rdev(rdev); if (mddev->thread) md_wakeup_thread(mddev->thread); return err; } /* otherwise, add_new_disk is only allowed * for major_version==0 superblocks */ if (mddev->major_version != 0) { printk(KERN_WARNING "%s: ADD_NEW_DISK not supported\n", mdname(mddev)); return -EINVAL; } if (!(info->state & (1<<MD_DISK_FAULTY))) { int err; rdev = md_import_device (dev, -1, 0); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); return PTR_ERR(rdev); } rdev->desc_nr = info->number; if (info->raid_disk < mddev->raid_disks) rdev->raid_disk = info->raid_disk; else rdev->raid_disk = -1; rdev->faulty = 0; if (rdev->raid_disk < mddev->raid_disks) rdev->in_sync = (info->state & (1<<MD_DISK_SYNC)); else rdev->in_sync = 0; err = bind_rdev_to_array(rdev, mddev); if (err) { export_rdev(rdev); return err; } if (!mddev->persistent) { printk(KERN_INFO "md: nonpersistent superblock ...\n"); rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; } else rdev->sb_offset = calc_dev_sboffset(rdev->bdev); rdev->size = calc_dev_size(rdev, mddev->chunk_size); if (!mddev->size || (mddev->size > rdev->size)) mddev->size = rdev->size; } return 0;}static int hot_remove_disk(mddev_t * mddev, dev_t dev){ char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; if (!mddev->pers) return -ENODEV; rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; if (rdev->raid_disk >= 0) goto busy; kick_rdev_from_array(rdev); md_update_sb(mddev); return 0;busy:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?