diff mbox series

[3/3] dm array: fix cursor index when skipping across block boundaries

Message ID 20241203175029.1259542-1-mtsai@redhat.com (mailing list archive)
State Superseded, archived
Delegated to: Mike Snitzer
Headers show
Series Fix dm_array_cursor skipping and error handling | expand

Commit Message

Ming Hung Tsai Dec. 3, 2024, 5:50 p.m. UTC
dm_array_cursor_skip() seeks to the target position by loading array
blocks iteratively until the specified number of entries to skip is
reached. When seeking across block boundaries, it uses
dm_array_cursor_next() to step into the next block.
dm_array_cursor_skip() must first move the cursor index to the end
of the current block; otherwise, the cursor position could incorrectly
remain in the same block, causing the actual number of skipped entries
to be much smaller than expected.

This bug affects cache resizing in v2 metadata and could lead to data
loss if the fast device is shrunk during the first-time resume. For
example:

1. create a cache metadata consists of 32768 blocks, with a dirty block
   assigned to the second bitmap block. cache_restore v1.0 is required.

cat <<EOF >> cmeta.xml
<superblock uuid="" block_size="64" nr_cache_blocks="32768" \
policy="smq" hint_width="4">
  <mappings>
    <mapping cache_block="32767" origin_block="0" dirty="true"/>
  </mappings>
</superblock>
EOF
dmsetup create cmeta --table "0 8192 linear /dev/sdc 0"
cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2

2. bring up the cache while attempt to discard all the blocks belonging
   to the second bitmap block (block# 32576 to 32767). The last command
   is expected to fail, but it actually succeeds.

dmsetup create cdata --table "0 2084864 linear /dev/sdc 8192"
dmsetup create corig --table "0 65536 linear /dev/sdc 2105344"
dmsetup create cache --table "0 65536 cache /dev/mapper/cmeta \
/dev/mapper/cdata /dev/mapper/corig 64 2 metadata2 writeback smq \
2 migration_threshold 0"

Signed-off-by: Ming-Hung Tsai <mtsai@redhat.com>
Fixes: 9b696229aa7d ("dm persistent data: add cursor skip functions to the cursor APIs")
---
 drivers/md/persistent-data/dm-array.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Joe Thornber Dec. 10, 2024, 4:35 p.m. UTC | #1
Reviewed-by: thornber@redhat.com

On Tue, Dec 3, 2024 at 5:50 PM Ming-Hung Tsai <mtsai@redhat.com> wrote:
>
> dm_array_cursor_skip() seeks to the target position by loading array
> blocks iteratively until the specified number of entries to skip is
> reached. When seeking across block boundaries, it uses
> dm_array_cursor_next() to step into the next block.
> dm_array_cursor_skip() must first move the cursor index to the end
> of the current block; otherwise, the cursor position could incorrectly
> remain in the same block, causing the actual number of skipped entries
> to be much smaller than expected.
>
> This bug affects cache resizing in v2 metadata and could lead to data
> loss if the fast device is shrunk during the first-time resume. For
> example:
>
> 1. create a cache metadata consists of 32768 blocks, with a dirty block
>    assigned to the second bitmap block. cache_restore v1.0 is required.
>
> cat <<EOF >> cmeta.xml
> <superblock uuid="" block_size="64" nr_cache_blocks="32768" \
> policy="smq" hint_width="4">
>   <mappings>
>     <mapping cache_block="32767" origin_block="0" dirty="true"/>
>   </mappings>
> </superblock>
> EOF
> dmsetup create cmeta --table "0 8192 linear /dev/sdc 0"
> cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2
>
> 2. bring up the cache while attempt to discard all the blocks belonging
>    to the second bitmap block (block# 32576 to 32767). The last command
>    is expected to fail, but it actually succeeds.
>
> dmsetup create cdata --table "0 2084864 linear /dev/sdc 8192"
> dmsetup create corig --table "0 65536 linear /dev/sdc 2105344"
> dmsetup create cache --table "0 65536 cache /dev/mapper/cmeta \
> /dev/mapper/cdata /dev/mapper/corig 64 2 metadata2 writeback smq \
> 2 migration_threshold 0"
>
> Signed-off-by: Ming-Hung Tsai <mtsai@redhat.com>
> Fixes: 9b696229aa7d ("dm persistent data: add cursor skip functions to the cursor APIs")
> ---
>  drivers/md/persistent-data/dm-array.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
> index 1c3af717ee4f..b293da766fb1 100644
> --- a/drivers/md/persistent-data/dm-array.c
> +++ b/drivers/md/persistent-data/dm-array.c
> @@ -1004,6 +1004,7 @@ int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count)
>                 }
>
>                 count -= remaining;
> +               c->index += (remaining - 1);
>                 r = dm_array_cursor_next(c);
>
>         } while (!r);
> --
> 2.47.0
>
diff mbox series

Patch

diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
index 1c3af717ee4f..b293da766fb1 100644
--- a/drivers/md/persistent-data/dm-array.c
+++ b/drivers/md/persistent-data/dm-array.c
@@ -1004,6 +1004,7 @@  int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count)
 		}
 
 		count -= remaining;
+		c->index += (remaining - 1);
 		r = dm_array_cursor_next(c);
 
 	} while (!r);