md.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,796 行 · 第 1/5 页
C
2,796 行
printk(KERN_WARNING "md: cannot remove active disk %s from %s ... \n", bdevname(rdev->bdev,b), mdname(mddev)); return -EBUSY;}static int hot_add_disk(mddev_t * mddev, dev_t dev){ char b[BDEVNAME_SIZE]; int err; unsigned int size; mdk_rdev_t *rdev; if (!mddev->pers) return -ENODEV; if (mddev->major_version != 0) { printk(KERN_WARNING "%s: HOT_ADD may only be used with" " version-0 superblocks.\n", mdname(mddev)); return -EINVAL; } 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, -1, 0); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); return -EINVAL; } if (mddev->persistent) rdev->sb_offset = calc_dev_sboffset(rdev->bdev); else rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; size = calc_dev_size(rdev, mddev->chunk_size); rdev->size = size; if (size < mddev->size) { printk(KERN_WARNING "%s: disk size %llu blocks < array size %llu\n", mdname(mddev), (unsigned long long)size, (unsigned long long)mddev->size); err = -ENOSPC; goto abort_export; } if (rdev->faulty) { printk(KERN_WARNING "md: can not hot-add faulty %s disk to %s!\n", bdevname(rdev->bdev,b), mdname(mddev)); err = -EINVAL; goto abort_export; } rdev->in_sync = 0; rdev->desc_nr = -1; bind_rdev_to_array(rdev, mddev); /* * The rest should better be atomic, we can have disk failures * noticed in interrupt contexts ... */ if (rdev->desc_nr == mddev->max_disks) { printk(KERN_WARNING "%s: can not hot-add to full array!\n", mdname(mddev)); err = -EBUSY; goto abort_unbind_export; } rdev->raid_disk = -1; md_update_sb(mddev); /* * Kick recovery, maybe this spare has to be added to the * array immediately. */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); return 0;abort_unbind_export: unbind_rdev_from_array(rdev);abort_export: export_rdev(rdev); return err;}/* * set_array_info is used two different ways * The original usage is when creating a new array. * In this usage, raid_disks is > 0 and it together with * level, size, not_persistent,layout,chunksize determine the * shape of the array. * This will always create an array with a type-0.90.0 superblock. * The newer usage is when assembling an array. * In this case raid_disks will be 0, and the major_version field is * use to determine which style super-blocks are to be found on the devices. * The minor and patch _version numbers are also kept incase the * super_block handler wishes to interpret them. */static int set_array_info(mddev_t * mddev, mdu_array_info_t *info){ if (info->raid_disks == 0) { /* just setting version number for superblock loading */ if (info->major_version < 0 || info->major_version >= sizeof(super_types)/sizeof(super_types[0]) || super_types[info->major_version].name == NULL) { /* maybe try to auto-load a module? */ printk(KERN_INFO "md: superblock version %d not known\n", info->major_version); return -EINVAL; } mddev->major_version = info->major_version; mddev->minor_version = info->minor_version; mddev->patch_version = info->patch_version; return 0; } mddev->major_version = MD_MAJOR_VERSION; mddev->minor_version = MD_MINOR_VERSION; mddev->patch_version = MD_PATCHLEVEL_VERSION; mddev->ctime = get_seconds(); mddev->level = info->level; mddev->size = info->size; mddev->raid_disks = info->raid_disks; /* don't set md_minor, it is determined by which /dev/md* was * openned */ if (info->state & (1<<MD_SB_CLEAN)) mddev->recovery_cp = MaxSector; else mddev->recovery_cp = 0; mddev->persistent = ! info->not_persistent; mddev->layout = info->layout; mddev->chunk_size = info->chunk_size; mddev->max_disks = MD_SB_DISKS; mddev->sb_dirty = 1; /* * Generate a 128 bit UUID */ get_random_bytes(mddev->uuid, 16); return 0;}/* * update_array_info is used to change the configuration of an * on-line array. * The version, ctime,level,size,raid_disks,not_persistent, layout,chunk_size * fields in the info are checked against the array. * Any differences that cannot be handled will cause an error. * Normally, only one change can be managed at a time. */static int update_array_info(mddev_t *mddev, mdu_array_info_t *info){ int rv = 0; int cnt = 0; if (mddev->major_version != info->major_version || mddev->minor_version != info->minor_version ||/* mddev->patch_version != info->patch_version || */ mddev->ctime != info->ctime || mddev->level != info->level || mddev->layout != info->layout || !mddev->persistent != info->not_persistent|| mddev->chunk_size != info->chunk_size ) return -EINVAL; /* Check there is only one change */ if (mddev->size != info->size) cnt++; if (mddev->raid_disks != info->raid_disks) cnt++; if (cnt == 0) return 0; if (cnt > 1) return -EINVAL; if (mddev->size != info->size) { mdk_rdev_t * rdev; struct list_head *tmp; if (mddev->pers->resize == NULL) return -EINVAL; /* The "size" is the amount of each device that is used. * This can only make sense for arrays with redundancy. * linear and raid0 always use whatever space is available * We can only consider changing the size of no resync * or reconstruction is happening, and if the new size * is acceptable. It must fit before the sb_offset or, * if that is <data_offset, it must fit before the * size of each device. * If size is zero, we find the largest size that fits. */ if (mddev->sync_thread) return -EBUSY; ITERATE_RDEV(mddev,rdev,tmp) { sector_t avail; int fit = (info->size == 0); if (rdev->sb_offset > rdev->data_offset) avail = (rdev->sb_offset*2) - rdev->data_offset; else avail = get_capacity(rdev->bdev->bd_disk) - rdev->data_offset; if (fit && (info->size == 0 || info->size > avail/2)) info->size = avail/2; if (avail < ((sector_t)info->size << 1)) return -ENOSPC; } rv = mddev->pers->resize(mddev, (sector_t)info->size *2); if (!rv) { struct block_device *bdev; bdev = bdget_disk(mddev->gendisk, 0); if (bdev) { down(&bdev->bd_inode->i_sem); i_size_write(bdev->bd_inode, mddev->array_size << 10); up(&bdev->bd_inode->i_sem); bdput(bdev); } } } if (mddev->raid_disks != info->raid_disks) { /* change the number of raid disks */ if (mddev->pers->reshape == NULL) return -EINVAL; if (info->raid_disks <= 0 || info->raid_disks >= mddev->max_disks) return -EINVAL; if (mddev->sync_thread) return -EBUSY; rv = mddev->pers->reshape(mddev, info->raid_disks); if (!rv) { struct block_device *bdev; bdev = bdget_disk(mddev->gendisk, 0); if (bdev) { down(&bdev->bd_inode->i_sem); i_size_write(bdev->bd_inode, mddev->array_size << 10); up(&bdev->bd_inode->i_sem); bdput(bdev); } } } md_update_sb(mddev); return rv;}static int set_disk_faulty(mddev_t *mddev, dev_t dev){ mdk_rdev_t *rdev; rdev = find_rdev(mddev, dev); if (!rdev) return -ENODEV; md_error(mddev, rdev); return 0;}static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err = 0; void __user *argp = (void __user *)arg; struct hd_geometry __user *loc = argp; mddev_t *mddev = NULL; if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Commands dealing with the RAID driver but not any * particular array: */ switch (cmd) { case RAID_VERSION: err = get_version(argp); goto done; case PRINT_RAID_DEBUG: err = 0; md_print_devices(); goto done;#ifndef MODULE case RAID_AUTORUN: err = 0; autostart_arrays(arg); goto done;#endif default:; } /* * Commands creating/starting a new array: */ mddev = inode->i_bdev->bd_disk->private_data; if (!mddev) { BUG(); goto abort; } if (cmd == START_ARRAY) { /* START_ARRAY doesn't need to lock the array as autostart_array * does the locking, and it could even be a different array */ static int cnt = 3; if (cnt > 0 ) { printk(KERN_WARNING "md: %s(pid %d) used deprecated START_ARRAY ioctl. " "This will not be supported beyond 2.6\n", current->comm, current->pid); cnt--; } err = autostart_array(new_decode_dev(arg)); if (err) { printk(KERN_WARNING "md: autostart failed!\n"); goto abort; } goto done; } err = mddev_lock(mddev); if (err) { printk(KERN_INFO "md: ioctl lock interrupted, reason %d, cmd %d\n", err, cmd); goto abort; } switch (cmd) { case SET_ARRAY_INFO: { mdu_array_info_t info; if (!arg) memset(&info, 0, sizeof(info)); else if (copy_from_user(&info, argp, sizeof(info))) { err = -EFAULT; goto abort_unlock; } if (mddev->pers) { err = update_array_info(mddev, &info); if (err) { printk(KERN_WARNING "md: couldn't update" " array info. %d\n", err); goto abort_unlock; } goto done_unlock; } if (!list_empty(&mddev->disks)) { printk(KERN_WARNING "md: array %s already has disks!\n", mdname(mddev)); err = -EBUSY; goto abort_unlock; } if (mddev->raid_disks) { printk(KERN_WARNING "md: array %s already initialised!\n", mdname(mddev)); err = -EBUSY; goto abort_unlock; } err = set_array_info(mddev, &info); if (err) { printk(KERN_WARNING "md: couldn't set" " array info. %d\n", err); goto abort_unlock; } } goto done_unlock; default:; } /* * Commands querying/configuring an existing array: */ /* if we are initialised yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { err = -ENODEV; goto abort_unlock; } /* * Commands even a read-only array can execute: */ switch (cmd) { case GET_ARRAY_INFO: err = get_array_info(mddev, argp); goto done_unlock; case GET_DISK_INFO: err = get_disk_info(mddev, argp); goto done_unlock; case RESTART_ARRAY_RW: err = restart_array(mddev); goto done_unlock; case STOP_ARRAY: err = do_md_stop (mddev, 0); goto done_unlock; case STOP_ARRAY_RO: err = do_md_stop (mddev, 1); goto done_unlock; /* * We have a problem here : there is no easy way to give a CHS * virtual geometry. We currently pretend that we have a 2 heads * 4 sectors (with a BIG number of cylinders...). This drives * dosfs just mad... ;-) */ case HDIO_GETGEO: if (!loc) { err = -EINVAL; goto abort_unlock; } err = put_user (2, (char __user *) &loc->heads); if (err) goto abort_unlock; err = put_user (4, (char __user *) &loc->sectors); if (err) goto abort_unlock; err = put_user(get_capacity(mddev->gendisk)/8, (short __user *) &loc->cylinders); if (err) goto abort_unlock; err = put_user (get_start_sect(inode->i_bdev), (long __user *) &loc->start); goto done_unlock; } /* * The remaining ioctls are changing the state of the * superblock, so we do not allow read-only arrays * here: */ if (mddev->ro) { err = -EROFS; goto abort_unlock; } switch (cmd) { case ADD_NEW_DISK: { mdu_disk_info_t info; if (copy_from_user(&info, argp, sizeof(info))) err = -EFAULT; else err = add_new_disk(mddev, &info); goto done_unlock; } case HOT_REMOVE_DISK: err = hot_remove_disk(mddev, new_decode_dev(arg)); goto done_unlock; case HOT_ADD_DISK: err = hot_add_disk(mddev, new_decode_dev(arg)); goto done_unlock; case SET_DISK_FAULTY: err = set_disk_faulty(mddev, new_decode_dev(arg)); goto done_unlock; case RUN_ARRAY: err = do_md_run (mddev); goto done_unlock; default: if (_IOC_TYPE(cmd) == MD_MAJOR) printk(KERN_WARNING "md: %s(pid %d) used" " obsolete MD ioctl, upgrade your" " software to use new ictls.\n", current->comm, current->pid); err = -EINVAL; goto abort_unlock; }done_unlock:abort_unlock: mddev_unlock(mddev); return err;done: if (err) MD_BUG();abort: return err;}static int md_open(struct inode *inode, struct file *file){ /* * Succeed if we can lock the mddev, which confirms that * it isn't being stopped right now. */ mddev_t *mddev = inode->i_bdev->bd_disk->private_data; int err; if ((err = mddev_lock(mddev))) goto out; err = 0; mddev_get(mddev); mddev_unlock(mddev); check_disk_change(inode->i_bdev); out: return err;}static int md_release(struct inode *inode, struct file * file){ mddev_t *mddev = inode->i_bdev->bd_disk->private_data; if (!mddev) BUG(); mddev_put(mddev); return 0;}static int md_media_changed(struct gendisk *disk){ mddev_t *mddev = disk->private_data; return mddev->changed;}static int md_revalidate(struct gendisk *disk){ mddev_t *mddev = disk->private_data; mddev->changed =
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?