dm table: train hybrid target type detection to select blk-mq if appropriate
authorMike Snitzer <snitzer@redhat.com>
Thu, 18 Dec 2014 21:26:47 +0000 (16:26 -0500)
committerMike Snitzer <snitzer@redhat.com>
Mon, 9 Feb 2015 18:06:47 +0000 (13:06 -0500)
Otherwise replacing the multipath target with the error target fails:
  device-mapper: ioctl: can't change device type after initial table load.

The error target was mistakenly considered to be target type
DM_TYPE_REQUEST_BASED rather than DM_TYPE_MQ_REQUEST_BASED even if the
target it was to replace was of type DM_TYPE_MQ_REQUEST_BASED.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-table.c
drivers/md/dm.h

index 2d7e373955f398489fbb0de4df23060e7359433d..14954d844668011bc6770eebb6935de655171028 100644 (file)
@@ -831,7 +831,7 @@ static int dm_table_set_type(struct dm_table *t)
        struct dm_target *tgt;
        struct dm_dev_internal *dd;
        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++) {
                tgt = t->targets + i;
@@ -855,8 +855,8 @@ static int dm_table_set_type(struct dm_table *t)
                 * Determine the type from the live device.
                 * 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;
                else
                        bio_based = 1;
@@ -870,6 +870,17 @@ static int dm_table_set_type(struct dm_table *t)
 
        BUG_ON(!request_based); /* No targets in this table */
 
+       /*
+        * Request-based dm supports only tables that have a single target now.
+        * To support multiple targets, request splitting support is needed,
+        * and that needs lots of changes in the block-layer.
+        * (e.g. request completion process for partial completion.)
+        */
+       if (t->num_targets > 1) {
+               DMWARN("Request-based dm doesn't support multiple targets yet");
+               return -EINVAL;
+       }
+
        /* 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) {
@@ -893,20 +904,14 @@ static int dm_table_set_type(struct dm_table *t)
                                      " are blk-mq request-stackable");
                                return -EINVAL;
                        }
-       }
+               t->type = DM_TYPE_MQ_REQUEST_BASED;
 
-       /*
-        * Request-based dm supports only tables that have a single target now.
-        * To support multiple targets, request splitting support is needed,
-        * and that needs lots of changes in the block-layer.
-        * (e.g. request completion process for partial completion.)
-        */
-       if (t->num_targets > 1) {
-               DMWARN("Request-based dm doesn't support multiple targets yet");
-               return -EINVAL;
-       }
+       } else if (hybrid && list_empty(devices) && live_md_type != DM_TYPE_NONE) {
+               /* inherit live MD type */
+               t->type = live_md_type;
 
-       t->type = !use_blk_mq ? DM_TYPE_REQUEST_BASED : DM_TYPE_MQ_REQUEST_BASED;
+       } else
+               t->type = DM_TYPE_REQUEST_BASED;
 
        return 0;
 }
index 84d79784b8665e9525c05ea489066cb0d02b06b3..59f53e79db8264521dc00d2563c7b58182b7e0da 100644 (file)
@@ -101,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).
  */
-#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