Commit 6e641f2440 for qemu.org
commit 6e641f2440aa637c670b7f0fe512ea3fc2611b99
Author: Sanne Raymaekers <sraymaek@redhat.com>
Date: Fri Oct 16 14:37:50 2026 +0200
block/vmdk: add eos marker for stream optimized disks
The end of stream marker should be at the very end of a stream optimized
disk. It consists of a regular marker struct with `val`, `size` and
`type` set to 0. It is then padded with more 0s to fill out a
sector. This effectively results in 512 zero bytes.[^1]
[^1] Virtual Disk Format 5.0 Technical Note.
Signed-off-by: Sanne Raymaekers <sraymaek@redhat.com>
Message-ID: <20261016123750.94769-4-sraymaek@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
diff --git a/block/vmdk.c b/block/vmdk.c
index e090e122f1..b6e78a2b5d 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -195,6 +195,13 @@ typedef struct VmdkGrainMarker {
uint8_t data[];
} QEMU_PACKED VmdkGrainMarker;
+typedef struct EosMarker {
+ uint64_t val;
+ uint32_t size;
+ uint32_t type;
+ uint8_t pad[512 - 16];
+} QEMU_PACKED EosMarker;
+
enum {
MARKER_END_OF_STREAM = 0,
MARKER_GRAIN_TABLE = 1,
@@ -987,12 +994,7 @@ vmdk_open_vmdk4(BlockDriverState *bs, BdrvChild *file, int flags,
VMDK4Header header;
uint8_t pad[512 - 4 - sizeof(VMDK4Header)];
- struct {
- uint64_t val;
- uint32_t size;
- uint32_t type;
- uint8_t pad[512 - 16];
- } QEMU_PACKED eos_marker;
+ EosMarker eos_marker;
} QEMU_PACKED footer;
ret = bdrv_pread(file, bs->file->bs->total_sectors * 512 - 1536,
@@ -2182,23 +2184,29 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov)
{
if (bytes == 0) {
- /* The caller will write bytes 0 to signal EOF.
- * When receive it, we align EOF to a sector boundary. */
+ /* The caller will write bytes 0 to signal EOF. */
BDRVVmdkState *s = bs->opaque;
- int i, ret;
+ int ret;
int64_t length;
+ QEMU_AUTO_VFREE EosMarker *eos_marker = NULL;
- for (i = 0; i < s->num_extents; i++) {
- length = bdrv_co_getlength(s->extents[i].file->bs);
- if (length < 0) {
- return length;
- }
- length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
- ret = bdrv_co_truncate(s->extents[i].file, length, false,
- PREALLOC_MODE_OFF, 0, NULL);
- if (ret < 0) {
- return ret;
- }
+ /* Stream optimized disks should only contain a single extent. */
+ assert(s->num_extents == 1);
+
+ /*
+ * Stream optimized disks end with an EOS marker,
+ * consisting of 512 null bytes.
+ */
+ eos_marker = qemu_blockalign0(bs, sizeof(EosMarker));
+ length = bdrv_co_getlength(s->extents[0].file->bs);
+ if (length < 0) {
+ return length;
+ }
+ length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
+ ret = bdrv_co_pwrite(s->extents[0].file, length, sizeof(EosMarker),
+ eos_marker, 0);
+ if (ret < 0) {
+ return ret;
}
return 0;
}