dm: support barriers on simple devices
authorAndi Kleen <ak@suse.de>
Tue, 6 Jan 2009 03:05:09 +0000 (03:05 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Tue, 6 Jan 2009 03:05:09 +0000 (03:05 +0000)
Implement barrier support for single device DM devices

This patch implements barrier support in DM for the common case of dm linear
just remapping a single underlying device. In this case we can safely
pass the barrier through because there can be no reordering between
devices.

 NB. Any DM device might cease to support barriers if it gets
     reconfigured so code must continue to allow for a possible
     -EOPNOTSUPP on every barrier bio submitted.  - agk

Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-linear.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
include/linux/device-mapper.h

index 79fb53e51c709e2875382c517bc61413e50fd978..bfa107f59d96fca62f219bff16e3affcf08b5046 100644 (file)
@@ -142,6 +142,7 @@ static struct target_type linear_target = {
        .status = linear_status,
        .ioctl  = linear_ioctl,
        .merge  = linear_merge,
+       .features = DM_TARGET_SUPPORTS_BARRIERS,
 };
 
 int __init dm_linear_init(void)
index 04e5fd742c2c29e42fbba920e1303b889229ccf7..ebaaf72cd8220c62e7f5287b8e32dee756186ee0 100644 (file)
@@ -38,6 +38,8 @@ struct dm_table {
        sector_t *highs;
        struct dm_target *targets;
 
+       unsigned barriers_supported:1;
+
        /*
         * Indicates the rw permissions for the new logical
         * device.  This should be a combination of FMODE_READ
@@ -227,6 +229,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
 
        INIT_LIST_HEAD(&t->devices);
        atomic_set(&t->holders, 1);
+       t->barriers_supported = 1;
 
        if (!num_targets)
                num_targets = KEYS_PER_NODE;
@@ -728,6 +731,10 @@ int dm_table_add_target(struct dm_table *t, const char *type,
        /* FIXME: the plan is to combine high here and then have
         * the merge fn apply the target level restrictions. */
        combine_restrictions_low(&t->limits, &tgt->limits);
+
+       if (!(tgt->type->features & DM_TARGET_SUPPORTS_BARRIERS))
+               t->barriers_supported = 0;
+
        return 0;
 
  bad:
@@ -772,6 +779,12 @@ int dm_table_complete(struct dm_table *t)
 
        check_for_valid_limits(&t->limits);
 
+       /*
+        * We only support barriers if there is exactly one underlying device.
+        */
+       if (!list_is_singular(&t->devices))
+               t->barriers_supported = 0;
+
        /* how many indexes will the btree have ? */
        leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
        t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
@@ -986,6 +999,12 @@ struct mapped_device *dm_table_get_md(struct dm_table *t)
        return t->md;
 }
 
+int dm_table_barrier_ok(struct dm_table *t)
+{
+       return t->barriers_supported;
+}
+EXPORT_SYMBOL(dm_table_barrier_ok);
+
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
index 4882ce7e88a33e974a071def5fb8496ed7cc3969..dd953b189f459288b576fedcd6b42a29931f76c9 100644 (file)
@@ -835,7 +835,11 @@ static int __split_bio(struct mapped_device *md, struct bio *bio)
        ci.map = dm_get_table(md);
        if (unlikely(!ci.map))
                return -EIO;
-
+       if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) {
+               dm_table_put(ci.map);
+               bio_endio(bio, -EOPNOTSUPP);
+               return 0;
+       }
        ci.md = md;
        ci.bio = bio;
        ci.io = alloc_io(md);
@@ -919,15 +923,6 @@ static int dm_request(struct request_queue *q, struct bio *bio)
        struct mapped_device *md = q->queuedata;
        int cpu;
 
-       /*
-        * There is no use in forwarding any barrier request since we can't
-        * guarantee it is (or can be) handled by the targets correctly.
-        */
-       if (unlikely(bio_barrier(bio))) {
-               bio_endio(bio, -EOPNOTSUPP);
-               return 0;
-       }
-
        down_read(&md->io_lock);
 
        cpu = part_stat_lock();
index 0ade60cdef42dd062bf8f11210ee27b65dd651d2..5b5d08ba9e92f17e2a5c28f3a97d14f7dd4ec74c 100644 (file)
@@ -51,6 +51,7 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits);
  * To check the return value from dm_table_find_target().
  */
 #define dm_target_is_valid(t) ((t)->table)
+int dm_table_barrier_ok(struct dm_table *t);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
index c1ba76c7c0e538f8f8804beb77231c78f45d6c58..8209e08969f9e4265e4fbbcd0c00b5a68467cad5 100644 (file)
@@ -112,7 +112,14 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d);
 /*
  * Information about a target type
  */
+
+/*
+ * Target features
+ */
+#define DM_TARGET_SUPPORTS_BARRIERS 0x00000001
+
 struct target_type {
+       uint64_t features;
        const char *name;
        struct module *module;
        unsigned version[3];