Re: [RFC 2/4] qcow2: add configurations for zoned format extension
Stefan Hajnoczi 于2023年6月20日周二 22:48写道: > > On Mon, Jun 19, 2023 at 10:50:31PM +0800, Sam Li wrote: > > Stefan Hajnoczi 于2023年6月19日周一 22:42写道: > > > > > > On Mon, Jun 19, 2023 at 06:32:52PM +0800, Sam Li wrote: > > > > Stefan Hajnoczi 于2023年6月19日周一 18:10写道: > > > > > On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > > > > > > diff --git a/block/qcow2.h b/block/qcow2.h > > > > > > index 4f67eb912a..fe18dc4d97 100644 > > > > > > --- a/block/qcow2.h > > > > > > +++ b/block/qcow2.h > > > > > > @@ -235,6 +235,20 @@ typedef struct Qcow2CryptoHeaderExtension { > > > > > > uint64_t length; > > > > > > } QEMU_PACKED Qcow2CryptoHeaderExtension; > > > > > > > > > > > > +typedef struct Qcow2ZonedHeaderExtension { > > > > > > +/* Zoned device attributes */ > > > > > > +BlockZonedProfile zoned_profile; > > > > > > +BlockZoneModel zoned; > > > > > > +uint32_t zone_size; > > > > > > +uint32_t zone_capacity; > > > > > > +uint32_t nr_zones; > > > > > > +uint32_t zone_nr_conv; > > > > > > +uint32_t max_active_zones; > > > > > > +uint32_t max_open_zones; > > > > > > +uint32_t max_append_sectors; > > > > > > +uint8_t padding[3]; > > > > > > > > > > This looks strange. Why is there 3 bytes of padding at the end? > > > > > Normally > > > > > padding would align to an even power-of-two number of bytes like 2, 4, > > > > > 8, etc. > > > > > > > > It is calculated as 3 if sizeof(zoned+zoned_profile) = 8. Else if it's > > > > 16, the padding is 2. > > > > > > I don't understand. Can you explain why there is padding at the end of > > > this struct? > > > > The overall size should be aligned with 64 bit, which leaves use one > > uint32_t and two fields zoned, zoned_profile. I am not sure the size > > of macros here and it used 4 for each. So it makes 3 (*8) + 32 + 8 = > > 64 in the end. If the macro size is wrong, then the padding will > > change as well. > > The choice of the type (char or int) representing an enum is > implementation-defined according to the C17 standard (see "6.7.2.2 > Enumeration specifiers"). > > Therefore it's not portable to use enums in structs exposed to the > outside world (on-disk formats or network protocols). > > Please use uint8_t for the zoned_profile and zoned fields and move them > to the end of the struct so the uint32_t fields are naturally aligned. > > I think only 2 bytes of padding will be required to align the struct to > a 64-bit boundary once you've done that. I see. Thanks! Sam
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
On Mon, Jun 19, 2023 at 10:50:31PM +0800, Sam Li wrote: > Stefan Hajnoczi 于2023年6月19日周一 22:42写道: > > > > On Mon, Jun 19, 2023 at 06:32:52PM +0800, Sam Li wrote: > > > Stefan Hajnoczi 于2023年6月19日周一 18:10写道: > > > > On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > > > > > diff --git a/block/qcow2.h b/block/qcow2.h > > > > > index 4f67eb912a..fe18dc4d97 100644 > > > > > --- a/block/qcow2.h > > > > > +++ b/block/qcow2.h > > > > > @@ -235,6 +235,20 @@ typedef struct Qcow2CryptoHeaderExtension { > > > > > uint64_t length; > > > > > } QEMU_PACKED Qcow2CryptoHeaderExtension; > > > > > > > > > > +typedef struct Qcow2ZonedHeaderExtension { > > > > > +/* Zoned device attributes */ > > > > > +BlockZonedProfile zoned_profile; > > > > > +BlockZoneModel zoned; > > > > > +uint32_t zone_size; > > > > > +uint32_t zone_capacity; > > > > > +uint32_t nr_zones; > > > > > +uint32_t zone_nr_conv; > > > > > +uint32_t max_active_zones; > > > > > +uint32_t max_open_zones; > > > > > +uint32_t max_append_sectors; > > > > > +uint8_t padding[3]; > > > > > > > > This looks strange. Why is there 3 bytes of padding at the end? Normally > > > > padding would align to an even power-of-two number of bytes like 2, 4, > > > > 8, etc. > > > > > > It is calculated as 3 if sizeof(zoned+zoned_profile) = 8. Else if it's > > > 16, the padding is 2. > > > > I don't understand. Can you explain why there is padding at the end of > > this struct? > > The overall size should be aligned with 64 bit, which leaves use one > uint32_t and two fields zoned, zoned_profile. I am not sure the size > of macros here and it used 4 for each. So it makes 3 (*8) + 32 + 8 = > 64 in the end. If the macro size is wrong, then the padding will > change as well. The choice of the type (char or int) representing an enum is implementation-defined according to the C17 standard (see "6.7.2.2 Enumeration specifiers"). Therefore it's not portable to use enums in structs exposed to the outside world (on-disk formats or network protocols). Please use uint8_t for the zoned_profile and zoned fields and move them to the end of the struct so the uint32_t fields are naturally aligned. I think only 2 bytes of padding will be required to align the struct to a 64-bit boundary once you've done that. Stefan signature.asc Description: PGP signature
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
Stefan Hajnoczi 于2023年6月19日周一 22:42写道: > > On Mon, Jun 19, 2023 at 06:32:52PM +0800, Sam Li wrote: > > Stefan Hajnoczi 于2023年6月19日周一 18:10写道: > > > On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > > > > diff --git a/block/qcow2.h b/block/qcow2.h > > > > index 4f67eb912a..fe18dc4d97 100644 > > > > --- a/block/qcow2.h > > > > +++ b/block/qcow2.h > > > > @@ -235,6 +235,20 @@ typedef struct Qcow2CryptoHeaderExtension { > > > > uint64_t length; > > > > } QEMU_PACKED Qcow2CryptoHeaderExtension; > > > > > > > > +typedef struct Qcow2ZonedHeaderExtension { > > > > +/* Zoned device attributes */ > > > > +BlockZonedProfile zoned_profile; > > > > +BlockZoneModel zoned; > > > > +uint32_t zone_size; > > > > +uint32_t zone_capacity; > > > > +uint32_t nr_zones; > > > > +uint32_t zone_nr_conv; > > > > +uint32_t max_active_zones; > > > > +uint32_t max_open_zones; > > > > +uint32_t max_append_sectors; > > > > +uint8_t padding[3]; > > > > > > This looks strange. Why is there 3 bytes of padding at the end? Normally > > > padding would align to an even power-of-two number of bytes like 2, 4, > > > 8, etc. > > > > It is calculated as 3 if sizeof(zoned+zoned_profile) = 8. Else if it's > > 16, the padding is 2. > > I don't understand. Can you explain why there is padding at the end of > this struct? The overall size should be aligned with 64 bit, which leaves use one uint32_t and two fields zoned, zoned_profile. I am not sure the size of macros here and it used 4 for each. So it makes 3 (*8) + 32 + 8 = 64 in the end. If the macro size is wrong, then the padding will change as well. Sam
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
On Mon, Jun 19, 2023 at 06:32:52PM +0800, Sam Li wrote: > Stefan Hajnoczi 于2023年6月19日周一 18:10写道: > > On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > > > diff --git a/block/qcow2.h b/block/qcow2.h > > > index 4f67eb912a..fe18dc4d97 100644 > > > --- a/block/qcow2.h > > > +++ b/block/qcow2.h > > > @@ -235,6 +235,20 @@ typedef struct Qcow2CryptoHeaderExtension { > > > uint64_t length; > > > } QEMU_PACKED Qcow2CryptoHeaderExtension; > > > > > > +typedef struct Qcow2ZonedHeaderExtension { > > > +/* Zoned device attributes */ > > > +BlockZonedProfile zoned_profile; > > > +BlockZoneModel zoned; > > > +uint32_t zone_size; > > > +uint32_t zone_capacity; > > > +uint32_t nr_zones; > > > +uint32_t zone_nr_conv; > > > +uint32_t max_active_zones; > > > +uint32_t max_open_zones; > > > +uint32_t max_append_sectors; > > > +uint8_t padding[3]; > > > > This looks strange. Why is there 3 bytes of padding at the end? Normally > > padding would align to an even power-of-two number of bytes like 2, 4, > > 8, etc. > > It is calculated as 3 if sizeof(zoned+zoned_profile) = 8. Else if it's > 16, the padding is 2. I don't understand. Can you explain why there is padding at the end of this struct? signature.asc Description: PGP signature
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
Stefan Hajnoczi 于2023年6月19日周一 18:10写道: > > On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > > To configure the zoned format feature on the qcow2 driver, it > > requires following arguments: the device size, zoned profile, > > zoned model, zone size, zone capacity, number of conventional > > zones, limits on zone resources (max append sectors, max open > > zones, and max_active_zones). > > > > To create a qcow2 file with zoned format, use command like this: > > $ qemu-img create -f qcow2 test.qcow2 -o size=768M -o > > zone_size=64M -o zone_capacity=64M -o zone_nr_conv=0 -o > > max_append_sectors=512 -o max_open_zones=0 -o max_active_zones=0 > > -o zoned_profile=zbc > > > > Signed-off-by: Sam Li > > --- > > block/qcow2.c| 119 +++ > > block/qcow2.h| 21 ++ > > include/block/block-common.h | 5 ++ > > include/block/block_int-common.h | 8 +++ > > qapi/block-core.json | 46 > > 5 files changed, 185 insertions(+), 14 deletions(-) > > > > diff --git a/block/qcow2.c b/block/qcow2.c > > index 7f3948360d..b886dab42b 100644 > > --- a/block/qcow2.c > > +++ b/block/qcow2.c > > @@ -73,6 +73,7 @@ typedef struct { > > #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 > > #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 > > #define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 > > +#define QCOW2_EXT_MAGIC_ZONED_FORMAT 0x7a6264 > > > > static int coroutine_fn > > qcow2_co_preadv_compressed(BlockDriverState *bs, > > @@ -210,6 +211,7 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > > start_offset, > > uint64_t offset; > > int ret; > > Qcow2BitmapHeaderExt bitmaps_ext; > > +Qcow2ZonedHeaderExtension zoned_ext; > > > > if (need_update_header != NULL) { > > *need_update_header = false; > > @@ -431,6 +433,37 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > > start_offset, > > break; > > } > > > > +case QCOW2_EXT_MAGIC_ZONED_FORMAT: > > +{ > > +if (ext.len != sizeof(zoned_ext)) { > > +error_setg_errno(errp, -ret, "zoned_ext: " > > + "Invalid extension length"); > > +return -EINVAL; > > +} > > +ret = bdrv_pread(bs->file, offset, ext.len, _ext, 0); > > +if (ret < 0) { > > +error_setg_errno(errp, -ret, "zoned_ext: " > > + "Could not read ext header"); > > +return ret; > > +} > > + > > +zoned_ext.zone_size = be32_to_cpu(zoned_ext.zone_size); > > +zoned_ext.nr_zones = be32_to_cpu(zoned_ext.nr_zones); > > +zoned_ext.zone_nr_conv = be32_to_cpu(zoned_ext.zone_nr_conv); > > +zoned_ext.max_open_zones = > > be32_to_cpu(zoned_ext.max_open_zones); > > +zoned_ext.max_active_zones = > > +be32_to_cpu(zoned_ext.max_active_zones); > > +zoned_ext.max_append_sectors = > > +be32_to_cpu(zoned_ext.max_append_sectors); > > +s->zoned_header = zoned_ext; > > Please validate these values. The image file is not trusted and may be > broken/corrupt. For example, zone_size=0 and nr_zones=0 must be rejected > because the code can't do anything useful when these values are zero > (similar for values that are not multiples of the block size). > > > + > > +#ifdef DEBUG_EXT > > +printf("Qcow2: Got zoned format extension: " > > + "offset=%" PRIu32 "\n", offset); > > +#endif > > +break; > > +} > > + > > default: > > /* unknown magic - save it in case we need to rewrite the > > header */ > > /* If you add a new feature, make sure to also update the fast > > @@ -3071,6 +3104,31 @@ int qcow2_update_header(BlockDriverState *bs) > > buflen -= ret; > > } > > > > +/* Zoned devices header extension */ > > +if (s->zoned_header.zoned == BLK_Z_HM) { > > +Qcow2ZonedHeaderExtension zoned_header = { > > +.zoned_profile = s->zoned_header.zoned_profile, > > +.zoned = s->zoned_header.zoned, > > +.nr_zones = cpu_to_be32(s->zoned_header.nr_zones), > > +.zone_size = cpu_to_be32(s->zoned_header.zone_size), > > +.zone_capacity = > > cpu_to_be32(s->zoned_header.zone_capacity), > > +.zone_nr_conv = > > cpu_to_be32(s->zoned_header.zone_nr_conv), > > +.max_open_zones = > > cpu_to_be32(s->zoned_header.max_open_zones), > > +.max_active_zones = > > +cpu_to_be32(s->zoned_header.max_active_zones), > > +.max_append_sectors = > > +cpu_to_be32(s->zoned_header.max_append_sectors) > > +}; > > +ret = header_ext_add(buf, QCOW2_EXT_MAGIC_ZONED_FORMAT, > > +
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > To configure the zoned format feature on the qcow2 driver, it > requires following arguments: the device size, zoned profile, > zoned model, zone size, zone capacity, number of conventional > zones, limits on zone resources (max append sectors, max open > zones, and max_active_zones). > > To create a qcow2 file with zoned format, use command like this: > $ qemu-img create -f qcow2 test.qcow2 -o size=768M -o > zone_size=64M -o zone_capacity=64M -o zone_nr_conv=0 -o > max_append_sectors=512 -o max_open_zones=0 -o max_active_zones=0 > -o zoned_profile=zbc > > Signed-off-by: Sam Li > --- > block/qcow2.c| 119 +++ > block/qcow2.h| 21 ++ > include/block/block-common.h | 5 ++ > include/block/block_int-common.h | 8 +++ > qapi/block-core.json | 46 > 5 files changed, 185 insertions(+), 14 deletions(-) > > diff --git a/block/qcow2.c b/block/qcow2.c > index 7f3948360d..b886dab42b 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -73,6 +73,7 @@ typedef struct { > #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 > #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 > #define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 > +#define QCOW2_EXT_MAGIC_ZONED_FORMAT 0x7a6264 > > static int coroutine_fn > qcow2_co_preadv_compressed(BlockDriverState *bs, > @@ -210,6 +211,7 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > start_offset, > uint64_t offset; > int ret; > Qcow2BitmapHeaderExt bitmaps_ext; > +Qcow2ZonedHeaderExtension zoned_ext; > > if (need_update_header != NULL) { > *need_update_header = false; > @@ -431,6 +433,37 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > start_offset, > break; > } > > +case QCOW2_EXT_MAGIC_ZONED_FORMAT: > +{ > +if (ext.len != sizeof(zoned_ext)) { > +error_setg_errno(errp, -ret, "zoned_ext: " > + "Invalid extension length"); > +return -EINVAL; > +} > +ret = bdrv_pread(bs->file, offset, ext.len, _ext, 0); > +if (ret < 0) { > +error_setg_errno(errp, -ret, "zoned_ext: " > + "Could not read ext header"); > +return ret; > +} > + > +zoned_ext.zone_size = be32_to_cpu(zoned_ext.zone_size); > +zoned_ext.nr_zones = be32_to_cpu(zoned_ext.nr_zones); > +zoned_ext.zone_nr_conv = be32_to_cpu(zoned_ext.zone_nr_conv); > +zoned_ext.max_open_zones = be32_to_cpu(zoned_ext.max_open_zones); > +zoned_ext.max_active_zones = > +be32_to_cpu(zoned_ext.max_active_zones); > +zoned_ext.max_append_sectors = > +be32_to_cpu(zoned_ext.max_append_sectors); > +s->zoned_header = zoned_ext; Please validate these values. The image file is not trusted and may be broken/corrupt. For example, zone_size=0 and nr_zones=0 must be rejected because the code can't do anything useful when these values are zero (similar for values that are not multiples of the block size). > + > +#ifdef DEBUG_EXT > +printf("Qcow2: Got zoned format extension: " > + "offset=%" PRIu32 "\n", offset); > +#endif > +break; > +} > + > default: > /* unknown magic - save it in case we need to rewrite the header > */ > /* If you add a new feature, make sure to also update the fast > @@ -3071,6 +3104,31 @@ int qcow2_update_header(BlockDriverState *bs) > buflen -= ret; > } > > +/* Zoned devices header extension */ > +if (s->zoned_header.zoned == BLK_Z_HM) { > +Qcow2ZonedHeaderExtension zoned_header = { > +.zoned_profile = s->zoned_header.zoned_profile, > +.zoned = s->zoned_header.zoned, > +.nr_zones = cpu_to_be32(s->zoned_header.nr_zones), > +.zone_size = cpu_to_be32(s->zoned_header.zone_size), > +.zone_capacity = cpu_to_be32(s->zoned_header.zone_capacity), > +.zone_nr_conv = cpu_to_be32(s->zoned_header.zone_nr_conv), > +.max_open_zones = > cpu_to_be32(s->zoned_header.max_open_zones), > +.max_active_zones = > +cpu_to_be32(s->zoned_header.max_active_zones), > +.max_append_sectors = > +cpu_to_be32(s->zoned_header.max_append_sectors) > +}; > +ret = header_ext_add(buf, QCOW2_EXT_MAGIC_ZONED_FORMAT, > + _header, sizeof(zoned_header), > + buflen); > +if (ret < 0) { > +goto fail; > +} > +buf += ret; > +buflen -= ret; > +} > + > /* Keep unknown header extensions
Re: [RFC 2/4] qcow2: add configurations for zoned format extension
On Mon, Jun 05, 2023 at 06:41:06PM +0800, Sam Li wrote: > To configure the zoned format feature on the qcow2 driver, it > requires following arguments: the device size, zoned profile, > zoned model, zone size, zone capacity, number of conventional > zones, limits on zone resources (max append sectors, max open > zones, and max_active_zones). > > To create a qcow2 file with zoned format, use command like this: > $ qemu-img create -f qcow2 test.qcow2 -o size=768M -o > zone_size=64M -o zone_capacity=64M -o zone_nr_conv=0 -o > max_append_sectors=512 -o max_open_zones=0 -o max_active_zones=0 > -o zoned_profile=zbc > > Signed-off-by: Sam Li > --- > block/qcow2.c| 119 +++ > block/qcow2.h| 21 ++ > include/block/block-common.h | 5 ++ > include/block/block_int-common.h | 8 +++ > qapi/block-core.json | 46 > 5 files changed, 185 insertions(+), 14 deletions(-) > ... > diff --git a/block/qcow2.c b/block/qcow2.c > index 7f3948360d..b886dab42b 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -73,6 +73,7 @@ typedef struct { > #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 > #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 > #define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 > +#define QCOW2_EXT_MAGIC_ZONED_FORMAT 0x7a6264 > > static int coroutine_fn > qcow2_co_preadv_compressed(BlockDriverState *bs, > @@ -210,6 +211,7 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > start_offset, > uint64_t offset; > int ret; > Qcow2BitmapHeaderExt bitmaps_ext; > +Qcow2ZonedHeaderExtension zoned_ext; > > if (need_update_header != NULL) { > *need_update_header = false; > @@ -431,6 +433,37 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t > start_offset, > break; > } > > +case QCOW2_EXT_MAGIC_ZONED_FORMAT: > +{ Missing a patch to docs/interop/qcow2.txt that describes the new header so that other qcow2 implementations can be interoperable with it. [unrelated - maybe we should convert that file to .rst someday?] -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
[RFC 2/4] qcow2: add configurations for zoned format extension
To configure the zoned format feature on the qcow2 driver, it requires following arguments: the device size, zoned profile, zoned model, zone size, zone capacity, number of conventional zones, limits on zone resources (max append sectors, max open zones, and max_active_zones). To create a qcow2 file with zoned format, use command like this: $ qemu-img create -f qcow2 test.qcow2 -o size=768M -o zone_size=64M -o zone_capacity=64M -o zone_nr_conv=0 -o max_append_sectors=512 -o max_open_zones=0 -o max_active_zones=0 -o zoned_profile=zbc Signed-off-by: Sam Li --- block/qcow2.c| 119 +++ block/qcow2.h| 21 ++ include/block/block-common.h | 5 ++ include/block/block_int-common.h | 8 +++ qapi/block-core.json | 46 5 files changed, 185 insertions(+), 14 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 7f3948360d..b886dab42b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -73,6 +73,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 #define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 +#define QCOW2_EXT_MAGIC_ZONED_FORMAT 0x7a6264 static int coroutine_fn qcow2_co_preadv_compressed(BlockDriverState *bs, @@ -210,6 +211,7 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uint64_t offset; int ret; Qcow2BitmapHeaderExt bitmaps_ext; +Qcow2ZonedHeaderExtension zoned_ext; if (need_update_header != NULL) { *need_update_header = false; @@ -431,6 +433,37 @@ qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, break; } +case QCOW2_EXT_MAGIC_ZONED_FORMAT: +{ +if (ext.len != sizeof(zoned_ext)) { +error_setg_errno(errp, -ret, "zoned_ext: " + "Invalid extension length"); +return -EINVAL; +} +ret = bdrv_pread(bs->file, offset, ext.len, _ext, 0); +if (ret < 0) { +error_setg_errno(errp, -ret, "zoned_ext: " + "Could not read ext header"); +return ret; +} + +zoned_ext.zone_size = be32_to_cpu(zoned_ext.zone_size); +zoned_ext.nr_zones = be32_to_cpu(zoned_ext.nr_zones); +zoned_ext.zone_nr_conv = be32_to_cpu(zoned_ext.zone_nr_conv); +zoned_ext.max_open_zones = be32_to_cpu(zoned_ext.max_open_zones); +zoned_ext.max_active_zones = +be32_to_cpu(zoned_ext.max_active_zones); +zoned_ext.max_append_sectors = +be32_to_cpu(zoned_ext.max_append_sectors); +s->zoned_header = zoned_ext; + +#ifdef DEBUG_EXT +printf("Qcow2: Got zoned format extension: " + "offset=%" PRIu32 "\n", offset); +#endif +break; +} + default: /* unknown magic - save it in case we need to rewrite the header */ /* If you add a new feature, make sure to also update the fast @@ -3071,6 +3104,31 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } +/* Zoned devices header extension */ +if (s->zoned_header.zoned == BLK_Z_HM) { +Qcow2ZonedHeaderExtension zoned_header = { +.zoned_profile = s->zoned_header.zoned_profile, +.zoned = s->zoned_header.zoned, +.nr_zones = cpu_to_be32(s->zoned_header.nr_zones), +.zone_size = cpu_to_be32(s->zoned_header.zone_size), +.zone_capacity = cpu_to_be32(s->zoned_header.zone_capacity), +.zone_nr_conv = cpu_to_be32(s->zoned_header.zone_nr_conv), +.max_open_zones = cpu_to_be32(s->zoned_header.max_open_zones), +.max_active_zones = +cpu_to_be32(s->zoned_header.max_active_zones), +.max_append_sectors = +cpu_to_be32(s->zoned_header.max_append_sectors) +}; +ret = header_ext_add(buf, QCOW2_EXT_MAGIC_ZONED_FORMAT, + _header, sizeof(zoned_header), + buflen); +if (ret < 0) { +goto fail; +} +buf += ret; +buflen -= ret; +} + /* Keep unknown header extensions */ QLIST_FOREACH(uext, >unknown_header_ext, next) { ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen); @@ -3755,6 +3813,18 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) s->image_data_file = g_strdup(data_bs->filename); } +if (!strcmp(qcow2_opts->zoned_profile, "zbc")) { +BDRVQcow2State *s = blk_bs(blk)->opaque; +s->zoned_header.zoned_profile = BLK_ZP_ZBC; +s->zoned_header.zoned = BLK_Z_HM; +s->zoned_header.zone_size = qcow2_opts->zone_size; +