raid1.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,426 行 · 第 1/3 页

C
1,426
字号
				bio->bi_rw = READ;				unplug = 1;				generic_make_request(bio);			}		}	}	spin_unlock_irqrestore(&retry_list_lock, flags);	if (unplug)		unplug_slaves(mddev);}static int init_resync(conf_t *conf){	int buffs;	buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;	if (conf->r1buf_pool)		BUG();	conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free,					  conf->poolinfo);	if (!conf->r1buf_pool)		return -ENOMEM;	conf->next_resync = 0;	return 0;}/* * perform a "sync" on one "block" * * We need to make sure that no normal I/O request - particularly write * requests - conflict with active sync requests. * * This is achieved by tracking pending requests and a 'barrier' concept * that can be installed to exclude normal IO requests. */static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster){	conf_t *conf = mddev_to_conf(mddev);	mirror_info_t *mirror;	r1bio_t *r1_bio;	struct bio *bio;	sector_t max_sector, nr_sectors;	int disk;	int i;	int write_targets = 0;	if (!conf->r1buf_pool)		if (init_resync(conf))			return -ENOMEM;	max_sector = mddev->size << 1;	if (sector_nr >= max_sector) {		close_sync(conf);		return 0;	}	/*	 * If there is non-resync activity waiting for us then	 * put in a delay to throttle resync.	 */	if (!go_faster && waitqueue_active(&conf->wait_resume))		schedule_timeout(HZ);	device_barrier(conf, sector_nr + RESYNC_SECTORS);	/*	 * If reconstructing, and >1 working disc,	 * could dedicate one to rebuild and others to	 * service read requests ..	 */	disk = conf->last_used;	/* make sure disk is operational */	spin_lock_irq(&conf->device_lock);	while (conf->mirrors[disk].rdev == NULL ||	       !conf->mirrors[disk].rdev->in_sync) {		if (disk <= 0)			disk = conf->raid_disks;		disk--;		if (disk == conf->last_used)			break;	}	conf->last_used = disk;	atomic_inc(&conf->mirrors[disk].rdev->nr_pending);	spin_unlock_irq(&conf->device_lock);	mirror = conf->mirrors + disk;	r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO);	spin_lock_irq(&conf->resync_lock);	conf->nr_pending++;	spin_unlock_irq(&conf->resync_lock);	r1_bio->mddev = mddev;	r1_bio->sector = sector_nr;	set_bit(R1BIO_IsSync, &r1_bio->state);	r1_bio->read_disk = disk;	for (i=0; i < conf->raid_disks; i++) {		bio = r1_bio->bios[i];		/* take from bio_init */		bio->bi_next = NULL;		bio->bi_flags |= 1 << BIO_UPTODATE;		bio->bi_rw = 0;		bio->bi_vcnt = 0;		bio->bi_idx = 0;		bio->bi_phys_segments = 0;		bio->bi_hw_segments = 0;		bio->bi_size = 0;		bio->bi_end_io = NULL;		bio->bi_private = NULL;		if (i == disk) {			bio->bi_rw = READ;			bio->bi_end_io = end_sync_read;		} else if (conf->mirrors[i].rdev &&			   !conf->mirrors[i].rdev->faulty &&			   (!conf->mirrors[i].rdev->in_sync ||			    sector_nr + RESYNC_SECTORS > mddev->recovery_cp)) {			bio->bi_rw = WRITE;			bio->bi_end_io = end_sync_write;			write_targets ++;		} else			continue;		bio->bi_sector = sector_nr + conf->mirrors[i].rdev->data_offset;		bio->bi_bdev = conf->mirrors[i].rdev->bdev;		bio->bi_private = r1_bio;	}	if (write_targets == 0) {		/* There is nowhere to write, so all non-sync		 * drives must be failed - so we are finished		 */		int rv = max_sector - sector_nr;		md_done_sync(mddev, rv, 1);		put_buf(r1_bio);		atomic_dec(&conf->mirrors[disk].rdev->nr_pending);		return rv;	}	nr_sectors = 0;	do {		struct page *page;		int len = PAGE_SIZE;		if (sector_nr + (len>>9) > max_sector)			len = (max_sector - sector_nr) << 9;		if (len == 0)			break;		for (i=0 ; i < conf->raid_disks; i++) {			bio = r1_bio->bios[i];			if (bio->bi_end_io) {				page = r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page;				if (bio_add_page(bio, page, len, 0) == 0) {					/* stop here */					r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page = page;					while (i > 0) {						i--;						bio = r1_bio->bios[i];						if (bio->bi_end_io==NULL) continue;						/* remove last page from this bio */						bio->bi_vcnt--;						bio->bi_size -= len;						bio->bi_flags &= ~(1<< BIO_SEG_VALID);					}					goto bio_full;				}			}		}		nr_sectors += len>>9;		sector_nr += len>>9;	} while (r1_bio->bios[disk]->bi_vcnt < RESYNC_PAGES); bio_full:	bio = r1_bio->bios[disk];	r1_bio->sectors = nr_sectors;	md_sync_acct(mirror->rdev->bdev, nr_sectors);	generic_make_request(bio);	return nr_sectors;}static int run(mddev_t *mddev){	conf_t *conf;	int i, j, disk_idx;	mirror_info_t *disk;	mdk_rdev_t *rdev;	struct list_head *tmp;	if (mddev->level != 1) {		printk("raid1: %s: raid level not set to mirroring (%d)\n",		       mdname(mddev), mddev->level);		goto out;	}	/*	 * copy the already verified devices into our private RAID1	 * bookkeeping area. [whatever we allocate in run(),	 * should be freed in stop()]	 */	conf = kmalloc(sizeof(conf_t), GFP_KERNEL);	mddev->private = conf;	if (!conf)		goto out_no_mem;	memset(conf, 0, sizeof(*conf));	conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, 				 GFP_KERNEL);	if (!conf->mirrors)		goto out_no_mem;	memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks);	conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL);	if (!conf->poolinfo)		goto out_no_mem;	conf->poolinfo->mddev = mddev;	conf->poolinfo->raid_disks = mddev->raid_disks;	conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,					  r1bio_pool_free,					  conf->poolinfo);	if (!conf->r1bio_pool)		goto out_no_mem;	mddev->queue->unplug_fn = raid1_unplug;	mddev->queue->issue_flush_fn = raid1_issue_flush;	ITERATE_RDEV(mddev, rdev, tmp) {		disk_idx = rdev->raid_disk;		if (disk_idx >= mddev->raid_disks		    || disk_idx < 0)			continue;		disk = conf->mirrors + disk_idx;		disk->rdev = rdev;		blk_queue_stack_limits(mddev->queue,				       rdev->bdev->bd_disk->queue);		/* as we don't honour merge_bvec_fn, we must never risk		 * violating it, so limit ->max_sector to one PAGE, as		 * a one page request is never in violation.		 */		if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&		    mddev->queue->max_sectors > (PAGE_SIZE>>9))			blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);		disk->head_position = 0;		if (!rdev->faulty && rdev->in_sync)			conf->working_disks++;	}	conf->raid_disks = mddev->raid_disks;	conf->mddev = mddev;	conf->device_lock = SPIN_LOCK_UNLOCKED;	if (conf->working_disks == 1)		mddev->recovery_cp = MaxSector;	conf->resync_lock = SPIN_LOCK_UNLOCKED;	init_waitqueue_head(&conf->wait_idle);	init_waitqueue_head(&conf->wait_resume);	if (!conf->working_disks) {		printk(KERN_ERR "raid1: no operational mirrors for %s\n",			mdname(mddev));		goto out_free_conf;	}	mddev->degraded = 0;	for (i = 0; i < conf->raid_disks; i++) {		disk = conf->mirrors + i;		if (!disk->rdev) {			disk->head_position = 0;			mddev->degraded++;		}	}	/*	 * find the first working one and use it as a starting point	 * to read balancing.	 */	for (j = 0; j < conf->raid_disks &&		     (!conf->mirrors[j].rdev ||		      !conf->mirrors[j].rdev->in_sync) ; j++)		/* nothing */;	conf->last_used = j;	{		mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1");		if (!mddev->thread) {			printk(KERN_ERR 				"raid1: couldn't allocate thread for %s\n", 				mdname(mddev));			goto out_free_conf;		}	}	printk(KERN_INFO 		"raid1: raid set %s active with %d out of %d mirrors\n",		mdname(mddev), mddev->raid_disks - mddev->degraded, 		mddev->raid_disks);	/*	 * Ok, everything is just fine now	 */	mddev->array_size = mddev->size;	return 0;out_no_mem:	printk(KERN_ERR "raid1: couldn't allocate memory for %s\n",	       mdname(mddev));out_free_conf:	if (conf) {		if (conf->r1bio_pool)			mempool_destroy(conf->r1bio_pool);		if (conf->mirrors)			kfree(conf->mirrors);		if (conf->poolinfo)			kfree(conf->poolinfo);		kfree(conf);		mddev->private = NULL;	}out:	return -EIO;}static int stop(mddev_t *mddev){	conf_t *conf = mddev_to_conf(mddev);	md_unregister_thread(mddev->thread);	mddev->thread = NULL;	if (conf->r1bio_pool)		mempool_destroy(conf->r1bio_pool);	if (conf->mirrors)		kfree(conf->mirrors);	if (conf->poolinfo)		kfree(conf->poolinfo);	kfree(conf);	mddev->private = NULL;	return 0;}static int raid1_resize(mddev_t *mddev, sector_t sectors){	/* no resync is happening, and there is enough space	 * on all devices, so we can resize.	 * We need to make sure resync covers any new space.	 * If the array is shrinking we should possibly wait until	 * any io in the removed space completes, but it hardly seems	 * worth it.	 */	mddev->array_size = sectors>>1;	set_capacity(mddev->gendisk, mddev->array_size << 1);	mddev->changed = 1;	if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) {		mddev->recovery_cp = mddev->size << 1;		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);	}	mddev->size = mddev->array_size;	return 0;}static int raid1_reshape(mddev_t *mddev, int raid_disks){	/* We need to:	 * 1/ resize the r1bio_pool	 * 2/ resize conf->mirrors	 *	 * We allocate a new r1bio_pool if we can.	 * Then raise a device barrier and wait until all IO stops.	 * Then resize conf->mirrors and swap in the new r1bio pool.	 */	mempool_t *newpool, *oldpool;	struct pool_info *newpoolinfo;	mirror_info_t *newmirrors;	conf_t *conf = mddev_to_conf(mddev);	int d;	for (d= raid_disks; d < conf->raid_disks; d++)		if (conf->mirrors[d].rdev)			return -EBUSY;	newpoolinfo = kmalloc(sizeof(newpoolinfo), GFP_KERNEL);	if (!newpoolinfo)		return -ENOMEM;	newpoolinfo->mddev = mddev;	newpoolinfo->raid_disks = raid_disks;	newpool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,				 r1bio_pool_free, newpoolinfo);	if (!newpool) {		kfree(newpoolinfo);		return -ENOMEM;	}	newmirrors = kmalloc(sizeof(struct mirror_info) * raid_disks, GFP_KERNEL);	if (!newmirrors) {		kfree(newpoolinfo);		mempool_destroy(newpool);		return -ENOMEM;	}	memset(newmirrors, 0, sizeof(struct mirror_info)*raid_disks);	spin_lock_irq(&conf->resync_lock);	conf->barrier++;	wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,			    conf->resync_lock, unplug_slaves(mddev));	spin_unlock_irq(&conf->resync_lock);	/* ok, everything is stopped */	oldpool = conf->r1bio_pool;	conf->r1bio_pool = newpool;	for (d=0; d < raid_disks && d < conf->raid_disks; d++)		newmirrors[d] = conf->mirrors[d];	kfree(conf->mirrors);	conf->mirrors = newmirrors;	kfree(conf->poolinfo);	conf->poolinfo = newpoolinfo;	mddev->degraded += (raid_disks - conf->raid_disks);	conf->raid_disks = mddev->raid_disks = raid_disks;	spin_lock_irq(&conf->resync_lock);	conf->barrier--;	spin_unlock_irq(&conf->resync_lock);	wake_up(&conf->wait_resume);	wake_up(&conf->wait_idle);	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);	md_wakeup_thread(mddev->thread);	mempool_destroy(oldpool);	return 0;}static mdk_personality_t raid1_personality ={	.name		= "raid1",	.owner		= THIS_MODULE,	.make_request	= make_request,	.run		= run,	.stop		= stop,	.status		= status,	.error_handler	= error,	.hot_add_disk	= raid1_add_disk,	.hot_remove_disk= raid1_remove_disk,	.spare_active	= raid1_spare_active,	.sync_request	= sync_request,	.resize		= raid1_resize,	.reshape	= raid1_reshape,};static int __init raid_init(void){	return register_md_personality(RAID1, &raid1_personality);}static void raid_exit(void){	unregister_md_personality(RAID1);}module_init(raid_init);module_exit(raid_exit);MODULE_LICENSE("GPL");MODULE_ALIAS("md-personality-3"); /* RAID1 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?