Read and dump entries from the bitmap directory of QCOW2 image.
It extends the output in the test case #291.
Header extension:
magic 0x23852875 (Bitmaps)
...
Bitmap name bitmap-1
bitmap_table_offset 0xf0000
bitmap_table_size 1
flags 0x2 (['auto'])
type 1
granularity_bits 16
name_size 8
extra_data_size 0
Suggested-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
---
tests/qemu-iotests/291.out | 45 ++++++++++++++++++++++++++++++++++++++
tests/qemu-iotests/qcow2_format.py | 44 +++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
index 08bfaaa..53a8eeb 100644
--- a/tests/qemu-iotests/291.out
+++ b/tests/qemu-iotests/291.out
@@ -33,6 +33,24 @@ reserved32 0
bitmap_directory_size 0x40
bitmap_directory_offset 0x510000
+Bitmap name b1
+bitmap_table_offset 0x4e0000
+bitmap_table_size 1
+flags 0x0 ([])
+type 1
+granularity_bits 19
+name_size 2
+extra_data_size 0
+
+Bitmap name b2
+bitmap_table_offset 0x500000
+bitmap_table_size 1
+flags 0x2 (['auto'])
+type 1
+granularity_bits 16
+name_size 2
+extra_data_size 0
+
=== Bitmap preservation not possible to non-qcow2 ===
@@ -98,6 +116,33 @@ reserved32 0
bitmap_directory_size 0x60
bitmap_directory_offset 0x520000
+Bitmap name b1
+bitmap_table_offset 0x470000
+bitmap_table_size 1
+flags 0x0 ([])
+type 1
+granularity_bits 19
+name_size 2
+extra_data_size 0
+
+Bitmap name b2
+bitmap_table_offset 0x490000
+bitmap_table_size 1
+flags 0x2 (['auto'])
+type 1
+granularity_bits 16
+name_size 2
+extra_data_size 0
+
+Bitmap name b0
+bitmap_table_offset 0x510000
+bitmap_table_size 1
+flags 0x0 ([])
+type 1
+granularity_bits 16
+name_size 2
+extra_data_size 0
+
=== Check bitmap contents ===
diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py
index d8c058d..7c0dc9a 100644
--- a/tests/qemu-iotests/qcow2_format.py
+++ b/tests/qemu-iotests/qcow2_format.py
@@ -132,6 +132,50 @@ class Qcow2BitmapExt(Qcow2Struct):
def __init__(self, fd):
super().__init__(fd=fd)
+ self.read_bitmap_directory(fd)
+
+ def read_bitmap_directory(self, fd):
+ fd.seek(self.bitmap_directory_offset)
+ self.bitmap_directory = \
+ [Qcow2BitmapDirEntry(fd) for _ in range(self.nb_bitmaps)]
+
+ def dump(self):
+ super().dump()
+ for entry in self.bitmap_directory:
+ print()
+ entry.dump()
+
+
+class Qcow2BitmapDirEntry(Qcow2Struct):
+
+ fields = (
+ ('u64', '{:#x}', 'bitmap_table_offset'),
+ ('u32', '{}', 'bitmap_table_size'),
+ ('u32', BitmapFlags, 'flags'),
+ ('u8', '{}', 'type'),
+ ('u8', '{}', 'granularity_bits'),
+ ('u16', '{}', 'name_size'),
+ ('u32', '{}', 'extra_data_size')
+ )
+
+ def __init__(self, fd):
+ super().__init__(fd=fd)
+ # Seek relative to the current position in the file
+ fd.seek(self.extra_data_size, 1)
+ bitmap_name = fd.read(self.name_size)
+ self.name = bitmap_name.decode('ascii')
+ # Move position to the end of the entry in the directory
+ entry_raw_size = self.bitmap_dir_entry_raw_size()
+ padding = ((entry_raw_size + 7) & ~7) - entry_raw_size
+ fd.seek(padding, 1)
+
+ def bitmap_dir_entry_raw_size(self):
+ return struct.calcsize(self.fmt) + self.name_size + \
+ self.extra_data_size
+
+ def dump(self):
+ print(f'{"Bitmap name":<25} {self.name}')
+ super(Qcow2BitmapDirEntry, self).dump()
QCOW2_EXT_MAGIC_BITMAPS = 0x23852875
--
1.8.3.1
03.07.2020 16:13, Andrey Shinkevich wrote:
> Read and dump entries from the bitmap directory of QCOW2 image.
> It extends the output in the test case #291.
>
> Header extension:
> magic 0x23852875 (Bitmaps)
> ...
>
> Bitmap name bitmap-1
> bitmap_table_offset 0xf0000
> bitmap_table_size 1
> flags 0x2 (['auto'])
> type 1
> granularity_bits 16
> name_size 8
> extra_data_size 0
>
> Suggested-by: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
> ---
> tests/qemu-iotests/291.out | 45 ++++++++++++++++++++++++++++++++++++++
> tests/qemu-iotests/qcow2_format.py | 44 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 89 insertions(+)
>
> diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
> index 08bfaaa..53a8eeb 100644
> --- a/tests/qemu-iotests/291.out
> +++ b/tests/qemu-iotests/291.out
> @@ -33,6 +33,24 @@ reserved32 0
> bitmap_directory_size 0x40
> bitmap_directory_offset 0x510000
>
> +Bitmap name b1
> +bitmap_table_offset 0x4e0000
> +bitmap_table_size 1
> +flags 0x0 ([])
> +type 1
> +granularity_bits 19
> +name_size 2
> +extra_data_size 0
> +
> +Bitmap name b2
> +bitmap_table_offset 0x500000
> +bitmap_table_size 1
> +flags 0x2 (['auto'])
> +type 1
> +granularity_bits 16
> +name_size 2
> +extra_data_size 0
> +
>
> === Bitmap preservation not possible to non-qcow2 ===
>
> @@ -98,6 +116,33 @@ reserved32 0
> bitmap_directory_size 0x60
> bitmap_directory_offset 0x520000
>
> +Bitmap name b1
> +bitmap_table_offset 0x470000
> +bitmap_table_size 1
> +flags 0x0 ([])
> +type 1
> +granularity_bits 19
> +name_size 2
> +extra_data_size 0
> +
> +Bitmap name b2
> +bitmap_table_offset 0x490000
> +bitmap_table_size 1
> +flags 0x2 (['auto'])
> +type 1
> +granularity_bits 16
> +name_size 2
> +extra_data_size 0
> +
> +Bitmap name b0
> +bitmap_table_offset 0x510000
> +bitmap_table_size 1
> +flags 0x0 ([])
> +type 1
> +granularity_bits 16
> +name_size 2
> +extra_data_size 0
> +
>
> === Check bitmap contents ===
>
> diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py
> index d8c058d..7c0dc9a 100644
> --- a/tests/qemu-iotests/qcow2_format.py
> +++ b/tests/qemu-iotests/qcow2_format.py
> @@ -132,6 +132,50 @@ class Qcow2BitmapExt(Qcow2Struct):
>
> def __init__(self, fd):
> super().__init__(fd=fd)
> + self.read_bitmap_directory(fd)
> +
> + def read_bitmap_directory(self, fd):
> + fd.seek(self.bitmap_directory_offset)
> + self.bitmap_directory = \
> + [Qcow2BitmapDirEntry(fd) for _ in range(self.nb_bitmaps)]
sounds good. I think, we should restore fd position after reading bitmap_directory, to point at the end of extension, to not break further extensions loading
> +
> + def dump(self):
> + super().dump()
> + for entry in self.bitmap_directory:
> + print()
> + entry.dump()
> +
> +
> +class Qcow2BitmapDirEntry(Qcow2Struct):
> +
> + fields = (
> + ('u64', '{:#x}', 'bitmap_table_offset'),
> + ('u32', '{}', 'bitmap_table_size'),
> + ('u32', BitmapFlags, 'flags'),
> + ('u8', '{}', 'type'),
> + ('u8', '{}', 'granularity_bits'),
> + ('u16', '{}', 'name_size'),
> + ('u32', '{}', 'extra_data_size')
> + )
> +
> + def __init__(self, fd):
> + super().__init__(fd=fd)
> + # Seek relative to the current position in the file
> + fd.seek(self.extra_data_size, 1)
> + bitmap_name = fd.read(self.name_size)
> + self.name = bitmap_name.decode('ascii')
> + # Move position to the end of the entry in the directory
> + entry_raw_size = self.bitmap_dir_entry_raw_size()
> + padding = ((entry_raw_size + 7) & ~7) - entry_raw_size
> + fd.seek(padding, 1)
> +
> + def bitmap_dir_entry_raw_size(self):
> + return struct.calcsize(self.fmt) + self.name_size + \
> + self.extra_data_size
> +
> + def dump(self):
> + print(f'{"Bitmap name":<25} {self.name}')
> + super(Qcow2BitmapDirEntry, self).dump()
>
>
> QCOW2_EXT_MAGIC_BITMAPS = 0x23852875
>
--
Best regards,
Vladimir
On 11.07.2020 22:11, Vladimir Sementsov-Ogievskiy wrote: > 03.07.2020 16:13, Andrey Shinkevich wrote: >> Read and dump entries from the bitmap directory of QCOW2 image. >> It extends the output in the test case #291. >> >> ... >> diff --git a/tests/qemu-iotests/qcow2_format.py >> b/tests/qemu-iotests/qcow2_format.py >> index d8c058d..7c0dc9a 100644 >> --- a/tests/qemu-iotests/qcow2_format.py >> +++ b/tests/qemu-iotests/qcow2_format.py >> @@ -132,6 +132,50 @@ class Qcow2BitmapExt(Qcow2Struct): >> def __init__(self, fd): >> super().__init__(fd=fd) >> + self.read_bitmap_directory(fd) >> + >> + def read_bitmap_directory(self, fd): >> + fd.seek(self.bitmap_directory_offset) >> + self.bitmap_directory = \ >> + [Qcow2BitmapDirEntry(fd) for _ in range(self.nb_bitmaps)] > > sounds good. I think, we should restore fd position after reading > bitmap_directory, to point at the end of extension, to not break > further extensions loading > > Yes, it is done in the constructor of QcowHeaderExtension: if self.magic == QCOW2_EXT_MAGIC_BITMAPS: ... position = fd.tell() ... self.obj = Qcow2BitmapExt(fd=fd) fd.seek(position) Andrey
13.07.2020 10:07, Andrey Shinkevich wrote: > On 11.07.2020 22:11, Vladimir Sementsov-Ogievskiy wrote: >> 03.07.2020 16:13, Andrey Shinkevich wrote: >>> Read and dump entries from the bitmap directory of QCOW2 image. >>> It extends the output in the test case #291. >>> >>> > ... >>> diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py >>> index d8c058d..7c0dc9a 100644 >>> --- a/tests/qemu-iotests/qcow2_format.py >>> +++ b/tests/qemu-iotests/qcow2_format.py >>> @@ -132,6 +132,50 @@ class Qcow2BitmapExt(Qcow2Struct): >>> def __init__(self, fd): >>> super().__init__(fd=fd) >>> + self.read_bitmap_directory(fd) >>> + >>> + def read_bitmap_directory(self, fd): >>> + fd.seek(self.bitmap_directory_offset) >>> + self.bitmap_directory = \ >>> + [Qcow2BitmapDirEntry(fd) for _ in range(self.nb_bitmaps)] >> >> sounds good. I think, we should restore fd position after reading bitmap_directory, to point at the end of extension, to not break further extensions loading >> >> > Yes, it is done in the constructor of QcowHeaderExtension: > > if self.magic == QCOW2_EXT_MAGIC_BITMAPS: > > ... > > position = fd.tell() > > ... > > self.obj = Qcow2BitmapExt(fd=fd) > > fd.seek(position) > I don't like it. If you want caller to care about fd, caller should know size of created child. But passing fd to constructor implies that caller not aware of size of new created structure. So I think good api is: constuctor starts to read the structure and left after this structure on exit from consturctor (so, caller may read following structures). Constructor may read some nested structures, but is responsible for restoring fd after it. -- Best regards, Vladimir
03.07.2020 16:13, Andrey Shinkevich wrote: > Read and dump entries from the bitmap directory of QCOW2 image. > It extends the output in the test case #291. > > Header extension: > magic 0x23852875 (Bitmaps) > ... > > Bitmap name bitmap-1 > bitmap_table_offset 0xf0000 > bitmap_table_size 1 > flags 0x2 (['auto']) > type 1 > granularity_bits 16 > name_size 8 > extra_data_size 0 > > Suggested-by: Kevin Wolf <kwolf@redhat.com> > Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> -- Best regards, Vladimir
16.07.2020 12:13, Vladimir Sementsov-Ogievskiy wrote: > > Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Oops, sorry, I wanted to answer v10 patch. Ignore this. -- Best regards, Vladimir
© 2016 - 2026 Red Hat, Inc.