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 + -
显示快捷键?