- Most significant change this cycle is request-based DM now supports
stacking ontop of blk-mq devices. This blk-mq support changes the model request-based DM uses for cloning a request to relying on calling blk_get_request() directly from the underlying blk-mq device. Early consumer of this code is Intel's emerging NVMe hardware; thanks to Keith Busch for working on, and pushing for, these changes. - A few other small fixes and cleanups across other DM targets. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJU3NRnAAoJEMUj8QotnQNavG0H/3yogMcHvKg9H+w0WmUQdwhN w99Wj3nkquAw2sm9yahKlAMBNY53iu/LHmC6/PaTpJetgdH7y1foTrRa0qjyeB2D DgNr8mOzxSxzX6CX9V8JMwqzky9XoG2IOt/7FeQQOpMqp4T1M2zgvbZtpl0lK/f3 lNaNBFpl+47NbGssD/WbtfI4Yy3hX0u406yGmQN5DxRyGTWD2AFqpA76g2mp8vrp wmw259gPr4oLhj3pDc0GkuiVn59ZR2Zp+2gs0jD5uKlDL84VP/nE+WNB+ny1Mnmt cOg8Q+W6/OosL66MKBHNsF0QS6DXNo5UvsN9fHGa5IUJw7Tsa11ZEPKHZGEbQw4= =RiN2 -----END PGP SIGNATURE----- Merge tag 'dm-3.20-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm Pull device mapper changes from Mike Snitzer: - The most significant change this cycle is request-based DM now supports stacking ontop of blk-mq devices. This blk-mq support changes the model request-based DM uses for cloning a request to relying on calling blk_get_request() directly from the underlying blk-mq device. An early consumer of this code is Intel's emerging NVMe hardware; thanks to Keith Busch for working on, and pushing for, these changes. - A few other small fixes and cleanups across other DM targets. * tag 'dm-3.20-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm: inherit QUEUE_FLAG_SG_GAPS flags from underlying queues dm snapshot: remove unnecessary NULL checks before vfree() calls dm mpath: simplify failure path of dm_multipath_init() dm thin metadata: remove unused dm_pool_get_data_block_size() dm ioctl: fix stale comment above dm_get_inactive_table() dm crypt: update url in CONFIG_DM_CRYPT help text dm bufio: fix time comparison to use time_after_eq() dm: use time_in_range() and time_after() dm raid: fix a couple integer overflows dm table: train hybrid target type detection to select blk-mq if appropriate dm: allocate requests in target when stacking on blk-mq devices dm: prepare for allocating blk-mq clone requests in target dm: submit stacked requests in irq enabled context dm: split request structure out from dm_rq_target_io structure dm: remove exports for request-based interfaces without external callers
This commit is contained in:
		
				commit
				
					
						802ea9d864
					
				
			
		
					 17 changed files with 415 additions and 197 deletions
				
			
		|  | @ -231,9 +231,8 @@ config DM_CRYPT | ||||||
| 	  transparently encrypts the data on it. You'll need to activate | 	  transparently encrypts the data on it. You'll need to activate | ||||||
| 	  the ciphers you're going to use in the cryptoapi configuration. | 	  the ciphers you're going to use in the cryptoapi configuration. | ||||||
| 
 | 
 | ||||||
| 	  Information on how to use dm-crypt can be found on | 	  For further information on dm-crypt and userspace tools see: | ||||||
| 
 | 	  <http://code.google.com/p/cryptsetup/wiki/DMCrypt> | ||||||
| 	  <http://www.saout.de/misc/dm-crypt/> |  | ||||||
| 
 | 
 | ||||||
| 	  To compile this code as a module, choose M here: the module will | 	  To compile this code as a module, choose M here: the module will | ||||||
| 	  be called dm-crypt. | 	  be called dm-crypt. | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include <linux/device-mapper.h> | #include <linux/device-mapper.h> | ||||||
| #include <linux/dm-io.h> | #include <linux/dm-io.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
|  | #include <linux/jiffies.h> | ||||||
| #include <linux/vmalloc.h> | #include <linux/vmalloc.h> | ||||||
| #include <linux/shrinker.h> | #include <linux/shrinker.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
|  | @ -1739,7 +1740,7 @@ static unsigned get_max_age_hz(void) | ||||||
| 
 | 
 | ||||||
| static bool older_than(struct dm_buffer *b, unsigned long age_hz) | static bool older_than(struct dm_buffer *b, unsigned long age_hz) | ||||||
| { | { | ||||||
| 	return (jiffies - b->last_accessed) >= age_hz; | 	return time_after_eq(jiffies, b->last_accessed + age_hz); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz) | static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz) | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/dm-io.h> | #include <linux/dm-io.h> | ||||||
| #include <linux/dm-kcopyd.h> | #include <linux/dm-kcopyd.h> | ||||||
|  | #include <linux/jiffies.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/mempool.h> | #include <linux/mempool.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
|  | @ -1562,8 +1563,8 @@ static void process_bio(struct cache *cache, struct prealloc *structs, | ||||||
| 
 | 
 | ||||||
| static int need_commit_due_to_time(struct cache *cache) | static int need_commit_due_to_time(struct cache *cache) | ||||||
| { | { | ||||||
| 	return jiffies < cache->last_commit_jiffies || | 	return !time_in_range(jiffies, cache->last_commit_jiffies, | ||||||
| 	       jiffies > cache->last_commit_jiffies + COMMIT_PERIOD; | 			      cache->last_commit_jiffies + COMMIT_PERIOD); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int commit_if_needed(struct cache *cache) | static int commit_if_needed(struct cache *cache) | ||||||
|  |  | ||||||
|  | @ -639,8 +639,8 @@ static int check_name(const char *name) | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * On successful return, the caller must not attempt to acquire |  * On successful return, the caller must not attempt to acquire | ||||||
|  * _hash_lock without first calling dm_table_put, because dm_table_destroy |  * _hash_lock without first calling dm_put_live_table, because dm_table_destroy | ||||||
|  * waits for this dm_table_put and could be called under this lock. |  * waits for this dm_put_live_table and could be called under this lock. | ||||||
|  */ |  */ | ||||||
| static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx) | static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/bio.h> | #include <linux/bio.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
|  | #include <linux/jiffies.h> | ||||||
| #include <linux/dm-dirty-log.h> | #include <linux/dm-dirty-log.h> | ||||||
| #include <linux/device-mapper.h> | #include <linux/device-mapper.h> | ||||||
| #include <linux/dm-log-userspace.h> | #include <linux/dm-log-userspace.h> | ||||||
|  | @ -829,7 +830,7 @@ static int userspace_is_remote_recovering(struct dm_dirty_log *log, | ||||||
| 	int r; | 	int r; | ||||||
| 	uint64_t region64 = region; | 	uint64_t region64 = region; | ||||||
| 	struct log_c *lc = log->context; | 	struct log_c *lc = log->context; | ||||||
| 	static unsigned long long limit; | 	static unsigned long limit; | ||||||
| 	struct { | 	struct { | ||||||
| 		int64_t is_recovering; | 		int64_t is_recovering; | ||||||
| 		uint64_t in_sync_hint; | 		uint64_t in_sync_hint; | ||||||
|  | @ -845,7 +846,7 @@ static int userspace_is_remote_recovering(struct dm_dirty_log *log, | ||||||
| 	 */ | 	 */ | ||||||
| 	if (region < lc->in_sync_hint) | 	if (region < lc->in_sync_hint) | ||||||
| 		return 0; | 		return 0; | ||||||
| 	else if (jiffies < limit) | 	else if (time_after(limit, jiffies)) | ||||||
| 		return 1; | 		return 1; | ||||||
| 
 | 
 | ||||||
| 	limit = jiffies + (HZ / 4); | 	limit = jiffies + (HZ / 4); | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include "dm-path-selector.h" | #include "dm-path-selector.h" | ||||||
| #include "dm-uevent.h" | #include "dm-uevent.h" | ||||||
| 
 | 
 | ||||||
|  | #include <linux/blkdev.h> | ||||||
| #include <linux/ctype.h> | #include <linux/ctype.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/mempool.h> | #include <linux/mempool.h> | ||||||
|  | @ -378,18 +379,18 @@ static int __must_push_back(struct multipath *m) | ||||||
| /*
 | /*
 | ||||||
|  * Map cloned requests |  * Map cloned requests | ||||||
|  */ |  */ | ||||||
| static int multipath_map(struct dm_target *ti, struct request *clone, | static int __multipath_map(struct dm_target *ti, struct request *clone, | ||||||
| 			 union map_info *map_context) | 			   union map_info *map_context, | ||||||
|  | 			   struct request *rq, struct request **__clone) | ||||||
| { | { | ||||||
| 	struct multipath *m = (struct multipath *) ti->private; | 	struct multipath *m = (struct multipath *) ti->private; | ||||||
| 	int r = DM_MAPIO_REQUEUE; | 	int r = DM_MAPIO_REQUEUE; | ||||||
| 	size_t nr_bytes = blk_rq_bytes(clone); | 	size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq); | ||||||
| 	unsigned long flags; |  | ||||||
| 	struct pgpath *pgpath; | 	struct pgpath *pgpath; | ||||||
| 	struct block_device *bdev; | 	struct block_device *bdev; | ||||||
| 	struct dm_mpath_io *mpio; | 	struct dm_mpath_io *mpio; | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&m->lock, flags); | 	spin_lock_irq(&m->lock); | ||||||
| 
 | 
 | ||||||
| 	/* Do we need to select a new pgpath? */ | 	/* Do we need to select a new pgpath? */ | ||||||
| 	if (!m->current_pgpath || | 	if (!m->current_pgpath || | ||||||
|  | @ -411,25 +412,61 @@ static int multipath_map(struct dm_target *ti, struct request *clone, | ||||||
| 		/* ENOMEM, requeue */ | 		/* ENOMEM, requeue */ | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 
 | 
 | ||||||
| 	bdev = pgpath->path.dev->bdev; |  | ||||||
| 	clone->q = bdev_get_queue(bdev); |  | ||||||
| 	clone->rq_disk = bdev->bd_disk; |  | ||||||
| 	clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; |  | ||||||
| 	mpio = map_context->ptr; | 	mpio = map_context->ptr; | ||||||
| 	mpio->pgpath = pgpath; | 	mpio->pgpath = pgpath; | ||||||
| 	mpio->nr_bytes = nr_bytes; | 	mpio->nr_bytes = nr_bytes; | ||||||
|  | 
 | ||||||
|  | 	bdev = pgpath->path.dev->bdev; | ||||||
|  | 
 | ||||||
|  | 	spin_unlock_irq(&m->lock); | ||||||
|  | 
 | ||||||
|  | 	if (clone) { | ||||||
|  | 		/* Old request-based interface: allocated clone is passed in */ | ||||||
|  | 		clone->q = bdev_get_queue(bdev); | ||||||
|  | 		clone->rq_disk = bdev->bd_disk; | ||||||
|  | 		clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; | ||||||
|  | 	} else { | ||||||
|  | 		/* blk-mq request-based interface */ | ||||||
|  | 		*__clone = blk_get_request(bdev_get_queue(bdev), | ||||||
|  | 					   rq_data_dir(rq), GFP_KERNEL); | ||||||
|  | 		if (IS_ERR(*__clone)) | ||||||
|  | 			/* ENOMEM, requeue */ | ||||||
|  | 			return r; | ||||||
|  | 		(*__clone)->bio = (*__clone)->biotail = NULL; | ||||||
|  | 		(*__clone)->rq_disk = bdev->bd_disk; | ||||||
|  | 		(*__clone)->cmd_flags |= REQ_FAILFAST_TRANSPORT; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (pgpath->pg->ps.type->start_io) | 	if (pgpath->pg->ps.type->start_io) | ||||||
| 		pgpath->pg->ps.type->start_io(&pgpath->pg->ps, | 		pgpath->pg->ps.type->start_io(&pgpath->pg->ps, | ||||||
| 					      &pgpath->path, | 					      &pgpath->path, | ||||||
| 					      nr_bytes); | 					      nr_bytes); | ||||||
| 	r = DM_MAPIO_REMAPPED; | 	return DM_MAPIO_REMAPPED; | ||||||
| 
 | 
 | ||||||
| out_unlock: | out_unlock: | ||||||
| 	spin_unlock_irqrestore(&m->lock, flags); | 	spin_unlock_irq(&m->lock); | ||||||
| 
 | 
 | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int multipath_map(struct dm_target *ti, struct request *clone, | ||||||
|  | 			 union map_info *map_context) | ||||||
|  | { | ||||||
|  | 	return __multipath_map(ti, clone, map_context, NULL, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, | ||||||
|  | 				   union map_info *map_context, | ||||||
|  | 				   struct request **clone) | ||||||
|  | { | ||||||
|  | 	return __multipath_map(ti, NULL, map_context, rq, clone); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void multipath_release_clone(struct request *clone) | ||||||
|  | { | ||||||
|  | 	blk_put_request(clone); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * If we run out of usable paths, should we queue I/O or error it? |  * If we run out of usable paths, should we queue I/O or error it? | ||||||
|  */ |  */ | ||||||
|  | @ -1666,11 +1703,13 @@ out: | ||||||
|  *---------------------------------------------------------------*/ |  *---------------------------------------------------------------*/ | ||||||
| static struct target_type multipath_target = { | static struct target_type multipath_target = { | ||||||
| 	.name = "multipath", | 	.name = "multipath", | ||||||
| 	.version = {1, 7, 0}, | 	.version = {1, 8, 0}, | ||||||
| 	.module = THIS_MODULE, | 	.module = THIS_MODULE, | ||||||
| 	.ctr = multipath_ctr, | 	.ctr = multipath_ctr, | ||||||
| 	.dtr = multipath_dtr, | 	.dtr = multipath_dtr, | ||||||
| 	.map_rq = multipath_map, | 	.map_rq = multipath_map, | ||||||
|  | 	.clone_and_map_rq = multipath_clone_and_map, | ||||||
|  | 	.release_clone_rq = multipath_release_clone, | ||||||
| 	.rq_end_io = multipath_end_io, | 	.rq_end_io = multipath_end_io, | ||||||
| 	.presuspend = multipath_presuspend, | 	.presuspend = multipath_presuspend, | ||||||
| 	.postsuspend = multipath_postsuspend, | 	.postsuspend = multipath_postsuspend, | ||||||
|  | @ -1694,16 +1733,15 @@ static int __init dm_multipath_init(void) | ||||||
| 	r = dm_register_target(&multipath_target); | 	r = dm_register_target(&multipath_target); | ||||||
| 	if (r < 0) { | 	if (r < 0) { | ||||||
| 		DMERR("register failed %d", r); | 		DMERR("register failed %d", r); | ||||||
| 		kmem_cache_destroy(_mpio_cache); | 		r = -EINVAL; | ||||||
| 		return -EINVAL; | 		goto bad_register_target; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); | 	kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); | ||||||
| 	if (!kmultipathd) { | 	if (!kmultipathd) { | ||||||
| 		DMERR("failed to create workqueue kmpathd"); | 		DMERR("failed to create workqueue kmpathd"); | ||||||
| 		dm_unregister_target(&multipath_target); | 		r = -ENOMEM; | ||||||
| 		kmem_cache_destroy(_mpio_cache); | 		goto bad_alloc_kmultipathd; | ||||||
| 		return -ENOMEM; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1716,16 +1754,23 @@ static int __init dm_multipath_init(void) | ||||||
| 						  WQ_MEM_RECLAIM); | 						  WQ_MEM_RECLAIM); | ||||||
| 	if (!kmpath_handlerd) { | 	if (!kmpath_handlerd) { | ||||||
| 		DMERR("failed to create workqueue kmpath_handlerd"); | 		DMERR("failed to create workqueue kmpath_handlerd"); | ||||||
| 		destroy_workqueue(kmultipathd); | 		r = -ENOMEM; | ||||||
| 		dm_unregister_target(&multipath_target); | 		goto bad_alloc_kmpath_handlerd; | ||||||
| 		kmem_cache_destroy(_mpio_cache); |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	DMINFO("version %u.%u.%u loaded", | 	DMINFO("version %u.%u.%u loaded", | ||||||
| 	       multipath_target.version[0], multipath_target.version[1], | 	       multipath_target.version[0], multipath_target.version[1], | ||||||
| 	       multipath_target.version[2]); | 	       multipath_target.version[2]); | ||||||
| 
 | 
 | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | bad_alloc_kmpath_handlerd: | ||||||
|  | 	destroy_workqueue(kmultipathd); | ||||||
|  | bad_alloc_kmultipathd: | ||||||
|  | 	dm_unregister_target(&multipath_target); | ||||||
|  | bad_register_target: | ||||||
|  | 	kmem_cache_destroy(_mpio_cache); | ||||||
|  | 
 | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1237,7 +1237,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) | ||||||
| 	argv++; | 	argv++; | ||||||
| 
 | 
 | ||||||
| 	/* Skip over RAID params for now and find out # of devices */ | 	/* Skip over RAID params for now and find out # of devices */ | ||||||
| 	if (num_raid_params + 1 > argc) { | 	if (num_raid_params >= argc) { | ||||||
| 		ti->error = "Arguments do not agree with counts given"; | 		ti->error = "Arguments do not agree with counts given"; | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  | @ -1248,6 +1248,12 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */ | ||||||
|  | 	if (argc != (num_raid_devs * 2)) { | ||||||
|  | 		ti->error = "Supplied RAID devices does not match the count given"; | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	rs = context_alloc(ti, rt, (unsigned)num_raid_devs); | 	rs = context_alloc(ti, rt, (unsigned)num_raid_devs); | ||||||
| 	if (IS_ERR(rs)) | 	if (IS_ERR(rs)) | ||||||
| 		return PTR_ERR(rs); | 		return PTR_ERR(rs); | ||||||
|  | @ -1256,16 +1262,8 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto bad; | 		goto bad; | ||||||
| 
 | 
 | ||||||
| 	ret = -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */ |  | ||||||
| 	argv += num_raid_params + 1; | 	argv += num_raid_params + 1; | ||||||
| 
 | 
 | ||||||
| 	if (argc != (num_raid_devs * 2)) { |  | ||||||
| 		ti->error = "Supplied RAID devices does not match the count given"; |  | ||||||
| 		goto bad; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = dev_parms(rs, argv); | 	ret = dev_parms(rs, argv); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto bad; | 		goto bad; | ||||||
|  |  | ||||||
|  | @ -200,16 +200,11 @@ err_area: | ||||||
| 
 | 
 | ||||||
| static void free_area(struct pstore *ps) | static void free_area(struct pstore *ps) | ||||||
| { | { | ||||||
| 	if (ps->area) | 	vfree(ps->area); | ||||||
| 		vfree(ps->area); |  | ||||||
| 	ps->area = NULL; | 	ps->area = NULL; | ||||||
| 
 | 	vfree(ps->zero_area); | ||||||
| 	if (ps->zero_area) |  | ||||||
| 		vfree(ps->zero_area); |  | ||||||
| 	ps->zero_area = NULL; | 	ps->zero_area = NULL; | ||||||
| 
 | 	vfree(ps->header_area); | ||||||
| 	if (ps->header_area) |  | ||||||
| 		vfree(ps->header_area); |  | ||||||
| 	ps->header_area = NULL; | 	ps->header_area = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -605,8 +600,7 @@ static void persistent_dtr(struct dm_exception_store *store) | ||||||
| 	free_area(ps); | 	free_area(ps); | ||||||
| 
 | 
 | ||||||
| 	/* Allocated in persistent_read_metadata */ | 	/* Allocated in persistent_read_metadata */ | ||||||
| 	if (ps->callbacks) | 	vfree(ps->callbacks); | ||||||
| 		vfree(ps->callbacks); |  | ||||||
| 
 | 
 | ||||||
| 	kfree(ps); | 	kfree(ps); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -827,10 +827,11 @@ static int dm_table_set_type(struct dm_table *t) | ||||||
| { | { | ||||||
| 	unsigned i; | 	unsigned i; | ||||||
| 	unsigned bio_based = 0, request_based = 0, hybrid = 0; | 	unsigned bio_based = 0, request_based = 0, hybrid = 0; | ||||||
|  | 	bool use_blk_mq = false; | ||||||
| 	struct dm_target *tgt; | 	struct dm_target *tgt; | ||||||
| 	struct dm_dev_internal *dd; | 	struct dm_dev_internal *dd; | ||||||
| 	struct list_head *devices; | 	struct list_head *devices; | ||||||
| 	unsigned live_md_type; | 	unsigned live_md_type = dm_get_md_type(t->md); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < t->num_targets; i++) { | 	for (i = 0; i < t->num_targets; i++) { | ||||||
| 		tgt = t->targets + i; | 		tgt = t->targets + i; | ||||||
|  | @ -854,8 +855,8 @@ static int dm_table_set_type(struct dm_table *t) | ||||||
| 		 * Determine the type from the live device. | 		 * Determine the type from the live device. | ||||||
| 		 * Default to bio-based if device is new. | 		 * Default to bio-based if device is new. | ||||||
| 		 */ | 		 */ | ||||||
| 		live_md_type = dm_get_md_type(t->md); | 		if (live_md_type == DM_TYPE_REQUEST_BASED || | ||||||
| 		if (live_md_type == DM_TYPE_REQUEST_BASED) | 		    live_md_type == DM_TYPE_MQ_REQUEST_BASED) | ||||||
| 			request_based = 1; | 			request_based = 1; | ||||||
| 		else | 		else | ||||||
| 			bio_based = 1; | 			bio_based = 1; | ||||||
|  | @ -869,16 +870,6 @@ static int dm_table_set_type(struct dm_table *t) | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!request_based); /* No targets in this table */ | 	BUG_ON(!request_based); /* No targets in this table */ | ||||||
| 
 | 
 | ||||||
| 	/* Non-request-stackable devices can't be used for request-based dm */ |  | ||||||
| 	devices = dm_table_get_devices(t); |  | ||||||
| 	list_for_each_entry(dd, devices, list) { |  | ||||||
| 		if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev->bdev))) { |  | ||||||
| 			DMWARN("table load rejected: including" |  | ||||||
| 			       " non-request-stackable devices"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Request-based dm supports only tables that have a single target now. | 	 * Request-based dm supports only tables that have a single target now. | ||||||
| 	 * To support multiple targets, request splitting support is needed, | 	 * To support multiple targets, request splitting support is needed, | ||||||
|  | @ -890,7 +881,37 @@ static int dm_table_set_type(struct dm_table *t) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	t->type = DM_TYPE_REQUEST_BASED; | 	/* Non-request-stackable devices can't be used for request-based dm */ | ||||||
|  | 	devices = dm_table_get_devices(t); | ||||||
|  | 	list_for_each_entry(dd, devices, list) { | ||||||
|  | 		struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev); | ||||||
|  | 
 | ||||||
|  | 		if (!blk_queue_stackable(q)) { | ||||||
|  | 			DMERR("table load rejected: including" | ||||||
|  | 			      " non-request-stackable devices"); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (q->mq_ops) | ||||||
|  | 			use_blk_mq = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (use_blk_mq) { | ||||||
|  | 		/* verify _all_ devices in the table are blk-mq devices */ | ||||||
|  | 		list_for_each_entry(dd, devices, list) | ||||||
|  | 			if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) { | ||||||
|  | 				DMERR("table load rejected: not all devices" | ||||||
|  | 				      " are blk-mq request-stackable"); | ||||||
|  | 				return -EINVAL; | ||||||
|  | 			} | ||||||
|  | 		t->type = DM_TYPE_MQ_REQUEST_BASED; | ||||||
|  | 
 | ||||||
|  | 	} else if (hybrid && list_empty(devices) && live_md_type != DM_TYPE_NONE) { | ||||||
|  | 		/* inherit live MD type */ | ||||||
|  | 		t->type = live_md_type; | ||||||
|  | 
 | ||||||
|  | 	} else | ||||||
|  | 		t->type = DM_TYPE_REQUEST_BASED; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -907,7 +928,15 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t) | ||||||
| 
 | 
 | ||||||
| bool dm_table_request_based(struct dm_table *t) | bool dm_table_request_based(struct dm_table *t) | ||||||
| { | { | ||||||
| 	return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED; | 	unsigned table_type = dm_table_get_type(t); | ||||||
|  | 
 | ||||||
|  | 	return (table_type == DM_TYPE_REQUEST_BASED || | ||||||
|  | 		table_type == DM_TYPE_MQ_REQUEST_BASED); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool dm_table_mq_request_based(struct dm_table *t) | ||||||
|  | { | ||||||
|  | 	return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int dm_table_alloc_md_mempools(struct dm_table *t) | static int dm_table_alloc_md_mempools(struct dm_table *t) | ||||||
|  | @ -1360,6 +1389,14 @@ static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev, | ||||||
| 	return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); | 	return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int queue_supports_sg_gaps(struct dm_target *ti, struct dm_dev *dev, | ||||||
|  | 				  sector_t start, sector_t len, void *data) | ||||||
|  | { | ||||||
|  | 	struct request_queue *q = bdev_get_queue(dev->bdev); | ||||||
|  | 
 | ||||||
|  | 	return q && !test_bit(QUEUE_FLAG_SG_GAPS, &q->queue_flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static bool dm_table_all_devices_attribute(struct dm_table *t, | static bool dm_table_all_devices_attribute(struct dm_table *t, | ||||||
| 					   iterate_devices_callout_fn func) | 					   iterate_devices_callout_fn func) | ||||||
| { | { | ||||||
|  | @ -1480,6 +1517,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | ||||||
| 	else | 	else | ||||||
| 		queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); | 		queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); | ||||||
| 
 | 
 | ||||||
|  | 	if (dm_table_all_devices_attribute(t, queue_supports_sg_gaps)) | ||||||
|  | 		queue_flag_clear_unlocked(QUEUE_FLAG_SG_GAPS, q); | ||||||
|  | 	else | ||||||
|  | 		queue_flag_set_unlocked(QUEUE_FLAG_SG_GAPS, q); | ||||||
|  | 
 | ||||||
| 	dm_table_set_integrity(t); | 	dm_table_set_integrity(t); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  |  | ||||||
|  | @ -137,13 +137,26 @@ static int io_err_map_rq(struct dm_target *ti, struct request *clone, | ||||||
| 	return -EIO; | 	return -EIO; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq, | ||||||
|  | 				   union map_info *map_context, | ||||||
|  | 				   struct request **clone) | ||||||
|  | { | ||||||
|  | 	return -EIO; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void io_err_release_clone_rq(struct request *clone) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct target_type error_target = { | static struct target_type error_target = { | ||||||
| 	.name = "error", | 	.name = "error", | ||||||
| 	.version = {1, 2, 0}, | 	.version = {1, 3, 0}, | ||||||
| 	.ctr  = io_err_ctr, | 	.ctr  = io_err_ctr, | ||||||
| 	.dtr  = io_err_dtr, | 	.dtr  = io_err_dtr, | ||||||
| 	.map  = io_err_map, | 	.map  = io_err_map, | ||||||
| 	.map_rq = io_err_map_rq, | 	.map_rq = io_err_map_rq, | ||||||
|  | 	.clone_and_map_rq = io_err_clone_and_map_rq, | ||||||
|  | 	.release_clone_rq = io_err_release_clone_rq, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int __init dm_target_init(void) | int __init dm_target_init(void) | ||||||
|  |  | ||||||
|  | @ -1635,15 +1635,6 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result) |  | ||||||
| { |  | ||||||
| 	down_read(&pmd->root_lock); |  | ||||||
| 	*result = pmd->data_block_size; |  | ||||||
| 	up_read(&pmd->root_lock); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) | int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) | ||||||
| { | { | ||||||
| 	int r = -EINVAL; | 	int r = -EINVAL; | ||||||
|  |  | ||||||
|  | @ -182,8 +182,6 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, | ||||||
| int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, | int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, | ||||||
| 				  dm_block_t *result); | 				  dm_block_t *result); | ||||||
| 
 | 
 | ||||||
| int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result); |  | ||||||
| 
 |  | ||||||
| int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); | int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); | ||||||
| 
 | 
 | ||||||
| int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); | int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include <linux/device-mapper.h> | #include <linux/device-mapper.h> | ||||||
| #include <linux/dm-io.h> | #include <linux/dm-io.h> | ||||||
| #include <linux/dm-kcopyd.h> | #include <linux/dm-kcopyd.h> | ||||||
|  | #include <linux/jiffies.h> | ||||||
| #include <linux/log2.h> | #include <linux/log2.h> | ||||||
| #include <linux/list.h> | #include <linux/list.h> | ||||||
| #include <linux/rculist.h> | #include <linux/rculist.h> | ||||||
|  | @ -1700,8 +1701,8 @@ static void process_cell_fail(struct thin_c *tc, struct dm_bio_prison_cell *cell | ||||||
|  */ |  */ | ||||||
| static int need_commit_due_to_time(struct pool *pool) | static int need_commit_due_to_time(struct pool *pool) | ||||||
| { | { | ||||||
| 	return jiffies < pool->last_commit_jiffies || | 	return !time_in_range(jiffies, pool->last_commit_jiffies, | ||||||
| 	       jiffies > pool->last_commit_jiffies + COMMIT_PERIOD; | 			      pool->last_commit_jiffies + COMMIT_PERIOD); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define thin_pbd(node) rb_entry((node), struct dm_thin_endio_hook, rb_node) | #define thin_pbd(node) rb_entry((node), struct dm_thin_endio_hook, rb_node) | ||||||
|  |  | ||||||
							
								
								
									
										345
									
								
								drivers/md/dm.c
									
										
									
									
									
								
							
							
						
						
									
										345
									
								
								drivers/md/dm.c
									
										
									
									
									
								
							|  | @ -20,6 +20,7 @@ | ||||||
| #include <linux/hdreg.h> | #include <linux/hdreg.h> | ||||||
| #include <linux/delay.h> | #include <linux/delay.h> | ||||||
| #include <linux/wait.h> | #include <linux/wait.h> | ||||||
|  | #include <linux/kthread.h> | ||||||
| 
 | 
 | ||||||
| #include <trace/events/block.h> | #include <trace/events/block.h> | ||||||
| 
 | 
 | ||||||
|  | @ -78,7 +79,8 @@ struct dm_io { | ||||||
| struct dm_rq_target_io { | struct dm_rq_target_io { | ||||||
| 	struct mapped_device *md; | 	struct mapped_device *md; | ||||||
| 	struct dm_target *ti; | 	struct dm_target *ti; | ||||||
| 	struct request *orig, clone; | 	struct request *orig, *clone; | ||||||
|  | 	struct kthread_work work; | ||||||
| 	int error; | 	int error; | ||||||
| 	union map_info info; | 	union map_info info; | ||||||
| }; | }; | ||||||
|  | @ -179,6 +181,7 @@ struct mapped_device { | ||||||
| 	 * io objects are allocated from here. | 	 * io objects are allocated from here. | ||||||
| 	 */ | 	 */ | ||||||
| 	mempool_t *io_pool; | 	mempool_t *io_pool; | ||||||
|  | 	mempool_t *rq_pool; | ||||||
| 
 | 
 | ||||||
| 	struct bio_set *bs; | 	struct bio_set *bs; | ||||||
| 
 | 
 | ||||||
|  | @ -210,6 +213,9 @@ struct mapped_device { | ||||||
| 	unsigned internal_suspend_count; | 	unsigned internal_suspend_count; | ||||||
| 
 | 
 | ||||||
| 	struct dm_stats stats; | 	struct dm_stats stats; | ||||||
|  | 
 | ||||||
|  | 	struct kthread_worker kworker; | ||||||
|  | 	struct task_struct *kworker_task; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -217,6 +223,7 @@ struct mapped_device { | ||||||
|  */ |  */ | ||||||
| struct dm_md_mempools { | struct dm_md_mempools { | ||||||
| 	mempool_t *io_pool; | 	mempool_t *io_pool; | ||||||
|  | 	mempool_t *rq_pool; | ||||||
| 	struct bio_set *bs; | 	struct bio_set *bs; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -231,6 +238,7 @@ struct table_device { | ||||||
| #define RESERVED_MAX_IOS		1024 | #define RESERVED_MAX_IOS		1024 | ||||||
| static struct kmem_cache *_io_cache; | static struct kmem_cache *_io_cache; | ||||||
| static struct kmem_cache *_rq_tio_cache; | static struct kmem_cache *_rq_tio_cache; | ||||||
|  | static struct kmem_cache *_rq_cache; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Bio-based DM's mempools' reserved IOs set by the user. |  * Bio-based DM's mempools' reserved IOs set by the user. | ||||||
|  | @ -288,9 +296,14 @@ static int __init local_init(void) | ||||||
| 	if (!_rq_tio_cache) | 	if (!_rq_tio_cache) | ||||||
| 		goto out_free_io_cache; | 		goto out_free_io_cache; | ||||||
| 
 | 
 | ||||||
|  | 	_rq_cache = kmem_cache_create("dm_clone_request", sizeof(struct request), | ||||||
|  | 				      __alignof__(struct request), 0, NULL); | ||||||
|  | 	if (!_rq_cache) | ||||||
|  | 		goto out_free_rq_tio_cache; | ||||||
|  | 
 | ||||||
| 	r = dm_uevent_init(); | 	r = dm_uevent_init(); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		goto out_free_rq_tio_cache; | 		goto out_free_rq_cache; | ||||||
| 
 | 
 | ||||||
| 	deferred_remove_workqueue = alloc_workqueue("kdmremove", WQ_UNBOUND, 1); | 	deferred_remove_workqueue = alloc_workqueue("kdmremove", WQ_UNBOUND, 1); | ||||||
| 	if (!deferred_remove_workqueue) { | 	if (!deferred_remove_workqueue) { | ||||||
|  | @ -312,6 +325,8 @@ out_free_workqueue: | ||||||
| 	destroy_workqueue(deferred_remove_workqueue); | 	destroy_workqueue(deferred_remove_workqueue); | ||||||
| out_uevent_exit: | out_uevent_exit: | ||||||
| 	dm_uevent_exit(); | 	dm_uevent_exit(); | ||||||
|  | out_free_rq_cache: | ||||||
|  | 	kmem_cache_destroy(_rq_cache); | ||||||
| out_free_rq_tio_cache: | out_free_rq_tio_cache: | ||||||
| 	kmem_cache_destroy(_rq_tio_cache); | 	kmem_cache_destroy(_rq_tio_cache); | ||||||
| out_free_io_cache: | out_free_io_cache: | ||||||
|  | @ -325,6 +340,7 @@ static void local_exit(void) | ||||||
| 	flush_scheduled_work(); | 	flush_scheduled_work(); | ||||||
| 	destroy_workqueue(deferred_remove_workqueue); | 	destroy_workqueue(deferred_remove_workqueue); | ||||||
| 
 | 
 | ||||||
|  | 	kmem_cache_destroy(_rq_cache); | ||||||
| 	kmem_cache_destroy(_rq_tio_cache); | 	kmem_cache_destroy(_rq_tio_cache); | ||||||
| 	kmem_cache_destroy(_io_cache); | 	kmem_cache_destroy(_io_cache); | ||||||
| 	unregister_blkdev(_major, _name); | 	unregister_blkdev(_major, _name); | ||||||
|  | @ -577,6 +593,17 @@ static void free_rq_tio(struct dm_rq_target_io *tio) | ||||||
| 	mempool_free(tio, tio->md->io_pool); | 	mempool_free(tio, tio->md->io_pool); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct request *alloc_clone_request(struct mapped_device *md, | ||||||
|  | 					   gfp_t gfp_mask) | ||||||
|  | { | ||||||
|  | 	return mempool_alloc(md->rq_pool, gfp_mask); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void free_clone_request(struct mapped_device *md, struct request *rq) | ||||||
|  | { | ||||||
|  | 	mempool_free(rq, md->rq_pool); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int md_in_flight(struct mapped_device *md) | static int md_in_flight(struct mapped_device *md) | ||||||
| { | { | ||||||
| 	return atomic_read(&md->pending[READ]) + | 	return atomic_read(&md->pending[READ]) + | ||||||
|  | @ -992,7 +1019,7 @@ static void end_clone_bio(struct bio *clone, int error) | ||||||
|  * the md may be freed in dm_put() at the end of this function. |  * the md may be freed in dm_put() at the end of this function. | ||||||
|  * Or do dm_get() before calling this function and dm_put() later. |  * Or do dm_get() before calling this function and dm_put() later. | ||||||
|  */ |  */ | ||||||
| static void rq_completed(struct mapped_device *md, int rw, int run_queue) | static void rq_completed(struct mapped_device *md, int rw, bool run_queue) | ||||||
| { | { | ||||||
| 	atomic_dec(&md->pending[rw]); | 	atomic_dec(&md->pending[rw]); | ||||||
| 
 | 
 | ||||||
|  | @ -1020,12 +1047,17 @@ static void free_rq_clone(struct request *clone) | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; | 	struct dm_rq_target_io *tio = clone->end_io_data; | ||||||
| 
 | 
 | ||||||
| 	blk_rq_unprep_clone(clone); | 	blk_rq_unprep_clone(clone); | ||||||
|  | 	if (clone->q && clone->q->mq_ops) | ||||||
|  | 		tio->ti->type->release_clone_rq(clone); | ||||||
|  | 	else | ||||||
|  | 		free_clone_request(tio->md, clone); | ||||||
| 	free_rq_tio(tio); | 	free_rq_tio(tio); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Complete the clone and the original request. |  * Complete the clone and the original request. | ||||||
|  * Must be called without queue lock. |  * Must be called without clone's queue lock held, | ||||||
|  |  * see end_clone_request() for more details. | ||||||
|  */ |  */ | ||||||
| static void dm_end_request(struct request *clone, int error) | static void dm_end_request(struct request *clone, int error) | ||||||
| { | { | ||||||
|  | @ -1054,23 +1086,23 @@ static void dm_end_request(struct request *clone, int error) | ||||||
| 
 | 
 | ||||||
| static void dm_unprep_request(struct request *rq) | static void dm_unprep_request(struct request *rq) | ||||||
| { | { | ||||||
| 	struct request *clone = rq->special; | 	struct dm_rq_target_io *tio = rq->special; | ||||||
|  | 	struct request *clone = tio->clone; | ||||||
| 
 | 
 | ||||||
| 	rq->special = NULL; | 	rq->special = NULL; | ||||||
| 	rq->cmd_flags &= ~REQ_DONTPREP; | 	rq->cmd_flags &= ~REQ_DONTPREP; | ||||||
| 
 | 
 | ||||||
| 	free_rq_clone(clone); | 	if (clone) | ||||||
|  | 		free_rq_clone(clone); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Requeue the original request of a clone. |  * Requeue the original request of a clone. | ||||||
|  */ |  */ | ||||||
| void dm_requeue_unmapped_request(struct request *clone) | static void dm_requeue_unmapped_original_request(struct mapped_device *md, | ||||||
|  | 						 struct request *rq) | ||||||
| { | { | ||||||
| 	int rw = rq_data_dir(clone); | 	int rw = rq_data_dir(rq); | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; |  | ||||||
| 	struct mapped_device *md = tio->md; |  | ||||||
| 	struct request *rq = tio->orig; |  | ||||||
| 	struct request_queue *q = rq->q; | 	struct request_queue *q = rq->q; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
|  | @ -1080,9 +1112,15 @@ void dm_requeue_unmapped_request(struct request *clone) | ||||||
| 	blk_requeue_request(q, rq); | 	blk_requeue_request(q, rq); | ||||||
| 	spin_unlock_irqrestore(q->queue_lock, flags); | 	spin_unlock_irqrestore(q->queue_lock, flags); | ||||||
| 
 | 
 | ||||||
| 	rq_completed(md, rw, 0); | 	rq_completed(md, rw, false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void dm_requeue_unmapped_request(struct request *clone) | ||||||
|  | { | ||||||
|  | 	struct dm_rq_target_io *tio = clone->end_io_data; | ||||||
|  | 
 | ||||||
|  | 	dm_requeue_unmapped_original_request(tio->md, tio->orig); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dm_requeue_unmapped_request); |  | ||||||
| 
 | 
 | ||||||
| static void __stop_queue(struct request_queue *q) | static void __stop_queue(struct request_queue *q) | ||||||
| { | { | ||||||
|  | @ -1151,8 +1189,15 @@ static void dm_done(struct request *clone, int error, bool mapped) | ||||||
| static void dm_softirq_done(struct request *rq) | static void dm_softirq_done(struct request *rq) | ||||||
| { | { | ||||||
| 	bool mapped = true; | 	bool mapped = true; | ||||||
| 	struct request *clone = rq->completion_data; | 	struct dm_rq_target_io *tio = rq->special; | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; | 	struct request *clone = tio->clone; | ||||||
|  | 
 | ||||||
|  | 	if (!clone) { | ||||||
|  | 		blk_end_request_all(rq, tio->error); | ||||||
|  | 		rq_completed(tio->md, rq_data_dir(rq), false); | ||||||
|  | 		free_rq_tio(tio); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (rq->cmd_flags & REQ_FAILED) | 	if (rq->cmd_flags & REQ_FAILED) | ||||||
| 		mapped = false; | 		mapped = false; | ||||||
|  | @ -1164,13 +1209,11 @@ static void dm_softirq_done(struct request *rq) | ||||||
|  * Complete the clone and the original request with the error status |  * Complete the clone and the original request with the error status | ||||||
|  * through softirq context. |  * through softirq context. | ||||||
|  */ |  */ | ||||||
| static void dm_complete_request(struct request *clone, int error) | static void dm_complete_request(struct request *rq, int error) | ||||||
| { | { | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; | 	struct dm_rq_target_io *tio = rq->special; | ||||||
| 	struct request *rq = tio->orig; |  | ||||||
| 
 | 
 | ||||||
| 	tio->error = error; | 	tio->error = error; | ||||||
| 	rq->completion_data = clone; |  | ||||||
| 	blk_complete_request(rq); | 	blk_complete_request(rq); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1178,40 +1221,40 @@ static void dm_complete_request(struct request *clone, int error) | ||||||
|  * Complete the not-mapped clone and the original request with the error status |  * Complete the not-mapped clone and the original request with the error status | ||||||
|  * through softirq context. |  * through softirq context. | ||||||
|  * Target's rq_end_io() function isn't called. |  * Target's rq_end_io() function isn't called. | ||||||
|  * This may be used when the target's map_rq() function fails. |  * This may be used when the target's map_rq() or clone_and_map_rq() functions fail. | ||||||
|  */ |  */ | ||||||
| void dm_kill_unmapped_request(struct request *clone, int error) | static void dm_kill_unmapped_request(struct request *rq, int error) | ||||||
| { | { | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; |  | ||||||
| 	struct request *rq = tio->orig; |  | ||||||
| 
 |  | ||||||
| 	rq->cmd_flags |= REQ_FAILED; | 	rq->cmd_flags |= REQ_FAILED; | ||||||
| 	dm_complete_request(clone, error); | 	dm_complete_request(rq, error); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dm_kill_unmapped_request); |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Called with the queue lock held |  * Called with the clone's queue lock held | ||||||
|  */ |  */ | ||||||
| static void end_clone_request(struct request *clone, int error) | static void end_clone_request(struct request *clone, int error) | ||||||
| { | { | ||||||
| 	/*
 | 	struct dm_rq_target_io *tio = clone->end_io_data; | ||||||
| 	 * For just cleaning up the information of the queue in which | 
 | ||||||
| 	 * the clone was dispatched. | 	if (!clone->q->mq_ops) { | ||||||
| 	 * The clone is *NOT* freed actually here because it is alloced from | 		/*
 | ||||||
| 	 * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags. | 		 * For just cleaning up the information of the queue in which | ||||||
| 	 */ | 		 * the clone was dispatched. | ||||||
| 	__blk_put_request(clone->q, clone); | 		 * The clone is *NOT* freed actually here because it is alloced | ||||||
|  | 		 * from dm own mempool (REQ_ALLOCED isn't set). | ||||||
|  | 		 */ | ||||||
|  | 		__blk_put_request(clone->q, clone); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Actual request completion is done in a softirq context which doesn't | 	 * Actual request completion is done in a softirq context which doesn't | ||||||
| 	 * hold the queue lock.  Otherwise, deadlock could occur because: | 	 * hold the clone's queue lock.  Otherwise, deadlock could occur because: | ||||||
| 	 *     - another request may be submitted by the upper level driver | 	 *     - another request may be submitted by the upper level driver | ||||||
| 	 *       of the stacking during the completion | 	 *       of the stacking during the completion | ||||||
| 	 *     - the submission which requires queue lock may be done | 	 *     - the submission which requires queue lock may be done | ||||||
| 	 *       against this queue | 	 *       against this clone's queue | ||||||
| 	 */ | 	 */ | ||||||
| 	dm_complete_request(clone, error); | 	dm_complete_request(tio->orig, error); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1689,19 +1732,19 @@ static void dm_request(struct request_queue *q, struct bio *bio) | ||||||
| 		_dm_request(q, bio); | 		_dm_request(q, bio); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dm_dispatch_request(struct request *rq) | static void dm_dispatch_clone_request(struct request *clone, struct request *rq) | ||||||
| { | { | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	if (blk_queue_io_stat(rq->q)) | 	if (blk_queue_io_stat(clone->q)) | ||||||
| 		rq->cmd_flags |= REQ_IO_STAT; | 		clone->cmd_flags |= REQ_IO_STAT; | ||||||
| 
 | 
 | ||||||
| 	rq->start_time = jiffies; | 	clone->start_time = jiffies; | ||||||
| 	r = blk_insert_cloned_request(rq->q, rq); | 	r = blk_insert_cloned_request(clone->q, clone); | ||||||
| 	if (r) | 	if (r) | ||||||
|  | 		/* must complete clone in terms of original request */ | ||||||
| 		dm_complete_request(rq, r); | 		dm_complete_request(rq, r); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dm_dispatch_request); |  | ||||||
| 
 | 
 | ||||||
| static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig, | static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig, | ||||||
| 				 void *data) | 				 void *data) | ||||||
|  | @ -1718,12 +1761,11 @@ static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int setup_clone(struct request *clone, struct request *rq, | static int setup_clone(struct request *clone, struct request *rq, | ||||||
| 		       struct dm_rq_target_io *tio) | 		       struct dm_rq_target_io *tio, gfp_t gfp_mask) | ||||||
| { | { | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	blk_rq_init(NULL, clone); | 	r = blk_rq_prep_clone(clone, rq, tio->md->bs, gfp_mask, | ||||||
| 	r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC, |  | ||||||
| 			      dm_rq_bio_constructor, tio); | 			      dm_rq_bio_constructor, tio); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
|  | @ -1734,14 +1776,37 @@ static int setup_clone(struct request *clone, struct request *rq, | ||||||
| 	clone->end_io = end_clone_request; | 	clone->end_io = end_clone_request; | ||||||
| 	clone->end_io_data = tio; | 	clone->end_io_data = tio; | ||||||
| 
 | 
 | ||||||
|  | 	tio->clone = clone; | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct request *clone_rq(struct request *rq, struct mapped_device *md, | static struct request *clone_rq(struct request *rq, struct mapped_device *md, | ||||||
| 				gfp_t gfp_mask) | 				struct dm_rq_target_io *tio, gfp_t gfp_mask) | ||||||
|  | { | ||||||
|  | 	struct request *clone = alloc_clone_request(md, gfp_mask); | ||||||
|  | 
 | ||||||
|  | 	if (!clone) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	blk_rq_init(NULL, clone); | ||||||
|  | 	if (setup_clone(clone, rq, tio, gfp_mask)) { | ||||||
|  | 		/* -ENOMEM */ | ||||||
|  | 		free_clone_request(md, clone); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return clone; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void map_tio_request(struct kthread_work *work); | ||||||
|  | 
 | ||||||
|  | static struct dm_rq_target_io *prep_tio(struct request *rq, | ||||||
|  | 					struct mapped_device *md, gfp_t gfp_mask) | ||||||
| { | { | ||||||
| 	struct request *clone; |  | ||||||
| 	struct dm_rq_target_io *tio; | 	struct dm_rq_target_io *tio; | ||||||
|  | 	int srcu_idx; | ||||||
|  | 	struct dm_table *table; | ||||||
| 
 | 
 | ||||||
| 	tio = alloc_rq_tio(md, gfp_mask); | 	tio = alloc_rq_tio(md, gfp_mask); | ||||||
| 	if (!tio) | 	if (!tio) | ||||||
|  | @ -1749,18 +1814,23 @@ static struct request *clone_rq(struct request *rq, struct mapped_device *md, | ||||||
| 
 | 
 | ||||||
| 	tio->md = md; | 	tio->md = md; | ||||||
| 	tio->ti = NULL; | 	tio->ti = NULL; | ||||||
|  | 	tio->clone = NULL; | ||||||
| 	tio->orig = rq; | 	tio->orig = rq; | ||||||
| 	tio->error = 0; | 	tio->error = 0; | ||||||
| 	memset(&tio->info, 0, sizeof(tio->info)); | 	memset(&tio->info, 0, sizeof(tio->info)); | ||||||
|  | 	init_kthread_work(&tio->work, map_tio_request); | ||||||
| 
 | 
 | ||||||
| 	clone = &tio->clone; | 	table = dm_get_live_table(md, &srcu_idx); | ||||||
| 	if (setup_clone(clone, rq, tio)) { | 	if (!dm_table_mq_request_based(table)) { | ||||||
| 		/* -ENOMEM */ | 		if (!clone_rq(rq, md, tio, gfp_mask)) { | ||||||
| 		free_rq_tio(tio); | 			dm_put_live_table(md, srcu_idx); | ||||||
| 		return NULL; | 			free_rq_tio(tio); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | 	dm_put_live_table(md, srcu_idx); | ||||||
| 
 | 
 | ||||||
| 	return clone; | 	return tio; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1769,18 +1839,18 @@ static struct request *clone_rq(struct request *rq, struct mapped_device *md, | ||||||
| static int dm_prep_fn(struct request_queue *q, struct request *rq) | static int dm_prep_fn(struct request_queue *q, struct request *rq) | ||||||
| { | { | ||||||
| 	struct mapped_device *md = q->queuedata; | 	struct mapped_device *md = q->queuedata; | ||||||
| 	struct request *clone; | 	struct dm_rq_target_io *tio; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(rq->special)) { | 	if (unlikely(rq->special)) { | ||||||
| 		DMWARN("Already has something in rq->special."); | 		DMWARN("Already has something in rq->special."); | ||||||
| 		return BLKPREP_KILL; | 		return BLKPREP_KILL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	clone = clone_rq(rq, md, GFP_ATOMIC); | 	tio = prep_tio(rq, md, GFP_ATOMIC); | ||||||
| 	if (!clone) | 	if (!tio) | ||||||
| 		return BLKPREP_DEFER; | 		return BLKPREP_DEFER; | ||||||
| 
 | 
 | ||||||
| 	rq->special = clone; | 	rq->special = tio; | ||||||
| 	rq->cmd_flags |= REQ_DONTPREP; | 	rq->cmd_flags |= REQ_DONTPREP; | ||||||
| 
 | 
 | ||||||
| 	return BLKPREP_OK; | 	return BLKPREP_OK; | ||||||
|  | @ -1788,17 +1858,36 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq) | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Returns: |  * Returns: | ||||||
|  * 0  : the request has been processed (not requeued) |  * 0                : the request has been processed | ||||||
|  * !0 : the request has been requeued |  * DM_MAPIO_REQUEUE : the original request needs to be requeued | ||||||
|  |  * < 0              : the request was completed due to failure | ||||||
|  */ |  */ | ||||||
| static int map_request(struct dm_target *ti, struct request *clone, | static int map_request(struct dm_target *ti, struct request *rq, | ||||||
| 		       struct mapped_device *md) | 		       struct mapped_device *md) | ||||||
| { | { | ||||||
| 	int r, requeued = 0; | 	int r; | ||||||
| 	struct dm_rq_target_io *tio = clone->end_io_data; | 	struct dm_rq_target_io *tio = rq->special; | ||||||
|  | 	struct request *clone = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (tio->clone) { | ||||||
|  | 		clone = tio->clone; | ||||||
|  | 		r = ti->type->map_rq(ti, clone, &tio->info); | ||||||
|  | 	} else { | ||||||
|  | 		r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone); | ||||||
|  | 		if (r < 0) { | ||||||
|  | 			/* The target wants to complete the I/O */ | ||||||
|  | 			dm_kill_unmapped_request(rq, r); | ||||||
|  | 			return r; | ||||||
|  | 		} | ||||||
|  | 		if (IS_ERR(clone)) | ||||||
|  | 			return DM_MAPIO_REQUEUE; | ||||||
|  | 		if (setup_clone(clone, rq, tio, GFP_KERNEL)) { | ||||||
|  | 			/* -ENOMEM */ | ||||||
|  | 			ti->type->release_clone_rq(clone); | ||||||
|  | 			return DM_MAPIO_REQUEUE; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	tio->ti = ti; |  | ||||||
| 	r = ti->type->map_rq(ti, clone, &tio->info); |  | ||||||
| 	switch (r) { | 	switch (r) { | ||||||
| 	case DM_MAPIO_SUBMITTED: | 	case DM_MAPIO_SUBMITTED: | ||||||
| 		/* The target has taken the I/O to submit by itself later */ | 		/* The target has taken the I/O to submit by itself later */ | ||||||
|  | @ -1806,13 +1895,12 @@ static int map_request(struct dm_target *ti, struct request *clone, | ||||||
| 	case DM_MAPIO_REMAPPED: | 	case DM_MAPIO_REMAPPED: | ||||||
| 		/* The target has remapped the I/O so dispatch it */ | 		/* The target has remapped the I/O so dispatch it */ | ||||||
| 		trace_block_rq_remap(clone->q, clone, disk_devt(dm_disk(md)), | 		trace_block_rq_remap(clone->q, clone, disk_devt(dm_disk(md)), | ||||||
| 				     blk_rq_pos(tio->orig)); | 				     blk_rq_pos(rq)); | ||||||
| 		dm_dispatch_request(clone); | 		dm_dispatch_clone_request(clone, rq); | ||||||
| 		break; | 		break; | ||||||
| 	case DM_MAPIO_REQUEUE: | 	case DM_MAPIO_REQUEUE: | ||||||
| 		/* The target wants to requeue the I/O */ | 		/* The target wants to requeue the I/O */ | ||||||
| 		dm_requeue_unmapped_request(clone); | 		dm_requeue_unmapped_request(clone); | ||||||
| 		requeued = 1; |  | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		if (r > 0) { | 		if (r > 0) { | ||||||
|  | @ -1821,20 +1909,27 @@ static int map_request(struct dm_target *ti, struct request *clone, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* The target wants to complete the I/O */ | 		/* The target wants to complete the I/O */ | ||||||
| 		dm_kill_unmapped_request(clone, r); | 		dm_kill_unmapped_request(rq, r); | ||||||
| 		break; | 		return r; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return requeued; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct request *dm_start_request(struct mapped_device *md, struct request *orig) | static void map_tio_request(struct kthread_work *work) | ||||||
| { | { | ||||||
| 	struct request *clone; | 	struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work); | ||||||
|  | 	struct request *rq = tio->orig; | ||||||
|  | 	struct mapped_device *md = tio->md; | ||||||
| 
 | 
 | ||||||
|  | 	if (map_request(tio->ti, rq, md) == DM_MAPIO_REQUEUE) | ||||||
|  | 		dm_requeue_unmapped_original_request(md, rq); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void dm_start_request(struct mapped_device *md, struct request *orig) | ||||||
|  | { | ||||||
| 	blk_start_request(orig); | 	blk_start_request(orig); | ||||||
| 	clone = orig->special; | 	atomic_inc(&md->pending[rq_data_dir(orig)]); | ||||||
| 	atomic_inc(&md->pending[rq_data_dir(clone)]); |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Hold the md reference here for the in-flight I/O. | 	 * Hold the md reference here for the in-flight I/O. | ||||||
|  | @ -1844,8 +1939,6 @@ static struct request *dm_start_request(struct mapped_device *md, struct request | ||||||
| 	 * See the comment in rq_completed() too. | 	 * See the comment in rq_completed() too. | ||||||
| 	 */ | 	 */ | ||||||
| 	dm_get(md); | 	dm_get(md); | ||||||
| 
 |  | ||||||
| 	return clone; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1858,7 +1951,8 @@ static void dm_request_fn(struct request_queue *q) | ||||||
| 	int srcu_idx; | 	int srcu_idx; | ||||||
| 	struct dm_table *map = dm_get_live_table(md, &srcu_idx); | 	struct dm_table *map = dm_get_live_table(md, &srcu_idx); | ||||||
| 	struct dm_target *ti; | 	struct dm_target *ti; | ||||||
| 	struct request *rq, *clone; | 	struct request *rq; | ||||||
|  | 	struct dm_rq_target_io *tio; | ||||||
| 	sector_t pos; | 	sector_t pos; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1880,34 +1974,29 @@ static void dm_request_fn(struct request_queue *q) | ||||||
| 		ti = dm_table_find_target(map, pos); | 		ti = dm_table_find_target(map, pos); | ||||||
| 		if (!dm_target_is_valid(ti)) { | 		if (!dm_target_is_valid(ti)) { | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Must perform setup, that dm_done() requires, | 			 * Must perform setup, that rq_completed() requires, | ||||||
| 			 * before calling dm_kill_unmapped_request | 			 * before calling dm_kill_unmapped_request | ||||||
| 			 */ | 			 */ | ||||||
| 			DMERR_LIMIT("request attempted access beyond the end of device"); | 			DMERR_LIMIT("request attempted access beyond the end of device"); | ||||||
| 			clone = dm_start_request(md, rq); | 			dm_start_request(md, rq); | ||||||
| 			dm_kill_unmapped_request(clone, -EIO); | 			dm_kill_unmapped_request(rq, -EIO); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (ti->type->busy && ti->type->busy(ti)) | 		if (ti->type->busy && ti->type->busy(ti)) | ||||||
| 			goto delay_and_out; | 			goto delay_and_out; | ||||||
| 
 | 
 | ||||||
| 		clone = dm_start_request(md, rq); | 		dm_start_request(md, rq); | ||||||
| 
 |  | ||||||
| 		spin_unlock(q->queue_lock); |  | ||||||
| 		if (map_request(ti, clone, md)) |  | ||||||
| 			goto requeued; |  | ||||||
| 
 | 
 | ||||||
|  | 		tio = rq->special; | ||||||
|  | 		/* Establish tio->ti before queuing work (map_tio_request) */ | ||||||
|  | 		tio->ti = ti; | ||||||
|  | 		queue_kthread_work(&md->kworker, &tio->work); | ||||||
| 		BUG_ON(!irqs_disabled()); | 		BUG_ON(!irqs_disabled()); | ||||||
| 		spin_lock(q->queue_lock); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	goto out; | 	goto out; | ||||||
| 
 | 
 | ||||||
| requeued: |  | ||||||
| 	BUG_ON(!irqs_disabled()); |  | ||||||
| 	spin_lock(q->queue_lock); |  | ||||||
| 
 |  | ||||||
| delay_and_out: | delay_and_out: | ||||||
| 	blk_delay_queue(q, HZ / 10); | 	blk_delay_queue(q, HZ / 10); | ||||||
| out: | out: | ||||||
|  | @ -2093,6 +2182,7 @@ static struct mapped_device *alloc_dev(int minor) | ||||||
| 	INIT_WORK(&md->work, dm_wq_work); | 	INIT_WORK(&md->work, dm_wq_work); | ||||||
| 	init_waitqueue_head(&md->eventq); | 	init_waitqueue_head(&md->eventq); | ||||||
| 	init_completion(&md->kobj_holder.completion); | 	init_completion(&md->kobj_holder.completion); | ||||||
|  | 	md->kworker_task = NULL; | ||||||
| 
 | 
 | ||||||
| 	md->disk->major = _major; | 	md->disk->major = _major; | ||||||
| 	md->disk->first_minor = minor; | 	md->disk->first_minor = minor; | ||||||
|  | @ -2153,8 +2243,13 @@ static void free_dev(struct mapped_device *md) | ||||||
| 	unlock_fs(md); | 	unlock_fs(md); | ||||||
| 	bdput(md->bdev); | 	bdput(md->bdev); | ||||||
| 	destroy_workqueue(md->wq); | 	destroy_workqueue(md->wq); | ||||||
|  | 
 | ||||||
|  | 	if (md->kworker_task) | ||||||
|  | 		kthread_stop(md->kworker_task); | ||||||
| 	if (md->io_pool) | 	if (md->io_pool) | ||||||
| 		mempool_destroy(md->io_pool); | 		mempool_destroy(md->io_pool); | ||||||
|  | 	if (md->rq_pool) | ||||||
|  | 		mempool_destroy(md->rq_pool); | ||||||
| 	if (md->bs) | 	if (md->bs) | ||||||
| 		bioset_free(md->bs); | 		bioset_free(md->bs); | ||||||
| 	blk_integrity_unregister(md->disk); | 	blk_integrity_unregister(md->disk); | ||||||
|  | @ -2188,23 +2283,24 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t) | ||||||
| 			bioset_free(md->bs); | 			bioset_free(md->bs); | ||||||
| 			md->bs = p->bs; | 			md->bs = p->bs; | ||||||
| 			p->bs = NULL; | 			p->bs = NULL; | ||||||
| 		} else if (dm_table_get_type(t) == DM_TYPE_REQUEST_BASED) { |  | ||||||
| 			/*
 |  | ||||||
| 			 * There's no need to reload with request-based dm |  | ||||||
| 			 * because the size of front_pad doesn't change. |  | ||||||
| 			 * Note for future: If you are to reload bioset, |  | ||||||
| 			 * prep-ed requests in the queue may refer |  | ||||||
| 			 * to bio from the old bioset, so you must walk |  | ||||||
| 			 * through the queue to unprep. |  | ||||||
| 			 */ |  | ||||||
| 		} | 		} | ||||||
|  | 		/*
 | ||||||
|  | 		 * There's no need to reload with request-based dm | ||||||
|  | 		 * because the size of front_pad doesn't change. | ||||||
|  | 		 * Note for future: If you are to reload bioset, | ||||||
|  | 		 * prep-ed requests in the queue may refer | ||||||
|  | 		 * to bio from the old bioset, so you must walk | ||||||
|  | 		 * through the queue to unprep. | ||||||
|  | 		 */ | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!p || md->io_pool || md->bs); | 	BUG_ON(!p || md->io_pool || md->rq_pool || md->bs); | ||||||
| 
 | 
 | ||||||
| 	md->io_pool = p->io_pool; | 	md->io_pool = p->io_pool; | ||||||
| 	p->io_pool = NULL; | 	p->io_pool = NULL; | ||||||
|  | 	md->rq_pool = p->rq_pool; | ||||||
|  | 	p->rq_pool = NULL; | ||||||
| 	md->bs = p->bs; | 	md->bs = p->bs; | ||||||
| 	p->bs = NULL; | 	p->bs = NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -2407,6 +2503,14 @@ unsigned dm_get_md_type(struct mapped_device *md) | ||||||
| 	return md->type; | 	return md->type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool dm_md_type_request_based(struct mapped_device *md) | ||||||
|  | { | ||||||
|  | 	unsigned table_type = dm_get_md_type(md); | ||||||
|  | 
 | ||||||
|  | 	return (table_type == DM_TYPE_REQUEST_BASED || | ||||||
|  | 		table_type == DM_TYPE_MQ_REQUEST_BASED); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct target_type *dm_get_immutable_target_type(struct mapped_device *md) | struct target_type *dm_get_immutable_target_type(struct mapped_device *md) | ||||||
| { | { | ||||||
| 	return md->immutable_target_type; | 	return md->immutable_target_type; | ||||||
|  | @ -2444,6 +2548,11 @@ static int dm_init_request_based_queue(struct mapped_device *md) | ||||||
| 	blk_queue_prep_rq(md->queue, dm_prep_fn); | 	blk_queue_prep_rq(md->queue, dm_prep_fn); | ||||||
| 	blk_queue_lld_busy(md->queue, dm_lld_busy); | 	blk_queue_lld_busy(md->queue, dm_lld_busy); | ||||||
| 
 | 
 | ||||||
|  | 	/* Also initialize the request-based DM worker thread */ | ||||||
|  | 	init_kthread_worker(&md->kworker); | ||||||
|  | 	md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, | ||||||
|  | 				       "kdmwork-%s", dm_device_name(md)); | ||||||
|  | 
 | ||||||
| 	elv_register_queue(md->queue); | 	elv_register_queue(md->queue); | ||||||
| 
 | 
 | ||||||
| 	return 1; | 	return 1; | ||||||
|  | @ -2454,8 +2563,7 @@ static int dm_init_request_based_queue(struct mapped_device *md) | ||||||
|  */ |  */ | ||||||
| int dm_setup_md_queue(struct mapped_device *md) | int dm_setup_md_queue(struct mapped_device *md) | ||||||
| { | { | ||||||
| 	if ((dm_get_md_type(md) == DM_TYPE_REQUEST_BASED) && | 	if (dm_md_type_request_based(md) && !dm_init_request_based_queue(md)) { | ||||||
| 	    !dm_init_request_based_queue(md)) { |  | ||||||
| 		DMWARN("Cannot initialize queue for request-based mapped device"); | 		DMWARN("Cannot initialize queue for request-based mapped device"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  | @ -2534,6 +2642,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait) | ||||||
| 	set_bit(DMF_FREEING, &md->flags); | 	set_bit(DMF_FREEING, &md->flags); | ||||||
| 	spin_unlock(&_minor_lock); | 	spin_unlock(&_minor_lock); | ||||||
| 
 | 
 | ||||||
|  | 	if (dm_request_based(md)) | ||||||
|  | 		flush_kthread_worker(&md->kworker); | ||||||
|  | 
 | ||||||
| 	if (!dm_suspended_md(md)) { | 	if (!dm_suspended_md(md)) { | ||||||
| 		dm_table_presuspend_targets(map); | 		dm_table_presuspend_targets(map); | ||||||
| 		dm_table_postsuspend_targets(map); | 		dm_table_postsuspend_targets(map); | ||||||
|  | @ -2777,8 +2888,10 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map, | ||||||
| 	 * Stop md->queue before flushing md->wq in case request-based | 	 * Stop md->queue before flushing md->wq in case request-based | ||||||
| 	 * dm defers requests to md->wq from md->queue. | 	 * dm defers requests to md->wq from md->queue. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (dm_request_based(md)) | 	if (dm_request_based(md)) { | ||||||
| 		stop_queue(md->queue); | 		stop_queue(md->queue); | ||||||
|  | 		flush_kthread_worker(&md->kworker); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	flush_workqueue(md->wq); | 	flush_workqueue(md->wq); | ||||||
| 
 | 
 | ||||||
|  | @ -3124,24 +3237,35 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u | ||||||
| { | { | ||||||
| 	struct dm_md_mempools *pools = kzalloc(sizeof(*pools), GFP_KERNEL); | 	struct dm_md_mempools *pools = kzalloc(sizeof(*pools), GFP_KERNEL); | ||||||
| 	struct kmem_cache *cachep; | 	struct kmem_cache *cachep; | ||||||
| 	unsigned int pool_size; | 	unsigned int pool_size = 0; | ||||||
| 	unsigned int front_pad; | 	unsigned int front_pad; | ||||||
| 
 | 
 | ||||||
| 	if (!pools) | 	if (!pools) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	if (type == DM_TYPE_BIO_BASED) { | 	switch (type) { | ||||||
|  | 	case DM_TYPE_BIO_BASED: | ||||||
| 		cachep = _io_cache; | 		cachep = _io_cache; | ||||||
| 		pool_size = dm_get_reserved_bio_based_ios(); | 		pool_size = dm_get_reserved_bio_based_ios(); | ||||||
| 		front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); | 		front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); | ||||||
| 	} else if (type == DM_TYPE_REQUEST_BASED) { | 		break; | ||||||
| 		cachep = _rq_tio_cache; | 	case DM_TYPE_REQUEST_BASED: | ||||||
| 		pool_size = dm_get_reserved_rq_based_ios(); | 		pool_size = dm_get_reserved_rq_based_ios(); | ||||||
|  | 		pools->rq_pool = mempool_create_slab_pool(pool_size, _rq_cache); | ||||||
|  | 		if (!pools->rq_pool) | ||||||
|  | 			goto out; | ||||||
|  | 		/* fall through to setup remaining rq-based pools */ | ||||||
|  | 	case DM_TYPE_MQ_REQUEST_BASED: | ||||||
|  | 		cachep = _rq_tio_cache; | ||||||
|  | 		if (!pool_size) | ||||||
|  | 			pool_size = dm_get_reserved_rq_based_ios(); | ||||||
| 		front_pad = offsetof(struct dm_rq_clone_bio_info, clone); | 		front_pad = offsetof(struct dm_rq_clone_bio_info, clone); | ||||||
| 		/* per_bio_data_size is not used. See __bind_mempools(). */ | 		/* per_bio_data_size is not used. See __bind_mempools(). */ | ||||||
| 		WARN_ON(per_bio_data_size != 0); | 		WARN_ON(per_bio_data_size != 0); | ||||||
| 	} else | 		break; | ||||||
|  | 	default: | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	pools->io_pool = mempool_create_slab_pool(pool_size, cachep); | 	pools->io_pool = mempool_create_slab_pool(pool_size, cachep); | ||||||
| 	if (!pools->io_pool) | 	if (!pools->io_pool) | ||||||
|  | @ -3170,6 +3294,9 @@ void dm_free_md_mempools(struct dm_md_mempools *pools) | ||||||
| 	if (pools->io_pool) | 	if (pools->io_pool) | ||||||
| 		mempool_destroy(pools->io_pool); | 		mempool_destroy(pools->io_pool); | ||||||
| 
 | 
 | ||||||
|  | 	if (pools->rq_pool) | ||||||
|  | 		mempool_destroy(pools->rq_pool); | ||||||
|  | 
 | ||||||
| 	if (pools->bs) | 	if (pools->bs) | ||||||
| 		bioset_free(pools->bs); | 		bioset_free(pools->bs); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,9 +34,10 @@ | ||||||
| /*
 | /*
 | ||||||
|  * Type of table and mapped_device's mempool |  * Type of table and mapped_device's mempool | ||||||
|  */ |  */ | ||||||
| #define DM_TYPE_NONE		0 | #define DM_TYPE_NONE			0 | ||||||
| #define DM_TYPE_BIO_BASED	1 | #define DM_TYPE_BIO_BASED		1 | ||||||
| #define DM_TYPE_REQUEST_BASED	2 | #define DM_TYPE_REQUEST_BASED		2 | ||||||
|  | #define DM_TYPE_MQ_REQUEST_BASED	3 | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * List of devices that a metadevice uses and should open/close. |  * List of devices that a metadevice uses and should open/close. | ||||||
|  | @ -73,6 +74,7 @@ int dm_table_any_busy_target(struct dm_table *t); | ||||||
| unsigned dm_table_get_type(struct dm_table *t); | unsigned dm_table_get_type(struct dm_table *t); | ||||||
| struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); | struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); | ||||||
| bool dm_table_request_based(struct dm_table *t); | bool dm_table_request_based(struct dm_table *t); | ||||||
|  | bool dm_table_mq_request_based(struct dm_table *t); | ||||||
| void dm_table_free_md_mempools(struct dm_table *t); | void dm_table_free_md_mempools(struct dm_table *t); | ||||||
| struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); | struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); | ||||||
| 
 | 
 | ||||||
|  | @ -99,7 +101,8 @@ int dm_setup_md_queue(struct mapped_device *md); | ||||||
| /*
 | /*
 | ||||||
|  * To check whether the target type is request-based or not (bio-based). |  * To check whether the target type is request-based or not (bio-based). | ||||||
|  */ |  */ | ||||||
| #define dm_target_request_based(t) ((t)->type->map_rq != NULL) | #define dm_target_request_based(t) (((t)->type->map_rq != NULL) || \ | ||||||
|  | 				    ((t)->type->clone_and_map_rq != NULL)) | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * To check whether the target type is a hybrid (capable of being |  * To check whether the target type is a hybrid (capable of being | ||||||
|  |  | ||||||
|  | @ -48,6 +48,11 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti); | ||||||
| typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio); | typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio); | ||||||
| typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone, | typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone, | ||||||
| 				  union map_info *map_context); | 				  union map_info *map_context); | ||||||
|  | typedef int (*dm_clone_and_map_request_fn) (struct dm_target *ti, | ||||||
|  | 					    struct request *rq, | ||||||
|  | 					    union map_info *map_context, | ||||||
|  | 					    struct request **clone); | ||||||
|  | typedef void (*dm_release_clone_request_fn) (struct request *clone); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Returns: |  * Returns: | ||||||
|  | @ -143,6 +148,8 @@ struct target_type { | ||||||
| 	dm_dtr_fn dtr; | 	dm_dtr_fn dtr; | ||||||
| 	dm_map_fn map; | 	dm_map_fn map; | ||||||
| 	dm_map_request_fn map_rq; | 	dm_map_request_fn map_rq; | ||||||
|  | 	dm_clone_and_map_request_fn clone_and_map_rq; | ||||||
|  | 	dm_release_clone_request_fn release_clone_rq; | ||||||
| 	dm_endio_fn end_io; | 	dm_endio_fn end_io; | ||||||
| 	dm_request_endio_fn rq_end_io; | 	dm_request_endio_fn rq_end_io; | ||||||
| 	dm_presuspend_fn presuspend; | 	dm_presuspend_fn presuspend; | ||||||
|  | @ -600,9 +607,6 @@ static inline unsigned long to_bytes(sector_t n) | ||||||
| /*-----------------------------------------------------------------
 | /*-----------------------------------------------------------------
 | ||||||
|  * Helper for block layer and dm core operations |  * Helper for block layer and dm core operations | ||||||
|  *---------------------------------------------------------------*/ |  *---------------------------------------------------------------*/ | ||||||
| void dm_dispatch_request(struct request *rq); |  | ||||||
| void dm_requeue_unmapped_request(struct request *rq); |  | ||||||
| void dm_kill_unmapped_request(struct request *rq, int error); |  | ||||||
| int dm_underlying_device_busy(struct request_queue *q); | int dm_underlying_device_busy(struct request_queue *q); | ||||||
| 
 | 
 | ||||||
| #endif	/* _LINUX_DEVICE_MAPPER_H */ | #endif	/* _LINUX_DEVICE_MAPPER_H */ | ||||||
|  |  | ||||||
|  | @ -267,9 +267,9 @@ enum { | ||||||
| #define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | #define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | ||||||
| 
 | 
 | ||||||
| #define DM_VERSION_MAJOR	4 | #define DM_VERSION_MAJOR	4 | ||||||
| #define DM_VERSION_MINOR	29 | #define DM_VERSION_MINOR	30 | ||||||
| #define DM_VERSION_PATCHLEVEL	0 | #define DM_VERSION_PATCHLEVEL	0 | ||||||
| #define DM_VERSION_EXTRA	"-ioctl (2014-10-28)" | #define DM_VERSION_EXTRA	"-ioctl (2014-12-22)" | ||||||
| 
 | 
 | ||||||
| /* Status bits */ | /* Status bits */ | ||||||
| #define DM_READONLY_FLAG	(1 << 0) /* In/Out */ | #define DM_READONLY_FLAG	(1 << 0) /* In/Out */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus Torvalds
				Linus Torvalds