Allow tracking of first file write in the VHDX image, as well as the ability to update the GUID in the header. This is in preparation for log support.
Signed-off-by: Jeff Cody <jc...@redhat.com> --- block/vhdx.c | 28 +++++++++++++++++++++++----- block/vhdx.h | 7 +++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/block/vhdx.c b/block/vhdx.c index 9f7f04f..f5689c3 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -233,7 +233,8 @@ static int vhdx_probe(const uint8_t *buf, int buf_size, const char *filename) * * - non-current header is updated with largest sequence number */ -static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, bool rw) +static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, bool rw, + MSGUID *log_guid) { int ret = 0; int hdr_idx = 0; @@ -266,6 +267,11 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, bool rw) vhdx_guid_generate(&inactive_header->data_write_guid); } + /* update the log guid if present */ + if (log_guid) { + memcpy(&inactive_header->log_guid, log_guid, sizeof(MSGUID)); + } + /* the header checksum is not over just the packed size of VHDXHeader, * but rather over the entire 'reserved' range for the header, which is * 4KB (VHDX_HEADER_SIZE). */ @@ -293,15 +299,16 @@ fail: * The VHDX spec calls for header updates to be performed twice, so that both * the current and non-current header have valid info */ -static int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw) +int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw, + MSGUID *log_guid) { int ret; - ret = vhdx_update_header(bs, s, rw); + ret = vhdx_update_header(bs, s, rw, log_guid); if (ret < 0) { return ret; } - ret = vhdx_update_header(bs, s, rw); + ret = vhdx_update_header(bs, s, rw, log_guid); return ret; } @@ -781,6 +788,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags) s->bat = NULL; + s->first_visible_write = true; qemu_co_mutex_init(&s->lock); @@ -861,7 +869,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags) } if (flags & BDRV_O_RDWR) { - vhdx_update_headers(bs, s, false); + vhdx_update_headers(bs, s, false, NULL); } /* TODO: differencing files, write */ @@ -998,6 +1006,16 @@ exit: +/* Per the spec, on the first write of guest-visible data to the file the + * data write guid must be updated in the header */ +void vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s) +{ + if (s->first_visible_write) { + s->first_visible_write = false; + vhdx_update_headers(bs, s, true, NULL); + } +} + static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { diff --git a/block/vhdx.h b/block/vhdx.h index 5e0a1d3..cb3ce0e 100644 --- a/block/vhdx.h +++ b/block/vhdx.h @@ -366,6 +366,7 @@ typedef struct BDRVVHDXState { VHDXBatEntry *bat; uint64_t bat_offset; + bool first_visible_write; MSGUID session_guid; VHDXLogEntries log; @@ -377,6 +378,9 @@ typedef struct BDRVVHDXState { void vhdx_guid_generate(MSGUID *guid); +int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw, + MSGUID *log_guid); + uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset); uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size, int crc_offset); @@ -406,8 +410,7 @@ void vhdx_log_data_le_export(VHDXLogDataSector *d); void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr); void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr); - - +void vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s); -- 1.8.1.4