Beispiel #1
0
Datei: dm.c Projekt: wxlong/Test
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;
}
Beispiel #2
0
Datei: dm.c Projekt: wxlong/Test
/*
 * Split the bio into several clones.
 */
static void __split_bio(struct mapped_device *md, struct bio *bio)
{
	struct clone_info ci;

	ci.map = dm_get_table(md);
	if (!ci.map) {
		bio_io_error(bio, bio->bi_size);
		return;
	}

	ci.md = md;
	ci.bio = bio;
	ci.io = alloc_io(md);
	ci.io->error = 0;
	atomic_set(&ci.io->io_count, 1);
	ci.io->bio = bio;
	ci.io->md = md;
	ci.sector = bio->bi_sector;
	ci.sector_count = bio_sectors(bio);
	ci.idx = bio->bi_idx;

	atomic_inc(&md->pending);
	while (ci.sector_count)
		__clone_and_map(&ci);

	/* drop the extra reference count */
	dec_pending(ci.io, 0);
	dm_table_put(ci.map);
}
/**ltl
 * 功能: 分割bio请求
 * 参数:
 * 返回值:
 * 说明:
 */
static void __split_bio(struct mapped_device *md, struct bio *bio)
{
	struct clone_info ci;

	ci.map = dm_get_table(md);
	if (!ci.map) {
		bio_io_error(bio, bio->bi_size);
		return;
	}

	ci.md = md;
	ci.bio = bio;
	ci.io = alloc_io(md);
	ci.io->error = 0;
	atomic_set(&ci.io->io_count, 1);
	ci.io->bio = bio;
	ci.io->md = md;
	ci.sector = bio->bi_sector;	/* 请求起始扇区 */
	
	/* 从这里可以看出数据长度必定是512的整数倍 */
	ci.sector_count = bio_sectors(bio); /* 数据长度(扇区数) */
	ci.idx = bio->bi_idx; /* 当前bi_vec数组下标 */

	start_io_acct(ci.io);
	while (ci.sector_count) /* 分发各个请求 */
		__clone_and_map(&ci);

	/* drop the extra reference count */
	dec_pending(ci.io, 0);
	dm_table_put(ci.map);
}
/**ltl
 * 功能: 映射设备的泄流处理函数
 * 参数:
 * 返回值:
 * 说明:
 */
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);
	}
}
Beispiel #5
0
Datei: dm.c Projekt: wxlong/Test
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);
	}
}
Beispiel #6
0
Datei: dm.c Projekt: wxlong/Test
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);
}
Beispiel #7
0
Datei: dm.c Projekt: wxlong/Test
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);
}
Beispiel #8
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(map);
		dm_table_put(map);
	}

	return ret;
}
Beispiel #9
0
Datei: dm.c Projekt: wxlong/Test
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;
}
Beispiel #10
0
int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
{
	struct dm_table *t;
	sector_t dev_size = 1;
	int r;

	/*
	 * Find current size of device.
	 * Default to 1 sector if inactive.
	 */
	t = dm_get_table(md);
	if (t) {
		dev_size = dm_table_get_size(t);
		dm_table_put(t);
	}

	r = dm_table_create(&t, FMODE_READ, 1, md);
	if (r)
		return r;

	r = dm_table_add_target(t, "error", 0, dev_size, NULL);
	if (r)
		goto out;

	r = dm_table_complete(t);
	if (r)
		goto out;

	*result = t;

out:
	if (r)
		dm_table_put(t);

	return r;
}
Beispiel #11
0
void dm_put(struct mapped_device *md)
{
	struct dm_table *map = dm_get_table(md);

	if (atomic_dec_and_test(&md->holders)) {
		if (!dm_suspended(md)) {
			dm_table_presuspend_targets(map);
			dm_table_postsuspend_targets(map);
		}
		__unbind(md);
		free_dev(md);
	}

	dm_table_put(map);
}
Beispiel #12
0
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);

	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);

	r = 0;

out:
	dm_table_put(map);
	up(&md->suspend_lock);

	return r;
}
Beispiel #13
0
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);
	}
}
Beispiel #14
0
static int dm_blk_ioctl(struct inode *inode, struct file *file,
			unsigned int cmd, unsigned long arg)
{
	struct mapped_device *md;
	struct dm_table *map;
	struct dm_target *tgt;
	int r = -ENOTTY;

	/* We don't really need this lock, but we do need 'inode'. */
	unlock_kernel();

	md = inode->i_bdev->bd_disk->private_data;

	map = dm_get_table(md);

	if (!map || !dm_table_get_size(map))
		goto out;

	/* We only support devices that have a single target */
	if (dm_table_get_num_targets(map) != 1)
		goto out;

	tgt = dm_table_get_target(map, 0);

	if (dm_suspended(md)) {
		r = -EAGAIN;
		goto out;
	}

	if (tgt->type->ioctl)
		r = tgt->type->ioctl(tgt, inode, file, cmd, arg);

out:
	dm_table_put(map);

	lock_kernel();
	return r;
}
Beispiel #15
0
Datei: dm.c Projekt: wxlong/Test
/*
 * 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;
}
static void __init dm_setup_drive(void)
{
	struct mapped_device *md = NULL;
	struct dm_table *table = NULL;
	struct dm_setup_target *target;
	char *uuid = dm_setup_args.uuid;
	fmode_t fmode = FMODE_READ;

	/* Finish parsing the targets. */
	if (dm_setup_parse_targets(dm_setup_args.targets))
		goto parse_fail;

	if (dm_create(dm_setup_args.minor, &md)) {
		DMDEBUG("failed to create the device");
		goto dm_create_fail;
	}
	DMDEBUG("created device '%s'", dm_device_name(md));

	/* In addition to flagging the table below, the disk must be
	 * set explicitly ro/rw. */
	set_disk_ro(dm_disk(md), dm_setup_args.ro);

	if (!dm_setup_args.ro)
		fmode |= FMODE_WRITE;
	if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) {
		DMDEBUG("failed to create the table");
		goto dm_table_create_fail;
	}

	target = dm_setup_args.target;
	while (target) {
		DMINFO("adding target '%llu %llu %s %s'",
		       (unsigned long long) target->begin,
		       (unsigned long long) target->length, target->type,
		       target->params);
		if (dm_table_add_target(table, target->type, target->begin,
					target->length, target->params)) {
			DMDEBUG("failed to add the target to the table");
			goto add_target_fail;
		}
		target = target->next;
	}

	if (dm_table_complete(table)) {
		DMDEBUG("failed to complete the table");
		goto table_complete_fail;
	}

	/* Suspend the device so that we can bind it to the table. */
	if (dm_suspend(md, 0)) {
		DMDEBUG("failed to suspend the device pre-bind");
		goto suspend_fail;
	}

	/* Bind the table to the device. This is the only way to associate
	 * md->map with the table and set the disk capacity directly. */
	if (dm_swap_table(md, table)) {  /* should return NULL. */
		DMDEBUG("failed to bind the device to the table");
		goto table_bind_fail;
	}

	/* Finally, resume and the device should be ready. */
	if (dm_resume(md)) {
		DMDEBUG("failed to resume the device");
		goto resume_fail;
	}

	/* Export the dm device via the ioctl interface */
	if (!strcmp(DM_NO_UUID, dm_setup_args.uuid))
		uuid = NULL;
	if (dm_ioctl_export(md, dm_setup_args.name, uuid)) {
		DMDEBUG("failed to export device with given name and uuid");
		goto export_fail;
	}
	printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor);

	dm_setup_cleanup();
	return;

export_fail:
resume_fail:
table_bind_fail:
suspend_fail:
table_complete_fail:
add_target_fail:
	dm_table_put(table);
dm_table_create_fail:
	dm_put(md);
dm_create_fail:
	dm_setup_cleanup();
parse_fail:
	printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n",
	       dm_setup_args.minor, dm_setup_args.name);
}
Beispiel #17
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, int do_lockfs)
{
	struct dm_table *map = NULL;
	DECLARE_WAITQUEUE(wait, current);
	struct bio *def;
	int r = -EINVAL;

	down(&md->suspend_lock);

	if (dm_suspended(md))
		goto out;

	map = dm_get_table(md);

	/* This does not get reverted if there's an error later. */
	dm_table_presuspend_targets(map);

	md->suspended_bdev = bdget_disk(md->disk, 0);
	if (!md->suspended_bdev) {
		DMWARN("bdget failed in dm_suspend");
		r = -ENOMEM;
		goto out;
	}

	/* Flush I/O to the device. */
	if (do_lockfs) {
		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);

	/* 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;
	}
	up_write(&md->io_lock);

	dm_table_postsuspend_targets(map);

	set_bit(DMF_SUSPENDED, &md->flags);

	r = 0;

out:
	if (r && md->suspended_bdev) {
		bdput(md->suspended_bdev);
		md->suspended_bdev = NULL;
	}

	dm_table_put(map);
	up(&md->suspend_lock);
	return r;
}
Beispiel #18
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, 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;
}