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 | ||
