Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm: mark targets that pass integrity data

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>

authored by

Mikulas Patocka and committed by
Mike Snitzer
e2460f2a 3c120169

+29 -3
+1
drivers/md/dm-delay.c
··· 340 340 static struct target_type delay_target = { 341 341 .name = "delay", 342 342 .version = {1, 2, 1}, 343 + .features = DM_TARGET_PASSES_INTEGRITY, 343 344 .module = THIS_MODULE, 344 345 .ctr = delay_ctr, 345 346 .dtr = delay_dtr,
+1
drivers/md/dm-linear.c
··· 162 162 static struct target_type linear_target = { 163 163 .name = "linear", 164 164 .version = {1, 3, 0}, 165 + .features = DM_TARGET_PASSES_INTEGRITY, 165 166 .module = THIS_MODULE, 166 167 .ctr = linear_ctr, 167 168 .dtr = linear_dtr,
+1
drivers/md/dm-stripe.c
··· 440 440 static struct target_type stripe_target = { 441 441 .name = "striped", 442 442 .version = {1, 6, 0}, 443 + .features = DM_TARGET_PASSES_INTEGRITY, 443 444 .module = THIS_MODULE, 444 445 .ctr = stripe_ctr, 445 446 .dtr = stripe_dtr,
+7
drivers/md/dm-table.c
··· 1135 1135 struct list_head *devices = dm_table_get_devices(t); 1136 1136 struct dm_dev_internal *dd = NULL; 1137 1137 struct gendisk *prev_disk = NULL, *template_disk = NULL; 1138 + unsigned i; 1139 + 1140 + for (i = 0; i < dm_table_get_num_targets(t); i++) { 1141 + struct dm_target *ti = dm_table_get_target(t, i); 1142 + if (!dm_target_passes_integrity(ti->type)) 1143 + goto no_integrity; 1144 + } 1138 1145 1139 1146 list_for_each_entry(dd, devices, list) { 1140 1147 template_disk = dd->dm_dev->bdev->bd_disk;
+13 -3
drivers/md/dm.c
··· 1089 1089 1090 1090 __bio_clone_fast(clone, bio); 1091 1091 1092 - if (bio_integrity(bio)) { 1093 - int r = bio_integrity_clone(clone, bio, GFP_NOIO); 1092 + if (unlikely(bio_integrity(bio) != NULL)) { 1093 + int r; 1094 + 1095 + if (unlikely(!dm_target_has_integrity(tio->ti->type) && 1096 + !dm_target_passes_integrity(tio->ti->type))) { 1097 + DMWARN("%s: the target %s doesn't support integrity data.", 1098 + dm_device_name(tio->io->md), 1099 + tio->ti->type->name); 1100 + return -EIO; 1101 + } 1102 + 1103 + r = bio_integrity_clone(clone, bio, GFP_NOIO); 1094 1104 if (r < 0) 1095 1105 return r; 1096 1106 } ··· 1108 1098 bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector)); 1109 1099 clone->bi_iter.bi_size = to_bytes(len); 1110 1100 1111 - if (bio_integrity(bio)) 1101 + if (unlikely(bio_integrity(bio) != NULL)) 1112 1102 bio_integrity_trim(clone, 0, len); 1113 1103 1114 1104 return 0;
+6
include/linux/device-mapper.h
··· 227 227 #define DM_TARGET_INTEGRITY 0x00000010 228 228 #define dm_target_has_integrity(type) ((type)->features & DM_TARGET_INTEGRITY) 229 229 230 + /* 231 + * A target passes integrity data to the lower device. 232 + */ 233 + #define DM_TARGET_PASSES_INTEGRITY 0x00000020 234 + #define dm_target_passes_integrity(type) ((type)->features & DM_TARGET_PASSES_INTEGRITY) 235 + 230 236 struct dm_target { 231 237 struct dm_table *table; 232 238 struct target_type *type;