diff options
| author | Mikulas Patocka <mpatocka@redhat.com> | 2026-01-19 15:06:02 +0100 |
|---|---|---|
| committer | Sasha Levin <sashal@kernel.org> | 2026-03-04 07:20:47 -0500 |
| commit | 824b9c27d7b600520b95f0cab95a47d1b08a9483 (patch) | |
| tree | 0742327951ce25ee38043aaa244431072d6c6748 | |
| parent | 7e70c349d46c7ac17c65ea9956d9f487c7cf2515 (diff) | |
dm-integrity: fix recalculation in bitmap mode
[ Upstream commit 118ba36e446c01e3cd34b3eedabf1d9436525e1d ]
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 <mpatocka@redhat.com>
Tested-by: Ondrej Kozina <okozina@redhat.com>
Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode")
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | drivers/md/dm-integrity.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 0749e210f485..c70dc64200d8 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -3204,14 +3204,27 @@ static void dm_integrity_resume(struct dm_target *ti) struct dm_integrity_c *ic = (struct dm_integrity_c *)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); |
