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