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 | 30 ++++++++++++++++++++++++------ block/vhdx.h | 6 ++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/block/vhdx.c b/block/vhdx.c index 15a4d1d..4dc056b 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -229,7 +229,7 @@ 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 generate_data_write_guid) + bool generate_data_write_guid, MSGUID *log_guid) { int ret = 0; int hdr_idx = 0; @@ -261,6 +261,11 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, vhdx_guid_generate(&inactive_header->data_write_guid); } + /* update the log guid if present */ + if (log_guid) { + inactive_header->log_guid = *log_guid; + } + /* 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,16 +298,16 @@ exit: * 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 generate_data_write_guid) +int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, + bool generate_data_write_guid, MSGUID *log_guid) { int ret; - ret = vhdx_update_header(bs, s, generate_data_write_guid); + ret = vhdx_update_header(bs, s, generate_data_write_guid, log_guid); if (ret < 0) { return ret; } - ret = vhdx_update_header(bs, s, generate_data_write_guid); + ret = vhdx_update_header(bs, s, generate_data_write_guid, log_guid); return ret; } @@ -782,6 +787,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); @@ -862,7 +868,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags) } if (flags & BDRV_O_RDWR) { - ret = vhdx_update_headers(bs, s, false); + ret = vhdx_update_headers(bs, s, false, NULL); if (ret < 0) { goto fail; } @@ -1002,6 +1008,18 @@ 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 */ +int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s) +{ + int ret = 0; + if (s->first_visible_write) { + s->first_visible_write = false; + ret = vhdx_update_headers(bs, s, true, NULL); + } + return ret; +} + 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 89d9a78..8c61bfd 100644 --- a/block/vhdx.h +++ b/block/vhdx.h @@ -361,6 +361,7 @@ typedef struct BDRVVHDXState { VHDXBatEntry *bat; uint64_t bat_offset; + bool first_visible_write; MSGUID session_guid; VHDXLogEntries log; @@ -372,6 +373,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); @@ -401,4 +405,6 @@ 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); +int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s); + #endif -- 1.8.1.4