dm: allow error target to replace bio-based and request-based targets
authorMike Snitzer <snitzer@redhat.com>
Thu, 22 Aug 2013 22:21:38 +0000 (18:21 -0400)
committerMike Snitzer <snitzer@redhat.com>
Fri, 6 Sep 2013 00:46:05 +0000 (20:46 -0400)
It may be useful to switch a request-based table to the "error" target.
Enhance the DM core to allow a hybrid target_type which is capable of
handling either bios (via .map) or requests (via .map_rq).

Add a request-based map function (.map_rq) to the "error" target_type;
making it DM's first hybrid target.  Train dm_table_set_type() to prefer
the mapped device's established type (request-based or bio-based).  If
the mapped device doesn't have an established type default to making the
table with the hybrid target(s) bio-based.

Tested 'dmsetup wipe_table' to work on both bio-based and request-based
devices.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Joe Jin <joe.jin@oracle.com>
Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Acked-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-table.c
drivers/md/dm-target.c
drivers/md/dm.h

index f221812b7dbcf0d3bae7c5171fe9e184c781d7d7..f309477d7efe6c4da1271aa2068e234933825394 100644 (file)
@@ -860,14 +860,17 @@ EXPORT_SYMBOL(dm_consume_args);
 static int dm_table_set_type(struct dm_table *t)
 {
        unsigned i;
-       unsigned bio_based = 0, request_based = 0;
+       unsigned bio_based = 0, request_based = 0, hybrid = 0;
        struct dm_target *tgt;
        struct dm_dev_internal *dd;
        struct list_head *devices;
+       unsigned live_md_type;
 
        for (i = 0; i < t->num_targets; i++) {
                tgt = t->targets + i;
-               if (dm_target_request_based(tgt))
+               if (dm_target_hybrid(tgt))
+                       hybrid = 1;
+               else if (dm_target_request_based(tgt))
                        request_based = 1;
                else
                        bio_based = 1;
@@ -879,6 +882,21 @@ static int dm_table_set_type(struct dm_table *t)
                }
        }
 
+       if (hybrid && !bio_based && !request_based) {
+               /*
+                * The targets can work either way.
+                * Determine the type from the live device.
+                * Default to bio-based if device is new.
+                */
+               dm_lock_md_type(t->md);
+               live_md_type = dm_get_md_type(t->md);
+               dm_unlock_md_type(t->md);
+               if (live_md_type == DM_TYPE_REQUEST_BASED)
+                       request_based = 1;
+               else
+                       bio_based = 1;
+       }
+
        if (bio_based) {
                /* We must use this table as bio-based */
                t->type = DM_TYPE_BIO_BASED;
index 37ba5db71cd9b2f3c16c0e64e67b109401c5903d..242e3cec397a5c87a1963b31aa0d65a9bec7527a 100644 (file)
@@ -131,12 +131,19 @@ static int io_err_map(struct dm_target *tt, struct bio *bio)
        return -EIO;
 }
 
+static int io_err_map_rq(struct dm_target *ti, struct request *clone,
+                        union map_info *map_context)
+{
+       return -EIO;
+}
+
 static struct target_type error_target = {
        .name = "error",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .ctr  = io_err_ctr,
        .dtr  = io_err_dtr,
        .map  = io_err_map,
+       .map_rq = io_err_map_rq,
 };
 
 int __init dm_target_init(void)
index 45b97da1bd061f02a32e0e7523fdf5125ffb1089..8b4c075d9a2f24c636eeaedd54d4e5daf7f7d4c3 100644 (file)
@@ -88,11 +88,22 @@ int dm_setup_md_queue(struct mapped_device *md);
  */
 #define dm_target_is_valid(t) ((t)->table)
 
+/*
+ * To check whether the target type is bio-based or not (request-based).
+ */
+#define dm_target_bio_based(t) ((t)->type->map != NULL)
+
 /*
  * To check whether the target type is request-based or not (bio-based).
  */
 #define dm_target_request_based(t) ((t)->type->map_rq != NULL)
 
+/*
+ * To check whether the target type is a hybrid (capable of being
+ * either request-based or bio-based).
+ */
+#define dm_target_hybrid(t) (dm_target_bio_based(t) && dm_target_request_based(t))
+
 /*-----------------------------------------------------------------
  * A registry of target types.
  *---------------------------------------------------------------*/