aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r--drivers/md/dm-table.c114
1 files changed, 80 insertions, 34 deletions
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,