From: Sanne Raymaekers <[email protected]> For stream optimized disks the spec notes: "The rgdOffset should be ignored because bit 1 of the flags field is not set." Where bit 1 of the flags field indicates a redundant grain directory (RGD).[^1]
In short, stream optimized disks should have the RGD offset set to 0, and only write the main grain directory. This patch also corrects the comments around the code writing the grain directories, and it makes the error thrown when it fails to write the backup grain directory more explicit. [^1] Virtual Disk Format 5.0 Technical Note. Signed-off-by: Sanne Raymaekers <[email protected]> Message-ID: <[email protected]> Reviewed-by: Kevin Wolf <[email protected]> Signed-off-by: Kevin Wolf <[email protected]> --- block/vmdk.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 7ca030c5fe9..e090e122f11 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2246,8 +2246,9 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress, } else { header.version = 1; } - header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT - | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) + header.flags = VMDK4_FLAG_NL_DETECT + | (compress ? + VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : VMDK4_FLAG_RGD) | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; header.capacity = filesize / BDRV_SECTOR_SIZE; @@ -2262,8 +2263,16 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress, header.desc_offset = 1; header.desc_size = 20; - header.rgd_offset = header.desc_offset + header.desc_size; - header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count); + + if (compress) { + header.rgd_offset = 0; + header.gd_offset = header.desc_offset + header.desc_size; + } else { + header.rgd_offset = header.desc_offset + header.desc_size; + header.gd_offset = + header.rgd_offset + gd_sectors + (gt_size * gt_count); + } + header.grain_offset = ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), header.granularity); @@ -2303,21 +2312,26 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress, goto exit; } - /* write grain directory */ + /* write backup grain directory */ gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; gd_buf = g_malloc0(gd_buf_size); - for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; - i < gt_count; i++, tmp += gt_size) { - gd_buf[i] = cpu_to_le32(tmp); - } - ret = blk_co_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, - gd_buf_size, gd_buf, 0); - if (ret < 0) { - error_setg_errno(errp, -ret, "failed to write VMDK grain directory"); - goto exit; + + if (!compress) { + for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; + i < gt_count; i++, tmp += gt_size) { + gd_buf[i] = cpu_to_le32(tmp); + } + ret = blk_co_pwrite(blk, + le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, + gd_buf_size, gd_buf, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, + "failed to write VMDK backup grain directory"); + goto exit; + } } - /* write backup grain directory */ + /* write grain directory */ for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; i < gt_count; i++, tmp += gt_size) { gd_buf[i] = cpu_to_le32(tmp); @@ -2326,7 +2340,7 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress, gd_buf_size, gd_buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, - "failed to write VMDK backup grain directory"); + "failed to write VMDK grain directory"); } ret = 0; -- 2.56.0
