⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm-raid1.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags,			recovery_complete, reg);	return r;}static void do_recovery(struct mirror_set *ms){	int r;	struct region *reg;	struct dirty_log *log = ms->rh.log;	/*	 * Start quiescing some regions.	 */	rh_recovery_prepare(&ms->rh);	/*	 * Copy any already quiesced regions.	 */	while ((reg = rh_recovery_start(&ms->rh))) {		r = recover(ms, reg);		if (r)			rh_recovery_end(reg, 0);	}	/*	 * Update the in sync flag.	 */	if (!ms->in_sync &&	    (log->type->get_sync_count(log) == ms->nr_regions)) {		/* the sync is complete */		dm_table_event(ms->ti->table);		ms->in_sync = 1;	}}/*----------------------------------------------------------------- * Reads *---------------------------------------------------------------*/static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector){	/* FIXME: add read balancing */	return ms->mirror + DEFAULT_MIRROR;}/* * remap a buffer to a particular mirror. */static void map_bio(struct mirror_set *ms, struct mirror *m, struct bio *bio){	bio->bi_bdev = m->dev->bdev;	bio->bi_sector = m->offset + (bio->bi_sector - ms->ti->begin);}static void do_reads(struct mirror_set *ms, struct bio_list *reads){	region_t region;	struct bio *bio;	struct mirror *m;	while ((bio = bio_list_pop(reads))) {		region = bio_to_region(&ms->rh, bio);		/*		 * We can only read balance if the region is in sync.		 */		if (rh_in_sync(&ms->rh, region, 0))			m = choose_mirror(ms, bio->bi_sector);		else			m = ms->mirror + DEFAULT_MIRROR;		map_bio(ms, m, bio);		generic_make_request(bio);	}}/*----------------------------------------------------------------- * Writes. * * We do different things with the write io depending on the * state of the region that it's in: * * SYNC: 	increment pending, use kcopyd to write to *all* mirrors * RECOVERING:	delay the io until recovery completes * NOSYNC:	increment pending, just write to the default mirror *---------------------------------------------------------------*/static void write_callback(unsigned long error, void *context){	unsigned int i;	int uptodate = 1;	struct bio *bio = (struct bio *) context;	struct mirror_set *ms;	ms = bio_get_ms(bio);	bio_set_ms(bio, NULL);	/*	 * NOTE: We don't decrement the pending count here,	 * instead it is done by the targets endio function.	 * This way we handle both writes to SYNC and NOSYNC	 * regions with the same code.	 */	if (error) {		/*		 * only error the io if all mirrors failed.		 * FIXME: bogus		 */		uptodate = 0;		for (i = 0; i < ms->nr_mirrors; i++)			if (!test_bit(i, &error)) {				uptodate = 1;				break;			}	}	bio_endio(bio, bio->bi_size, 0);}static void do_write(struct mirror_set *ms, struct bio *bio){	unsigned int i;	struct io_region io[KCOPYD_MAX_REGIONS+1];	struct mirror *m;	for (i = 0; i < ms->nr_mirrors; i++) {		m = ms->mirror + i;		io[i].bdev = m->dev->bdev;		io[i].sector = m->offset + (bio->bi_sector - ms->ti->begin);		io[i].count = bio->bi_size >> 9;	}	bio_set_ms(bio, ms);	dm_io_async_bvec(ms->nr_mirrors, io, WRITE,			 bio->bi_io_vec + bio->bi_idx,			 write_callback, bio);}static void do_writes(struct mirror_set *ms, struct bio_list *writes){	int state;	struct bio *bio;	struct bio_list sync, nosync, recover, *this_list = NULL;	if (!writes->head)		return;	/*	 * Classify each write.	 */	bio_list_init(&sync);	bio_list_init(&nosync);	bio_list_init(&recover);	while ((bio = bio_list_pop(writes))) {		state = rh_state(&ms->rh, bio_to_region(&ms->rh, bio), 1);		switch (state) {		case RH_CLEAN:		case RH_DIRTY:			this_list = &sync;			break;		case RH_NOSYNC:			this_list = &nosync;			break;		case RH_RECOVERING:			this_list = &recover;			break;		}		bio_list_add(this_list, bio);	}	/*	 * Increment the pending counts for any regions that will	 * be written to (writes to recover regions are going to	 * be delayed).	 */	rh_inc_pending(&ms->rh, &sync);	rh_inc_pending(&ms->rh, &nosync);	rh_flush(&ms->rh);	/*	 * Dispatch io.	 */	while ((bio = bio_list_pop(&sync)))		do_write(ms, bio);	while ((bio = bio_list_pop(&recover)))		rh_delay(&ms->rh, bio);	while ((bio = bio_list_pop(&nosync))) {		map_bio(ms, ms->mirror + DEFAULT_MIRROR, bio);		generic_make_request(bio);	}}/*----------------------------------------------------------------- * kmirrord *---------------------------------------------------------------*/static LIST_HEAD(_mirror_sets);static DECLARE_RWSEM(_mirror_sets_lock);static void do_mirror(struct mirror_set *ms){	struct bio_list reads, writes;	spin_lock(&ms->lock);	reads = ms->reads;	writes = ms->writes;	bio_list_init(&ms->reads);	bio_list_init(&ms->writes);	spin_unlock(&ms->lock);	rh_update_states(&ms->rh);	do_recovery(ms);	do_reads(ms, &reads);	do_writes(ms, &writes);}static void do_work(void *ignored){	struct mirror_set *ms;	down_read(&_mirror_sets_lock);	list_for_each_entry (ms, &_mirror_sets, list)		do_mirror(ms);	up_read(&_mirror_sets_lock);}/*----------------------------------------------------------------- * Target functions *---------------------------------------------------------------*/static struct mirror_set *alloc_context(unsigned int nr_mirrors,					sector_t region_size,					struct dm_target *ti,					struct dirty_log *dl){	size_t len;	struct mirror_set *ms = NULL;	if (array_too_big(sizeof(*ms), sizeof(ms->mirror[0]), nr_mirrors))		return NULL;	len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);	ms = kmalloc(len, GFP_KERNEL);	if (!ms) {		ti->error = "dm-mirror: Cannot allocate mirror context";		return NULL;	}	memset(ms, 0, len);	spin_lock_init(&ms->lock);	ms->ti = ti;	ms->nr_mirrors = nr_mirrors;	ms->nr_regions = dm_div_up(ti->len, region_size);	ms->in_sync = 0;	if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {		ti->error = "dm-mirror: Error creating dirty region hash";		kfree(ms);		return NULL;	}	return ms;}static void free_context(struct mirror_set *ms, struct dm_target *ti,			 unsigned int m){	while (m--)		dm_put_device(ti, ms->mirror[m].dev);	rh_exit(&ms->rh);	kfree(ms);}static inline int _check_region_size(struct dm_target *ti, sector_t size){	return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) ||		 size > ti->len);}static int get_mirror(struct mirror_set *ms, struct dm_target *ti,		      unsigned int mirror, char **argv){	sector_t offset;	if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) {		ti->error = "dm-mirror: Invalid offset";		return -EINVAL;	}	if (dm_get_device(ti, argv[0], offset, ti->len,			  dm_table_get_mode(ti->table),			  &ms->mirror[mirror].dev)) {		ti->error = "dm-mirror: Device lookup failure";		return -ENXIO;	}	ms->mirror[mirror].offset = offset;	return 0;}static int add_mirror_set(struct mirror_set *ms){	down_write(&_mirror_sets_lock);	list_add_tail(&ms->list, &_mirror_sets);	up_write(&_mirror_sets_lock);	wake();	return 0;}static void del_mirror_set(struct mirror_set *ms){	down_write(&_mirror_sets_lock);	list_del(&ms->list);	up_write(&_mirror_sets_lock);}/* * Create dirty log: log_type #log_params <log_params> */static struct dirty_log *create_dirty_log(struct dm_target *ti,					  unsigned int argc, char **argv,					  unsigned int *args_used){	unsigned int param_count;	struct dirty_log *dl;	if (argc < 2) {		ti->error = "dm-mirror: Insufficient mirror log arguments";		return NULL;	}	if (sscanf(argv[1], "%u", &param_count) != 1) {		ti->error = "dm-mirror: Invalid mirror log argument count";		return NULL;	}	*args_used = 2 + param_count;	if (argc < *args_used) {		ti->error = "dm-mirror: Insufficient mirror log arguments";		return NULL;	}	dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);	if (!dl) {		ti->error = "dm-mirror: Error creating mirror dirty log";		return NULL;	}	if (!_check_region_size(ti, dl->type->get_region_size(dl))) {		ti->error = "dm-mirror: Invalid region size";		dm_destroy_dirty_log(dl);		return NULL;	}	return dl;}/* * Construct a mirror mapping: * * log_type #log_params <log_params> * #mirrors [mirror_path offset]{2,} * * log_type is "core" or "disk" * #log_params is between 1 and 3 */#define DM_IO_PAGES 64static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv){	int r;	unsigned int nr_mirrors, m, args_used;	struct mirror_set *ms;	struct dirty_log *dl;	dl = create_dirty_log(ti, argc, argv, &args_used);	if (!dl)		return -EINVAL;	argv += args_used;	argc -= args_used;	if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||	    nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) {		ti->error = "dm-mirror: Invalid number of mirrors";		dm_destroy_dirty_log(dl);		return -EINVAL;	}	argv++, argc--;	if (argc != nr_mirrors * 2) {		ti->error = "dm-mirror: Wrong number of mirror arguments";		dm_destroy_dirty_log(dl);		return -EINVAL;	}	ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl);	if (!ms) {		dm_destroy_dirty_log(dl);		return -ENOMEM;	}	/* Get the mirror parameter sets */	for (m = 0; m < nr_mirrors; m++) {		r = get_mirror(ms, ti, m, argv);		if (r) {			free_context(ms, ti, m);			return r;		}		argv += 2;		argc -= 2;	}	ti->private = ms;	r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);	if (r) {		free_context(ms, ti, ms->nr_mirrors);		return r;	}	add_mirror_set(ms);	return 0;}static void mirror_dtr(struct dm_target *ti){	struct mirror_set *ms = (struct mirror_set *) ti->private;	del_mirror_set(ms);	kcopyd_client_destroy(ms->kcopyd_client);	free_context(ms, ti, ms->nr_mirrors);}static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw){	int should_wake = 0;	struct bio_list *bl;	bl = (rw == WRITE) ? &ms->writes : &ms->reads;	spin_lock(&ms->lock);	should_wake = !(bl->head);	bio_list_add(bl, bio);	spin_unlock(&ms->lock);	if (should_wake)		wake();}/* * Mirror mapping function */static int mirror_map(struct dm_target *ti, struct bio *bio,		      union map_info *map_context){	int r, rw = bio_rw(bio);	struct mirror *m;	struct mirror_set *ms = ti->private;	map_context->ll = bio->bi_sector >> ms->rh.region_shift;	if (rw == WRITE) {		queue_bio(ms, bio, rw);		return 0;	}	r = ms->rh.log->type->in_sync(ms->rh.log,				      bio_to_region(&ms->rh, bio), 0);	if (r < 0 && r != -EWOULDBLOCK)		return r;	if (r == -EWOULDBLOCK)	/* FIXME: ugly */		r = 0;	/*	 * We don't want to fast track a recovery just for a read	 * ahead.  So we just let it silently fail.	 * FIXME: get rid of this.	 */	if (!r && rw == READA)		return -EIO;	if (!r) {		/* Pass this io over to the daemon */		queue_bio(ms, bio, rw);		return 0;	}	m = choose_mirror(ms, bio->bi_sector);	if (!m)		return -EIO;	map_bio(ms, m, bio);	return 1;}static int mirror_end_io(struct dm_target *ti, struct bio *bio,			 int error, union map_info *map_context){	int rw = bio_rw(bio);	struct mirror_set *ms = (struct mirror_set *) ti->private;	region_t region = map_context->ll;	/*	 * We need to dec pending if this was a write.	 */	if (rw == WRITE)		rh_dec(&ms->rh, region);	return 0;}static void mirror_suspend(struct dm_target *ti){	struct mirror_set *ms = (struct mirror_set *) ti->private;	struct dirty_log *log = ms->rh.log;	rh_stop_recovery(&ms->rh);	if (log->type->suspend && log->type->suspend(log))		/* FIXME: need better error handling */		DMWARN("log suspend failed");}static void mirror_resume(struct dm_target *ti){	struct mirror_set *ms = (struct mirror_set *) ti->private;	struct dirty_log *log = ms->rh.log;	if (log->type->resume && log->type->resume(log))		/* FIXME: need better error handling */		DMWARN("log resume failed");	rh_start_recovery(&ms->rh);}static int mirror_status(struct dm_target *ti, status_type_t type,			 char *result, unsigned int maxlen){	char buffer[32];	unsigned int m, sz;	struct mirror_set *ms = (struct mirror_set *) ti->private;	sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);	switch (type) {	case STATUSTYPE_INFO:		DMEMIT("%d ", ms->nr_mirrors);		for (m = 0; m < ms->nr_mirrors; m++) {			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);			DMEMIT("%s ", buffer);		}		DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT,		       ms->rh.log->type->get_sync_count(ms->rh.log),		       ms->nr_regions);		break;	case STATUSTYPE_TABLE:		DMEMIT("%d ", ms->nr_mirrors);		for (m = 0; m < ms->nr_mirrors; m++) {			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);			DMEMIT("%s " SECTOR_FORMAT " ",			       buffer, ms->mirror[m].offset);		}	}	return 0;}static struct target_type mirror_target = {	.name	 = "mirror",	.version = {1, 0, 1},	.module	 = THIS_MODULE,	.ctr	 = mirror_ctr,	.dtr	 = mirror_dtr,	.map	 = mirror_map,	.end_io	 = mirror_end_io,	.suspend = mirror_suspend,	.resume	 = mirror_resume,	.status	 = mirror_status,};static int __init dm_mirror_init(void){	int r;	r = dm_dirty_log_init();	if (r)		return r;	_kmirrord_wq = create_workqueue("kmirrord");	if (!_kmirrord_wq) {		DMERR("couldn't start kmirrord");		dm_dirty_log_exit();		return r;	}	INIT_WORK(&_kmirrord_work, do_work, NULL);	r = dm_register_target(&mirror_target);	if (r < 0) {		DMERR("%s: Failed to register mirror target",		      mirror_target.name);		dm_dirty_log_exit();		destroy_workqueue(_kmirrord_wq);	}	return r;}static void __exit dm_mirror_exit(void){	int r;	r = dm_unregister_target(&mirror_target);	if (r < 0)		DMERR("%s: unregister failed %d", mirror_target.name, r);	destroy_workqueue(_kmirrord_wq);	dm_dirty_log_exit();}/* Module hooks */module_init(dm_mirror_init);module_exit(dm_mirror_exit);MODULE_DESCRIPTION(DM_NAME " mirror target");MODULE_AUTHOR("Joe Thornber");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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