There's a logic quirk in the handling of suspend in the bitmap mode:

This is the sequence of calls if we are reloading a dm-integrity table:
* dm_integrity_ctr reads a superblock with the flag SB_FLAG_DIRTY_BITMAP
  set.
* dm_integrity_postsuspend initializes a journal and clears the flag
  SB_FLAG_DIRTY_BITMAP.
* dm_integrity_resume sees the superblock with SB_FLAG_DIRTY_BITMAP set -
  thus it interprets the journal as if it were a bitmap.

This quirk causes recalculation problem if the user increases the size of
the device in the bitmap mode.

Fix this by reading a fresh copy on the superblock in
dm_integrity_resume. This commit also fixes another logic quirk - the
branch that sets bitmap bits if the device was extended should only be
executed if the flag SB_FLAG_DIRTY_BITMAP is set.

Signed-off-by: Mikulas Patocka <[email protected]>
Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode")
Cc: [email protected]

---
 drivers/md/dm-integrity.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)

Index: linux-2.6/drivers/md/dm-integrity.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-integrity.c    2026-01-16 08:54:47.000000000 
+0100
+++ linux-2.6/drivers/md/dm-integrity.c 2026-01-16 17:17:06.000000000 +0100
@@ -3788,14 +3788,27 @@ static void dm_integrity_resume(struct d
        struct dm_integrity_c *ic = ti->private;
        __u64 old_provided_data_sectors = 
le64_to_cpu(ic->sb->provided_data_sectors);
        int r;
+       __le32 flags;
 
        DEBUG_print("resume\n");
 
        ic->wrote_to_journal = false;
 
+       flags = ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING);
+       r = sync_rw_sb(ic, REQ_OP_READ);
+       if (r)
+               dm_integrity_io_error(ic, "reading superblock", r);
+       if ((ic->sb->flags & flags) != flags) {
+               ic->sb->flags |= flags;
+               r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
+               if (unlikely(r))
+                       dm_integrity_io_error(ic, "writing superblock", r);
+       }
+
        if (ic->provided_data_sectors != old_provided_data_sectors) {
                if (ic->provided_data_sectors > old_provided_data_sectors &&
                    ic->mode == 'B' &&
+                   ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP) &&
                    ic->sb->log2_blocks_per_bitmap_bit == 
ic->log2_blocks_per_bitmap_bit) {
                        rw_journal_sectors(ic, REQ_OP_READ, 0,
                                           ic->n_bitmap_blocks * 
(BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);


Reply via email to