@@ -926,21 +926,81 @@ static int dm_table_build_index(struct dm_table *t)
926926 return r ;
927927}
928928
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+
929966/*
930967 * 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
932975 */
933976static int dm_table_prealloc_integrity (struct dm_table * t , struct mapped_device * md )
934977{
935- struct list_head * devices = dm_table_get_devices (t );
936- struct dm_dev_internal * dd ;
978+ struct gendisk * template_disk = NULL ;
937979
938- list_for_each_entry (dd , devices , list )
939- if (bdev_get_integrity (dd -> dm_dev .bdev )) {
940- t -> integrity_supported = 1 ;
941- return blk_integrity_register (dm_disk (md ), NULL );
942- }
980+ template_disk = dm_table_get_integrity_disk (t , false);
981+ if (!template_disk )
982+ return 0 ;
943983
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 ;
9441004 return 0 ;
9451005}
9461006
@@ -1094,41 +1154,27 @@ int dm_calculate_queue_limits(struct dm_table *table,
10941154
10951155/*
10961156 * 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.
10981161 */
10991162static void dm_table_set_integrity (struct dm_table * t )
11001163{
1101- struct list_head * devices = dm_table_get_devices (t );
1102- struct dm_dev_internal * prev = NULL , * dd = NULL ;
1164+ struct gendisk * template_disk = NULL ;
11031165
11041166 if (!blk_get_integrity (dm_disk (t -> md )))
11051167 return ;
11061168
1107- list_for_each_entry (dd , devices , list ) {
1108- if (prev &&
1109- blk_integrity_compare (prev -> dm_dev .bdev -> bd_disk ,
1110- dd -> dm_dev .bdev -> bd_disk ) < 0 ) {
1111- DMWARN ("%s: integrity not set: %s and %s mismatch" ,
1112- dm_device_name (t -> md ),
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 ;
1169+ template_disk = dm_table_get_integrity_disk (t , true);
1170+ if (!template_disk &&
1171+ blk_integrity_is_initialized (dm_disk (t -> md ))) {
1172+ DMWARN ("%s: device no longer has a valid integrity profile" ,
1173+ dm_device_name (t -> md ));
1174+ return ;
11181175 }
1119-
1120- if (!prev || !bdev_get_integrity (prev -> dm_dev .bdev ))
1121- goto no_integrity ;
1122-
11231176 blk_integrity_register (dm_disk (t -> md ),
1124- bdev_get_integrity (prev -> dm_dev .bdev ));
1125-
1126- return ;
1127-
1128- no_integrity :
1129- blk_integrity_register (dm_disk (t -> md ), NULL );
1130-
1131- return ;
1177+ blk_get_integrity (template_disk ));
11321178}
11331179
11341180void dm_table_set_restrictions (struct dm_table * t , struct request_queue * q ,
0 commit comments