Teach block/vdi about "discarded" (no longer allocated) blocks
An entry in the VDI block map will hold an offset to the actual block if the block is allocated, or one of two specially-interpreted values if not allocated. Using VirtualBox terminology, value VDI_IMAGE_BLOCK_FREE (0xffffffff) represents a never-allocated block (semantically arbitrary content). VDI_IMAGE_BLOCK_ZERO (0xfffffffe) represents a "discarded" block (semantically zero-filled). block/vdi knows only about VDI_IMAGE_BLOCK_FREE. Teach it about VDI_IMAGE_BLOCK_ZERO. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
0f5314a2c8
commit
c794b4e0fd
23
block/vdi.c
23
block/vdi.c
@ -114,8 +114,13 @@ void uuid_unparse(const uuid_t uu, char *out);
|
||||
*/
|
||||
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
|
||||
|
||||
/* Unallocated blocks use this index (no need to convert endianness). */
|
||||
#define VDI_UNALLOCATED UINT32_MAX
|
||||
/* A never-allocated block; semantically arbitrary content. */
|
||||
#define VDI_UNALLOCATED 0xffffffffU
|
||||
|
||||
/* A discarded (no longer allocated) block; semantically zero-filled. */
|
||||
#define VDI_DISCARDED 0xfffffffeU
|
||||
|
||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||
|
||||
#if !defined(CONFIG_UUID)
|
||||
void uuid_generate(uuid_t out)
|
||||
@ -307,10 +312,10 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
/* Check block map and value of blocks_allocated. */
|
||||
for (block = 0; block < s->header.blocks_in_image; block++) {
|
||||
uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
|
||||
if (bmap_entry != VDI_UNALLOCATED) {
|
||||
if (VDI_IS_ALLOCATED(bmap_entry)) {
|
||||
if (bmap_entry < s->header.blocks_in_image) {
|
||||
blocks_allocated++;
|
||||
if (bmap[bmap_entry] == VDI_UNALLOCATED) {
|
||||
if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
|
||||
bmap[bmap_entry] = bmap_entry;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: block index %" PRIu32
|
||||
@ -472,7 +477,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
n_sectors = nb_sectors;
|
||||
}
|
||||
*pnum = n_sectors;
|
||||
return bmap_entry != VDI_UNALLOCATED;
|
||||
return VDI_IS_ALLOCATED(bmap_entry);
|
||||
}
|
||||
|
||||
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
@ -603,7 +608,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
|
||||
/* prepare next AIO request */
|
||||
acb->n_sectors = n_sectors;
|
||||
bmap_entry = le32_to_cpu(s->bmap[block_index]);
|
||||
if (bmap_entry == VDI_UNALLOCATED) {
|
||||
if (!VDI_IS_ALLOCATED(bmap_entry)) {
|
||||
/* Block not allocated, return zeros, no need to wait. */
|
||||
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
|
||||
ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
|
||||
@ -685,7 +690,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
if (acb->header_modified) {
|
||||
VdiHeader *header = acb->block_buffer;
|
||||
logout("now writing modified header\n");
|
||||
assert(acb->bmap_first != VDI_UNALLOCATED);
|
||||
assert(VDI_IS_ALLOCATED(acb->bmap_first));
|
||||
*header = s->header;
|
||||
vdi_header_to_le(header);
|
||||
acb->header_modified = 0;
|
||||
@ -699,7 +704,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
goto done;
|
||||
}
|
||||
return;
|
||||
} else if (acb->bmap_first != VDI_UNALLOCATED) {
|
||||
} else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
|
||||
/* One or more new blocks were allocated. */
|
||||
uint64_t offset;
|
||||
uint32_t bmap_first;
|
||||
@ -749,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
/* prepare next AIO request */
|
||||
acb->n_sectors = n_sectors;
|
||||
bmap_entry = le32_to_cpu(s->bmap[block_index]);
|
||||
if (bmap_entry == VDI_UNALLOCATED) {
|
||||
if (!VDI_IS_ALLOCATED(bmap_entry)) {
|
||||
/* Allocate new block and write to it. */
|
||||
uint64_t offset;
|
||||
uint8_t *block;
|
||||
|
Loading…
Reference in New Issue
Block a user