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

📄 dm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static void unlock_fs(struct mapped_device *md);static void free_dev(struct mapped_device *md){	int minor = md->disk->first_minor;	if (md->suspended_bdev) {		unlock_fs(md);		bdput(md->suspended_bdev);	}	mempool_destroy(md->tio_pool);	mempool_destroy(md->io_pool);	bioset_free(md->bs);	del_gendisk(md->disk);	free_minor(minor);	spin_lock(&_minor_lock);	md->disk->private_data = NULL;	spin_unlock(&_minor_lock);	put_disk(md->disk);	blk_cleanup_queue(md->queue);	module_put(THIS_MODULE);	kfree(md);}/* * Bind a table to the device. */static void event_callback(void *context){	unsigned long flags;	LIST_HEAD(uevents);	struct mapped_device *md = (struct mapped_device *) context;	spin_lock_irqsave(&md->uevent_lock, flags);	list_splice_init(&md->uevent_list, &uevents);	spin_unlock_irqrestore(&md->uevent_lock, flags);	dm_send_uevents(&uevents, &md->disk->kobj);	atomic_inc(&md->event_nr);	wake_up(&md->eventq);}static void __set_size(struct mapped_device *md, sector_t size){	set_capacity(md->disk, size);	mutex_lock(&md->suspended_bdev->bd_inode->i_mutex);	i_size_write(md->suspended_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);	mutex_unlock(&md->suspended_bdev->bd_inode->i_mutex);}static int __bind(struct mapped_device *md, struct dm_table *t){	struct request_queue *q = md->queue;	sector_t size;	size = dm_table_get_size(t);	/*	 * Wipe any geometry if the size of the table changed.	 */	if (size != get_capacity(md->disk))		memset(&md->geometry, 0, sizeof(md->geometry));	if (md->suspended_bdev)		__set_size(md, size);	if (size == 0)		return 0;	dm_table_get(t);	dm_table_event_callback(t, event_callback, md);	write_lock(&md->map_lock);	md->map = t;	dm_table_set_restrictions(t, q);	write_unlock(&md->map_lock);	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. */int dm_create(int minor, struct mapped_device **result){	struct mapped_device *md;	md = alloc_dev(minor);	if (!md)		return -ENXIO;	*result = md;	return 0;}static struct mapped_device *dm_find_md(dev_t dev){	struct mapped_device *md;	unsigned minor = MINOR(dev);	if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))		return NULL;	spin_lock(&_minor_lock);	md = idr_find(&_minor_idr, minor);	if (md && (md == MINOR_ALLOCED ||		   (dm_disk(md)->first_minor != minor) ||		   test_bit(DMF_FREEING, &md->flags))) {		md = NULL;		goto out;	}out:	spin_unlock(&_minor_lock);	return md;}struct mapped_device *dm_get_md(dev_t dev){	struct mapped_device *md = dm_find_md(dev);	if (md)		dm_get(md);	return md;}void *dm_get_mdptr(struct mapped_device *md){	return md->interface_ptr;}void dm_set_mdptr(struct mapped_device *md, void *ptr){	md->interface_ptr = ptr;}void dm_get(struct mapped_device *md){	atomic_inc(&md->holders);}const char *dm_device_name(struct mapped_device *md){	return md->name;}EXPORT_SYMBOL_GPL(dm_device_name);void dm_put(struct mapped_device *md){	struct dm_table *map;	BUG_ON(test_bit(DMF_FREEING, &md->flags));	if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {		map = dm_get_table(md);		idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);		set_bit(DMF_FREEING, &md->flags);		spin_unlock(&_minor_lock);		if (!dm_suspended(md)) {			dm_table_presuspend_targets(map);			dm_table_postsuspend_targets(map);		}		__unbind(md);		dm_table_put(map);		free_dev(md);	}}EXPORT_SYMBOL_GPL(dm_put);/* * 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;		if (__split_bio(md, c))			bio_io_error(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 = -EINVAL;	down(&md->suspend_lock);	/* device must be suspended */	if (!dm_suspended(md))		goto out;	/* without bdev, the device size cannot be changed */	if (!md->suspended_bdev)		if (get_capacity(md->disk) != dm_table_get_size(table))			goto out;	__unbind(md);	r = __bind(md, table);out:	up(&md->suspend_lock);	return r;}/* * Functions to lock and unlock any filesystem running on the * device. */static int lock_fs(struct mapped_device *md){	int r;	WARN_ON(md->frozen_sb);	md->frozen_sb = freeze_bdev(md->suspended_bdev);	if (IS_ERR(md->frozen_sb)) {		r = PTR_ERR(md->frozen_sb);		md->frozen_sb = NULL;		return r;	}	set_bit(DMF_FROZEN, &md->flags);	/* don't bdput right now, we don't want the bdev	 * to go away while it is locked.	 */	return 0;}static void unlock_fs(struct mapped_device *md){	if (!test_bit(DMF_FROZEN, &md->flags))		return;	thaw_bdev(md->suspended_bdev, md->frozen_sb);	md->frozen_sb = NULL;	clear_bit(DMF_FROZEN, &md->flags);}/* * 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, unsigned suspend_flags){	struct dm_table *map = NULL;	unsigned long flags;	DECLARE_WAITQUEUE(wait, current);	struct bio *def;	int r = -EINVAL;	int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;	int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;	down(&md->suspend_lock);	if (dm_suspended(md))		goto out_unlock;	map = dm_get_table(md);	/*	 * DMF_NOFLUSH_SUSPENDING must be set before presuspend.	 * This flag is cleared before dm_suspend returns.	 */	if (noflush)		set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);	/* This does not get reverted if there's an error later. */	dm_table_presuspend_targets(map);	/* bdget() can stall if the pending I/Os are not flushed */	if (!noflush) {		md->suspended_bdev = bdget_disk(md->disk, 0);		if (!md->suspended_bdev) {			DMWARN("bdget failed in dm_suspend");			r = -ENOMEM;			goto flush_and_out;		}	}	/*	 * Flush I/O to the device.	 * noflush supersedes do_lockfs, because lock_fs() needs to flush I/Os.	 */	if (do_lockfs && !noflush) {		r = lock_fs(md);		if (r)			goto out;	}	/*	 * First we set the BLOCK_IO flag so no more ios will be mapped.	 */	down_write(&md->io_lock);	set_bit(DMF_BLOCK_IO, &md->flags);	add_wait_queue(&md->wait, &wait);	up_write(&md->io_lock);	/* unplug */	if (map)		dm_table_unplug_all(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->io_lock);	remove_wait_queue(&md->wait, &wait);	if (noflush) {		spin_lock_irqsave(&md->pushback_lock, flags);		clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);		bio_list_merge_head(&md->deferred, &md->pushback);		bio_list_init(&md->pushback);		spin_unlock_irqrestore(&md->pushback_lock, flags);	}	/* were we interrupted ? */	r = -EINTR;	if (atomic_read(&md->pending)) {		clear_bit(DMF_BLOCK_IO, &md->flags);		def = bio_list_get(&md->deferred);		__flush_deferred_io(md, def);		up_write(&md->io_lock);		unlock_fs(md);		goto out; /* pushback list is already flushed, so skip flush */	}	up_write(&md->io_lock);	dm_table_postsuspend_targets(map);	set_bit(DMF_SUSPENDED, &md->flags);	r = 0;flush_and_out:	if (r && noflush) {		/*		 * Because there may be already I/Os in the pushback list,		 * flush them before return.		 */		down_write(&md->io_lock);		spin_lock_irqsave(&md->pushback_lock, flags);		clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);		bio_list_merge_head(&md->deferred, &md->pushback);		bio_list_init(&md->pushback);		spin_unlock_irqrestore(&md->pushback_lock, flags);		def = bio_list_get(&md->deferred);		__flush_deferred_io(md, def);		up_write(&md->io_lock);	}out:	if (r && md->suspended_bdev) {		bdput(md->suspended_bdev);		md->suspended_bdev = NULL;	}	dm_table_put(map);out_unlock:	up(&md->suspend_lock);	return r;}int dm_resume(struct mapped_device *md){	int r = -EINVAL;	struct bio *def;	struct dm_table *map = NULL;	down(&md->suspend_lock);	if (!dm_suspended(md))		goto out;	map = dm_get_table(md);	if (!map || !dm_table_get_size(map))		goto out;	r = dm_table_resume_targets(map);	if (r)		goto out;	down_write(&md->io_lock);	clear_bit(DMF_BLOCK_IO, &md->flags);	def = bio_list_get(&md->deferred);	__flush_deferred_io(md, def);	up_write(&md->io_lock);	unlock_fs(md);	if (md->suspended_bdev) {		bdput(md->suspended_bdev);		md->suspended_bdev = NULL;	}	clear_bit(DMF_SUSPENDED, &md->flags);	dm_table_unplug_all(map);	dm_kobject_uevent(md);	r = 0;out:	dm_table_put(map);	up(&md->suspend_lock);	return r;}/*----------------------------------------------------------------- * Event notification. *---------------------------------------------------------------*/void dm_kobject_uevent(struct mapped_device *md){	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);}uint32_t dm_next_uevent_seq(struct mapped_device *md){	return atomic_add_return(1, &md->uevent_seq);}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)));}void dm_uevent_add(struct mapped_device *md, struct list_head *elist){	unsigned long flags;	spin_lock_irqsave(&md->uevent_lock, flags);	list_add(elist, &md->uevent_list);	spin_unlock_irqrestore(&md->uevent_lock, flags);}/* * 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);}int dm_noflush_suspending(struct dm_target *ti){	struct mapped_device *md = dm_table_get_md(ti->table);	int r = __noflush_suspending(md);	dm_put(md);	return r;}EXPORT_SYMBOL_GPL(dm_noflush_suspending);static struct block_device_operations dm_blk_dops = {	.open = dm_blk_open,	.release = dm_blk_close,	.ioctl = dm_blk_ioctl,	.getgeo = dm_blk_getgeo,	.owner = THIS_MODULE};EXPORT_SYMBOL(dm_get_mapinfo);/* * 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 <dm-devel@redhat.com>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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