diff options
-rw-r--r-- | block/blk-integrity.c | 12 | ||||
-rw-r--r-- | drivers/md/dm-table.c | 114 | ||||
-rw-r--r-- | include/linux/blkdev.h | 2 |
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 | ||
31 | static struct kmem_cache *integrity_cachep; | 31 | static struct kmem_cache *integrity_cachep; |
32 | 32 | ||
33 | static 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 | ||
363 | bool 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 | } | ||
369 | EXPORT_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 | */ | ||
936 | static 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 | |||
957 | no_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 | */ |
933 | static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device *md) | 976 | static 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 | */ |
1099 | static void dm_table_set_integrity(struct dm_table *t) | 1162 | static 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 | |||
1128 | no_integrity: | ||
1129 | blk_integrity_register(dm_disk(t->md), NULL); | ||
1130 | |||
1131 | return; | ||
1132 | } | 1178 | } |
1133 | 1179 | ||
1134 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | 1180 | void 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 | ||
1209 | extern bool blk_integrity_is_initialized(struct gendisk *); | ||
1209 | extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); | 1210 | extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); |
1210 | extern void blk_integrity_unregister(struct gendisk *); | 1211 | extern void blk_integrity_unregister(struct gendisk *); |
1211 | extern int blk_integrity_compare(struct gendisk *, struct gendisk *); | 1212 | extern 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 | ||