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
 
        INIT_LIST_HEAD(&t->devices);
        atomic_set(&t->holders, 1);
+       t->barriers_supported = 1;
 
        if (!num_targets)
                num_targets = KEYS_PER_NODE;
        /* 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:
 
        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);
        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);
 
        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);
        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();
 
  * 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.