dm: mark targets that pass integrity data
authorMikulas Patocka <mpatocka@redhat.com>
Tue, 18 Apr 2017 20:51:48 +0000 (16:51 -0400)
committerMike Snitzer <snitzer@redhat.com>
Mon, 24 Apr 2017 16:04:32 +0000 (12:04 -0400)
A dm-crypt on dm-integrity device incorrectly advertises an integrity
profile on the DM crypt device.  It can be seen in the files
"/sys/block/dm-*/integrity/*" that both dm-integrity and dm-crypt target
advertise the integrity profile.  That is incorrect, only the
dm-integrity target should advertise the integrity profile.

A general problem in DM is that if we have a DM device that depends on
another device with an integrity profile, the upper device will always
advertise the integrity profile, even when the target driver doesn't
support handling integrity data.

Most targets don't support integrity data, so we provide a whitelist of
targets that support it (linear, delay and striped).  The targets that
support passing integrity data to the lower device are marked with the
flag DM_TARGET_PASSES_INTEGRITY.  The DM core will now advertise
integrity data on a DM device only if all the targets support the
integrity data.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-delay.c
drivers/md/dm-linear.c
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm.c
include/linux/device-mapper.h

index cc70871a6d298a92f451d341f1ee6a7c5d84533b..ae3158795d26bd0695d254d6d1a0cf25bc7278fd 100644 (file)
@@ -340,6 +340,7 @@ out:
 static struct target_type delay_target = {
        .name        = "delay",
        .version     = {1, 2, 1},
+       .features    = DM_TARGET_PASSES_INTEGRITY,
        .module      = THIS_MODULE,
        .ctr         = delay_ctr,
        .dtr         = delay_dtr,
index 4788b0b989a9bac661f07a8deb2c7a86a96c8677..ffa0c9c5968a38e08c140bf03c5e8998e0c44d86 100644 (file)
@@ -162,6 +162,7 @@ static long linear_direct_access(struct dm_target *ti, sector_t sector,
 static struct target_type linear_target = {
        .name   = "linear",
        .version = {1, 3, 0},
+       .features = DM_TARGET_PASSES_INTEGRITY,
        .module = THIS_MODULE,
        .ctr    = linear_ctr,
        .dtr    = linear_dtr,
index 28193a57bf471e30da0bedd944fe148283584b9c..d7e1b86e7570b16759224c7ca06345883fcdbf8e 100644 (file)
@@ -440,6 +440,7 @@ static void stripe_io_hints(struct dm_target *ti,
 static struct target_type stripe_target = {
        .name   = "striped",
        .version = {1, 6, 0},
+       .features = DM_TARGET_PASSES_INTEGRITY,
        .module = THIS_MODULE,
        .ctr    = stripe_ctr,
        .dtr    = stripe_dtr,
index 7fb29db478cdc7adac0144c6d555dfc2ccf83bbd..c68757f94e164a1406191201d8f0576e12f60a62 100644 (file)
@@ -1135,6 +1135,13 @@ static struct gendisk * dm_table_get_integrity_disk(struct dm_table *t)
        struct list_head *devices = dm_table_get_devices(t);
        struct dm_dev_internal *dd = NULL;
        struct gendisk *prev_disk = NULL, *template_disk = NULL;
+       unsigned i;
+
+       for (i = 0; i < dm_table_get_num_targets(t); i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
+               if (!dm_target_passes_integrity(ti->type))
+                       goto no_integrity;
+       }
 
        list_for_each_entry(dd, devices, list) {
                template_disk = dd->dm_dev->bdev->bd_disk;
index f4ffd1eb8f44c3d5c44c50277fb703545157dbcf..e602ae0d5d755ddc4c3cc2d67f9d5df240630def 100644 (file)
@@ -1089,8 +1089,18 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio,
 
        __bio_clone_fast(clone, bio);
 
-       if (bio_integrity(bio)) {
-               int r = bio_integrity_clone(clone, bio, GFP_NOIO);
+       if (unlikely(bio_integrity(bio) != NULL)) {
+               int r;
+
+               if (unlikely(!dm_target_has_integrity(tio->ti->type) &&
+                            !dm_target_passes_integrity(tio->ti->type))) {
+                       DMWARN("%s: the target %s doesn't support integrity data.",
+                               dm_device_name(tio->io->md),
+                               tio->ti->type->name);
+                       return -EIO;
+               }
+
+               r = bio_integrity_clone(clone, bio, GFP_NOIO);
                if (r < 0)
                        return r;
        }
@@ -1098,7 +1108,7 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio,
        bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
        clone->bi_iter.bi_size = to_bytes(len);
 
-       if (bio_integrity(bio))
+       if (unlikely(bio_integrity(bio) != NULL))
                bio_integrity_trim(clone, 0, len);
 
        return 0;
index 874462153f143ecc09c85b0f48b69013fcc1e777..98f981026e4e0c9d13d2de64022540d02b1bc7d4 100644 (file)
@@ -227,6 +227,12 @@ typedef unsigned (*dm_num_write_bios_fn) (struct dm_target *ti, struct bio *bio)
 #define DM_TARGET_INTEGRITY            0x00000010
 #define dm_target_has_integrity(type)  ((type)->features & DM_TARGET_INTEGRITY)
 
+/*
+ * A target passes integrity data to the lower device.
+ */
+#define DM_TARGET_PASSES_INTEGRITY     0x00000020
+#define dm_target_passes_integrity(type) ((type)->features & DM_TARGET_PASSES_INTEGRITY)
+
 struct dm_target {
        struct dm_table *table;
        struct target_type *type;