aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2011-04-01 15:02:31 -0400
committerJens Axboe <jaxboe@fusionio.com>2011-04-05 17:52:43 -0400
commita63a5cf84dac7a23a57c800eea5734701e7d3c04 (patch)
tree965552b96d7eacc21206a4f28672efd24a04d913
parent7dcda1c96d7c643101d4a05579ef4512a4baa7ef (diff)
dm: improve block integrity support
The current block integrity (DIF/DIX) support in DM is verifying that all devices' integrity profiles match during DM device resume (which is past the point of no return). To some degree that is unavoidable (stacked DM devices force this late checking). But for most DM devices (which aren't stacking on other DM devices) the ideal time to verify all integrity profiles match is during table load. Introduce the notion of an "initialized" integrity profile: a profile that was blk_integrity_register()'d with a non-NULL 'blk_integrity' template. Add blk_integrity_is_initialized() to allow checking if a profile was initialized. Update DM integrity support to: - check all devices with _initialized_ integrity profiles match during table load; uninitialized profiles (e.g. for underlying DM device(s) of a stacked DM device) are ignored. - disallow a table load that would result in an integrity profile that conflicts with a DM device's existing (in-use) integrity profile - avoid clearing an existing integrity profile - validate all integrity profiles match during resume; but if they don't all we can do is report the mismatch (during resume we're past the point of no return) Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
-rw-r--r--block/blk-integrity.c12
-rw-r--r--drivers/md/dm-table.c114
-rw-r--r--include/linux/blkdev.h2
3 files changed, 93 insertions, 35 deletions
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 54bcba6c02a7..129b9e209a3b 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -30,6 +30,8 @@
30 30
31static struct kmem_cache *integrity_cachep; 31static struct kmem_cache *integrity_cachep;
32 32
33static const char *bi_unsupported_name = "unsupported";
34
33/** 35/**
34 * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements 36 * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
35 * @q: request queue 37 * @q: request queue
@@ -358,6 +360,14 @@ static struct kobj_type integrity_ktype = {
358 .release = blk_integrity_release, 360 .release = blk_integrity_release,
359}; 361};
360 362
363bool blk_integrity_is_initialized(struct gendisk *disk)
364{
365 struct blk_integrity *bi = blk_get_integrity(disk);
366
367 return (bi && bi->name && strcmp(bi->name, bi_unsupported_name) != 0);
368}
369EXPORT_SYMBOL(blk_integrity_is_initialized);
370
361/** 371/**
362 * blk_integrity_register - Register a gendisk as being integrity-capable 372 * blk_integrity_register - Register a gendisk as being integrity-capable
363 * @disk: struct gendisk pointer to make integrity-aware 373 * @disk: struct gendisk pointer to make integrity-aware
@@ -407,7 +417,7 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
407 bi->get_tag_fn = template->get_tag_fn; 417 bi->get_tag_fn = template->get_tag_fn;
408 bi->tag_size = template->tag_size; 418 bi->tag_size = template->tag_size;
409 } else 419 } else
410 bi->name = "unsupported"; 420 bi->name = bi_unsupported_name;
411 421
412 return 0; 422 return 0;
413} 423}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 416d4e258df6..cb8380c9767f 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -927,20 +927,80 @@ static int dm_table_build_index(struct dm_table *t)
927} 927}
928 928
929/* 929/*
930 * Get a disk whose integrity profile reflects the table's profile.
931 * If %match_all is true, all devices' profiles must match.
932 * If %match_all is false, all devices must at least have an
933 * allocated integrity profile; but uninitialized is ok.
934 * Returns NULL if integrity support was inconsistent or unavailable.
935 */
936static struct gendisk * dm_table_get_integrity_disk(struct dm_table *t,
937 bool match_all)
938{
939 struct list_head *devices = dm_table_get_devices(t);
940 struct dm_dev_internal *dd = NULL;
941 struct gendisk *prev_disk = NULL, *template_disk = NULL;
942
943 list_for_each_entry(dd, devices, list) {
944 template_disk = dd->dm_dev.bdev->bd_disk;
945 if (!blk_get_integrity(template_disk))
946 goto no_integrity;
947 if (!match_all && !blk_integrity_is_initialized(template_disk))
948 continue; /* skip uninitialized profiles */
949 else if (prev_disk &&
950 blk_integrity_compare(prev_disk, template_disk) < 0)
951 goto no_integrity;
952 prev_disk = template_disk;
953 }
954
955 return template_disk;
956
957no_integrity:
958 if (prev_disk)
959 DMWARN("%s: integrity not set: %s and %s profile mismatch",
960 dm_device_name(t->md),
961 prev_disk->disk_name,
962 template_disk->disk_name);
963 return NULL;
964}
965
966/*
930 * Register the mapped device for blk_integrity support if 967 * Register the mapped device for blk_integrity support if
931 * the underlying devices support it. 968 * the underlying devices have an integrity profile. But all devices
969 * may not have matching profiles (checking all devices isn't reliable
970 * during table load because this table may use other DM device(s) which
971 * must be resumed before they will have an initialized integity profile).
972 * Stacked DM devices force a 2 stage integrity profile validation:
973 * 1 - during load, validate all initialized integrity profiles match
974 * 2 - during resume, validate all integrity profiles match
932 */ 975 */
933static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device *md) 976static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device *md)
934{ 977{
935 struct list_head *devices = dm_table_get_devices(t); 978 struct gendisk *template_disk = NULL;
936 struct dm_dev_internal *dd;
937 979
938 list_for_each_entry(dd, devices, list) 980 template_disk = dm_table_get_integrity_disk(t, false);
939 if (bdev_get_integrity(dd->dm_dev.bdev)) { 981 if (!template_disk)
940 t->integrity_supported = 1; 982 return 0;
941 return blk_integrity_register(dm_disk(md), NULL);
942 }
943 983
984 if (!blk_integrity_is_initialized(dm_disk(md))) {
985 t->integrity_supported = 1;
986 return blk_integrity_register(dm_disk(md), NULL);
987 }
988
989 /*
990 * If DM device already has an initalized integrity
991 * profile the new profile should not conflict.
992 */
993 if (blk_integrity_is_initialized(template_disk) &&
994 blk_integrity_compare(dm_disk(md), template_disk) < 0) {
995 DMWARN("%s: conflict with existing integrity profile: "
996 "%s profile mismatch",
997 dm_device_name(t->md),
998 template_disk->disk_name);
999 return 1;
1000 }
1001
1002 /* Preserve existing initialized integrity profile */
1003 t->integrity_supported = 1;
944 return 0; 1004 return 0;
945} 1005}
946 1006
@@ -1094,41 +1154,27 @@ combine_limits:
1094 1154
1095/* 1155/*
1096 * Set the integrity profile for this device if all devices used have 1156 * Set the integrity profile for this device if all devices used have
1097 * matching profiles. 1157 * matching profiles. We're quite deep in the resume path but still
1158 * don't know if all devices (particularly DM devices this device
1159 * may be stacked on) have matching profiles. Even if the profiles
1160 * don't match we have no way to fail (to resume) at this point.
1098 */ 1161 */
1099static void dm_table_set_integrity(struct dm_table *t) 1162static void dm_table_set_integrity(struct dm_table *t)
1100{ 1163{
1101 struct list_head *devices = dm_table_get_devices(t); 1164 struct gendisk *template_disk = NULL;
1102 struct dm_dev_internal *prev = NULL, *dd = NULL;
1103 1165
1104 if (!blk_get_integrity(dm_disk(t->md))) 1166 if (!blk_get_integrity(dm_disk(t->md)))
1105 return; 1167 return;
1106 1168
1107 list_for_each_entry(dd, devices, list) { 1169 template_disk = dm_table_get_integrity_disk(t, true);
1108 if (prev && 1170 if (!template_disk &&
1109 blk_integrity_compare(prev->dm_dev.bdev->bd_disk, 1171 blk_integrity_is_initialized(dm_disk(t->md))) {
1110 dd->dm_dev.bdev->bd_disk) < 0) { 1172 DMWARN("%s: device no longer has a valid integrity profile",
1111 DMWARN("%s: integrity not set: %s and %s mismatch", 1173 dm_device_name(t->md));
1112 dm_device_name(t->md), 1174 return;
1113 prev->dm_dev.bdev->bd_disk->disk_name,
1114 dd->dm_dev.bdev->bd_disk->disk_name);
1115 goto no_integrity;
1116 }
1117 prev = dd;
1118 } 1175 }
1119
1120 if (!prev || !bdev_get_integrity(prev->dm_dev.bdev))
1121 goto no_integrity;
1122
1123 blk_integrity_register(dm_disk(t->md), 1176 blk_integrity_register(dm_disk(t->md),
1124 bdev_get_integrity(prev->dm_dev.bdev)); 1177 blk_get_integrity(template_disk));
1125
1126 return;
1127
1128no_integrity:
1129 blk_integrity_register(dm_disk(t->md), NULL);
1130
1131 return;
1132} 1178}
1133 1179
1134void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, 1180void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 16a902f099ac..32176cc8e715 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1206,6 +1206,7 @@ struct blk_integrity {
1206 struct kobject kobj; 1206 struct kobject kobj;
1207}; 1207};
1208 1208
1209extern bool blk_integrity_is_initialized(struct gendisk *);
1209extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); 1210extern int blk_integrity_register(struct gendisk *, struct blk_integrity *);
1210extern void blk_integrity_unregister(struct gendisk *); 1211extern void blk_integrity_unregister(struct gendisk *);
1211extern int blk_integrity_compare(struct gendisk *, struct gendisk *); 1212extern int blk_integrity_compare(struct gendisk *, struct gendisk *);
@@ -1262,6 +1263,7 @@ queue_max_integrity_segments(struct request_queue *q)
1262#define queue_max_integrity_segments(a) (0) 1263#define queue_max_integrity_segments(a) (0)
1263#define blk_integrity_merge_rq(a, b, c) (0) 1264#define blk_integrity_merge_rq(a, b, c) (0)
1264#define blk_integrity_merge_bio(a, b, c) (0) 1265#define blk_integrity_merge_bio(a, b, c) (0)
1266#define blk_integrity_is_initialized(a) (0)
1265 1267
1266#endif /* CONFIG_BLK_DEV_INTEGRITY */ 1268#endif /* CONFIG_BLK_DEV_INTEGRITY */
1267 1269