#include "block/block_int.h"
#include "sysemu/block-backend.h"
#include "qemu/module.h"
-#include "migration/migration.h"
+#include "migration/blocker.h"
#include "qemu/bswap.h"
#include "qemu/uuid.h"
/*
* Returns the absolute byte offset of the given sector in the image file.
* If the sector is not allocated, -1 is returned instead.
+ * If an error occurred trying to write an updated block bitmap back to
+ * the file, -2 is returned, and the error value is written to *err.
+ * This can only happen for a write operation.
*
* The parameter write must be 1 if the offset will be used for a write
* operation (the block bitmaps is updated then), 0 otherwise.
+ * If write is true then err must not be NULL.
*/
static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
- bool write)
+ bool write, int *err)
{
BDRVVPCState *s = bs->opaque;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, offset_in_block;
+ assert(!(write && err == NULL));
+
pagetable_index = offset / s->block_size;
offset_in_block = offset % s->block_size;
correctness. */
if (write && (s->last_bitmap_offset != bitmap_offset)) {
uint8_t bitmap[s->bitmap_size];
+ int r;
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
- bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+ r = bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+ if (r < 0) {
+ *err = r;
+ return -2;
+ }
}
return block_offset;
}
-static inline int64_t get_sector_offset(BlockDriverState *bs,
- int64_t sector_num, bool write)
-{
- return get_image_offset(bs, sector_num * BDRV_SECTOR_SIZE, write);
-}
-
/*
* Writes the footer to the end of the image file. This is needed when the
* file grows as it overwrites the old footer
if (ret < 0)
goto fail;
- return get_image_offset(bs, offset, false);
+ return get_image_offset(bs, offset, false, NULL);
fail:
s->free_data_block_offset -= (s->block_size + s->bitmap_size);
qemu_iovec_init(&local_qiov, qiov->niov);
while (bytes > 0) {
- image_offset = get_image_offset(bs, offset, false);
+ image_offset = get_image_offset(bs, offset, false, NULL);
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
qemu_iovec_init(&local_qiov, qiov->niov);
while (bytes > 0) {
- image_offset = get_image_offset(bs, offset, true);
+ image_offset = get_image_offset(bs, offset, true, &ret);
+ if (image_offset == -2) {
+ /* Failed to write block bitmap: can't proceed with write */
+ goto fail;
+ }
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
VHDFooter *footer = (VHDFooter*) s->footer_buf;
int64_t start, offset;
bool allocated;
+ int64_t ret;
int n;
if (be32_to_cpu(footer->type) == VHD_FIXED) {
*pnum = nb_sectors;
*file = bs->file->bs;
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
(sector_num << BDRV_SECTOR_BITS);
}
- offset = get_sector_offset(bs, sector_num, 0);
+ qemu_co_mutex_lock(&s->lock);
+
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false, NULL);
start = offset;
allocated = (offset != -1);
*pnum = 0;
+ ret = 0;
do {
/* All sectors in a block are contiguous (without using the bitmap) */
* sectors since there is always a bitmap in between. */
if (allocated) {
*file = bs->file->bs;
- return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ break;
}
if (nb_sectors == 0) {
break;
}
- offset = get_sector_offset(bs, sector_num, 0);
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false,
+ NULL);
} while (offset == -1);
- return 0;
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
}
/*
/* Add footer to total size */
total_size += HEADER_SIZE;
- ret = blk_truncate(blk, total_size, errp);
+ ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
return ret;
}