Commit 802ea9d8 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 8494bcf5 a4afe76b
...@@ -231,9 +231,8 @@ config DM_CRYPT ...@@ -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 @@ ...@@ -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) ...@@ -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 @@ ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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) ...@@ -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, ...@@ -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 @@ static int multipath_busy(struct dm_target *ti) ...@@ -1666,11 +1703,13 @@ static int multipath_busy(struct dm_target *ti)
*---------------------------------------------------------------*/ *---------------------------------------------------------------*/
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ static int alloc_area(struct pstore *ps) ...@@ -200,16 +200,11 @@ static int alloc_area(struct pstore *ps)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 ...@@ -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)
......
...@@ -20,6 +20,7 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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 @@ static int __init local_init(void) ...@@ -312,6 +325,8 @@ static int __init local_init(void)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
if (setup_clone(clone, rq, tio)) { table = dm_get_live_table(md, &srcu_idx);
/* -ENOMEM */ if (!dm_table_mq_request_based(table)) {
free_rq_tio(tio); if (!clone_rq(rq, md, tio, gfp_mask)) {
return NULL; dm_put_live_table(md, srcu_idx);
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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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 @@ ...@@ -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); ...@@ -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); ...@@ -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); ...@@ -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 { ...@@ -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) ...@@ -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 { ...@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment