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

📄 dm.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
			return 0;	/* deferred successfully */		/*		 * We're in a while loop, because someone could suspend		 * before we get to the following read lock.		 */		down_read(&md->lock);	}	__split_bio(md, bio);	up_read(&md->lock);	return 0;}static int dm_flush_all(request_queue_t *q, struct gendisk *disk,			sector_t *error_sector){	struct mapped_device *md = q->queuedata;	struct dm_table *map = dm_get_table(md);	int ret = -ENXIO;	if (map) {		ret = dm_table_flush_all(md->map);		dm_table_put(map);	}	return ret;}static void dm_unplug_all(request_queue_t *q){	struct mapped_device *md = q->queuedata;	struct dm_table *map = dm_get_table(md);	if (map) {		dm_table_unplug_all(map);		dm_table_put(map);	}}static int dm_any_congested(void *congested_data, int bdi_bits){	int r;	struct mapped_device *md = (struct mapped_device *) congested_data;	struct dm_table *map = dm_get_table(md);	if (!map || test_bit(DMF_BLOCK_IO, &md->flags))		r = bdi_bits;	else		r = dm_table_any_congested(map, bdi_bits);	dm_table_put(map);	return r;}/*----------------------------------------------------------------- * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/static DECLARE_MUTEX(_minor_lock);static DEFINE_IDR(_minor_idr);static void free_minor(unsigned int minor){	down(&_minor_lock);	idr_remove(&_minor_idr, minor);	up(&_minor_lock);}/* * See if the device with a specific minor # is free. */static int specific_minor(unsigned int minor){	int r, m;	if (minor >= (1 << MINORBITS))		return -EINVAL;	down(&_minor_lock);	if (idr_find(&_minor_idr, minor)) {		r = -EBUSY;		goto out;	}	r = idr_pre_get(&_minor_idr, GFP_KERNEL);	if (!r) {		r = -ENOMEM;		goto out;	}	r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m);	if (r) {		goto out;	}	if (m != minor) {		idr_remove(&_minor_idr, m);		r = -EBUSY;		goto out;	}out:	up(&_minor_lock);	return r;}static int next_free_minor(unsigned int *minor){	int r;	unsigned int m;	down(&_minor_lock);	r = idr_pre_get(&_minor_idr, GFP_KERNEL);	if (!r) {		r = -ENOMEM;		goto out;	}	r = idr_get_new(&_minor_idr, next_free_minor, &m);	if (r) {		goto out;	}	if (m >= (1 << MINORBITS)) {		idr_remove(&_minor_idr, m);		r = -ENOSPC;		goto out;	}	*minor = m;out:	up(&_minor_lock);	return r;}static struct block_device_operations dm_blk_dops;/* * Allocate and initialise a blank device with a given minor. */static struct mapped_device *alloc_dev(unsigned int minor, int persistent){	int r;	struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);	if (!md) {		DMWARN("unable to allocate device, out of memory.");		return NULL;	}	/* get a minor number for the dev */	r = persistent ? specific_minor(minor) : next_free_minor(&minor);	if (r < 0)		goto bad1;	memset(md, 0, sizeof(*md));	init_rwsem(&md->lock);	rwlock_init(&md->map_lock);	atomic_set(&md->holders, 1);	atomic_set(&md->event_nr, 0);	md->queue = blk_alloc_queue(GFP_KERNEL);	if (!md->queue)		goto bad1;	md->queue->queuedata = md;	md->queue->backing_dev_info.congested_fn = dm_any_congested;	md->queue->backing_dev_info.congested_data = md;	blk_queue_make_request(md->queue, dm_request);	md->queue->unplug_fn = dm_unplug_all;	md->queue->issue_flush_fn = dm_flush_all;	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,				     mempool_free_slab, _io_cache); 	if (!md->io_pool) 		goto bad2;	md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,				      mempool_free_slab, _tio_cache);	if (!md->tio_pool)		goto bad3;	md->disk = alloc_disk(1);	if (!md->disk)		goto bad4;	md->disk->major = _major;	md->disk->first_minor = minor;	md->disk->fops = &dm_blk_dops;	md->disk->queue = md->queue;	md->disk->private_data = md;	sprintf(md->disk->disk_name, "dm-%d", minor);	add_disk(md->disk);	atomic_set(&md->pending, 0);	init_waitqueue_head(&md->wait);	init_waitqueue_head(&md->eventq);	return md; bad4:	mempool_destroy(md->tio_pool); bad3:	mempool_destroy(md->io_pool); bad2:	blk_put_queue(md->queue);	free_minor(minor); bad1:	kfree(md);	return NULL;}static void free_dev(struct mapped_device *md){	free_minor(md->disk->first_minor);	mempool_destroy(md->tio_pool);	mempool_destroy(md->io_pool);	del_gendisk(md->disk);	put_disk(md->disk);	blk_put_queue(md->queue);	kfree(md);}/* * Bind a table to the device. */static void event_callback(void *context){	struct mapped_device *md = (struct mapped_device *) context;	atomic_inc(&md->event_nr);;	wake_up(&md->eventq);}static void __set_size(struct gendisk *disk, sector_t size){	struct block_device *bdev;	set_capacity(disk, size);	bdev = bdget_disk(disk, 0);	if (bdev) {		down(&bdev->bd_inode->i_sem);		i_size_write(bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);		up(&bdev->bd_inode->i_sem);		bdput(bdev);	}}static int __bind(struct mapped_device *md, struct dm_table *t){	request_queue_t *q = md->queue;	sector_t size;	size = dm_table_get_size(t);	__set_size(md->disk, size);	if (size == 0)		return 0;	write_lock(&md->map_lock);	md->map = t;	write_unlock(&md->map_lock);	dm_table_get(t);	dm_table_event_callback(md->map, event_callback, md);	dm_table_set_restrictions(t, q);	return 0;}static void __unbind(struct mapped_device *md){	struct dm_table *map = md->map;	if (!map)		return;	dm_table_event_callback(map, NULL, NULL);	write_lock(&md->map_lock);	md->map = NULL;	write_unlock(&md->map_lock);	dm_table_put(map);}/* * Constructor for a new device. */static int create_aux(unsigned int minor, int persistent,		      struct mapped_device **result){	struct mapped_device *md;	md = alloc_dev(minor, persistent);	if (!md)		return -ENXIO;	*result = md;	return 0;}int dm_create(struct mapped_device **result){	return create_aux(0, 0, result);}int dm_create_with_minor(unsigned int minor, struct mapped_device **result){	return create_aux(minor, 1, result);}void dm_get(struct mapped_device *md){	atomic_inc(&md->holders);}void dm_put(struct mapped_device *md){	struct dm_table *map = dm_get_table(md);	if (atomic_dec_and_test(&md->holders)) {		if (!test_bit(DMF_SUSPENDED, &md->flags) && map)			dm_table_suspend_targets(map);		__unbind(md);		free_dev(md);	}	dm_table_put(map);}/* * Process the deferred bios */static void __flush_deferred_io(struct mapped_device *md, struct bio *c){	struct bio *n;	while (c) {		n = c->bi_next;		c->bi_next = NULL;		__split_bio(md, c);		c = n;	}}/* * Swap in a new table (destroying old one). */int dm_swap_table(struct mapped_device *md, struct dm_table *table){	int r;	down_write(&md->lock);	/* device must be suspended */	if (!test_bit(DMF_SUSPENDED, &md->flags)) {		up_write(&md->lock);		return -EPERM;	}	__unbind(md);	r = __bind(md, table);	if (r)		return r;	up_write(&md->lock);	return 0;}/* * Functions to lock and unlock any filesystem running on the * device. */static int __lock_fs(struct mapped_device *md){	struct block_device *bdev;	if (test_and_set_bit(DMF_FS_LOCKED, &md->flags))		return 0;	bdev = bdget_disk(md->disk, 0);	if (!bdev) {		DMWARN("bdget failed in __lock_fs");		return -ENOMEM;	}	WARN_ON(md->frozen_sb);	md->frozen_sb = freeze_bdev(bdev);	/* don't bdput right now, we don't want the bdev	 * to go away while it is locked.  We'll bdput	 * in __unlock_fs	 */	return 0;}static int __unlock_fs(struct mapped_device *md){	struct block_device *bdev;	if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags))		return 0;	bdev = bdget_disk(md->disk, 0);	if (!bdev) {		DMWARN("bdget failed in __unlock_fs");		return -ENOMEM;	}	thaw_bdev(bdev, md->frozen_sb);	md->frozen_sb = NULL;	bdput(bdev);	bdput(bdev);	return 0;}/* * We need to be able to change a mapping table under a mounted * filesystem.  For example we might want to move some data in * the background.  Before the table can be swapped with * dm_bind_table, dm_suspend must be called to flush any in * flight bios and ensure that any further io gets deferred. */int dm_suspend(struct mapped_device *md){	struct dm_table *map;	DECLARE_WAITQUEUE(wait, current);	/* Flush I/O to the device. */	down_read(&md->lock);	if (test_bit(DMF_BLOCK_IO, &md->flags)) {		up_read(&md->lock);		return -EINVAL;	}	__lock_fs(md);	up_read(&md->lock);	/*	 * First we set the BLOCK_IO flag so no more ios will be	 * mapped.	 */	down_write(&md->lock);	if (test_bit(DMF_BLOCK_IO, &md->flags)) {		/*		 * If we get here we know another thread is		 * trying to suspend as well, so we leave the fs		 * locked for this thread.		 */		up_write(&md->lock);		return -EINVAL;	}	set_bit(DMF_BLOCK_IO, &md->flags);	add_wait_queue(&md->wait, &wait);	up_write(&md->lock);	/* unplug */	map = dm_get_table(md);	if (map) {		dm_table_unplug_all(map);		dm_table_put(map);	}	/*	 * Then we wait for the already mapped ios to	 * complete.	 */	while (1) {		set_current_state(TASK_INTERRUPTIBLE);		if (!atomic_read(&md->pending) || signal_pending(current))			break;		io_schedule();	}	set_current_state(TASK_RUNNING);	down_write(&md->lock);	remove_wait_queue(&md->wait, &wait);	/* were we interrupted ? */	if (atomic_read(&md->pending)) {		__unlock_fs(md);		clear_bit(DMF_BLOCK_IO, &md->flags);		up_write(&md->lock);		return -EINTR;	}	set_bit(DMF_SUSPENDED, &md->flags);	map = dm_get_table(md);	if (map)		dm_table_suspend_targets(map);	dm_table_put(map);	up_write(&md->lock);	return 0;}int dm_resume(struct mapped_device *md){	struct bio *def;	struct dm_table *map = dm_get_table(md);	down_write(&md->lock);	if (!map ||	    !test_bit(DMF_SUSPENDED, &md->flags) ||	    !dm_table_get_size(map)) {		up_write(&md->lock);		dm_table_put(map);		return -EINVAL;	}	dm_table_resume_targets(map);	clear_bit(DMF_SUSPENDED, &md->flags);	clear_bit(DMF_BLOCK_IO, &md->flags);	def = bio_list_get(&md->deferred);	__flush_deferred_io(md, def);	up_write(&md->lock);	__unlock_fs(md);	dm_table_unplug_all(map);	dm_table_put(map);	return 0;}/*----------------------------------------------------------------- * Event notification. *---------------------------------------------------------------*/uint32_t dm_get_event_nr(struct mapped_device *md){	return atomic_read(&md->event_nr);}int dm_wait_event(struct mapped_device *md, int event_nr){	return wait_event_interruptible(md->eventq,			(event_nr != atomic_read(&md->event_nr)));}/* * The gendisk is only valid as long as you have a reference * count on 'md'. */struct gendisk *dm_disk(struct mapped_device *md){	return md->disk;}int dm_suspended(struct mapped_device *md){	return test_bit(DMF_SUSPENDED, &md->flags);}static struct block_device_operations dm_blk_dops = {	.open = dm_blk_open,	.release = dm_blk_close,	.owner = THIS_MODULE};/* * module hooks */module_init(dm_init);module_exit(dm_exit);module_param(major, uint, 0);MODULE_PARM_DESC(major, "The major number of the device mapper");MODULE_DESCRIPTION(DM_NAME " driver");MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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