dm integrity: fix recalculation when moving from journal mode to bitmap mode
authorMikulas Patocka <mpatocka@redhat.com>
Fri, 7 Feb 2020 16:42:30 +0000 (11:42 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Mar 2020 12:00:23 +0000 (13:00 +0100)
commit d5bdf66108419cdb39da361b58ded661c29ff66e upstream.

If we resume a device in bitmap mode and the on-disk format is in journal
mode, we must recalculate anything above ic->sb->recalc_sector. Otherwise,
there would be non-recalculated blocks which would cause I/O errors.

Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode")
Cc: stable@vger.kernel.org # v5.2+
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/md/dm-integrity.c

index dab4446..47a74d2 100644 (file)
@@ -2883,17 +2883,24 @@ static void dm_integrity_resume(struct dm_target *ti)
        } else {
                replay_journal(ic);
                if (ic->mode == 'B') {
-                       int mode;
                        ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                        ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
                        r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
                        if (unlikely(r))
                                dm_integrity_io_error(ic, "writing superblock", r);
 
-                       mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR;
-                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode);
+                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+                           le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) {
+                               block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                       }
                        rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                }