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:
Eric Sunshine 2011-10-26 15:51:18 -04:00 committed by Kevin Wolf
parent 0f5314a2c8
commit c794b4e0fd

View File

@ -114,8 +114,13 @@ void uuid_unparse(const uuid_t uu, char *out);
*/ */
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n" #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
/* Unallocated blocks use this index (no need to convert endianness). */ /* A never-allocated block; semantically arbitrary content. */
#define VDI_UNALLOCATED UINT32_MAX #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) #if !defined(CONFIG_UUID)
void uuid_generate(uuid_t out) 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. */ /* Check block map and value of blocks_allocated. */
for (block = 0; block < s->header.blocks_in_image; block++) { for (block = 0; block < s->header.blocks_in_image; block++) {
uint32_t bmap_entry = le32_to_cpu(s->bmap[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) { if (bmap_entry < s->header.blocks_in_image) {
blocks_allocated++; blocks_allocated++;
if (bmap[bmap_entry] == VDI_UNALLOCATED) { if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
bmap[bmap_entry] = bmap_entry; bmap[bmap_entry] = bmap_entry;
} else { } else {
fprintf(stderr, "ERROR: block index %" PRIu32 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; n_sectors = nb_sectors;
} }
*pnum = n_sectors; *pnum = n_sectors;
return bmap_entry != VDI_UNALLOCATED; return VDI_IS_ALLOCATED(bmap_entry);
} }
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb) 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 */ /* prepare next AIO request */
acb->n_sectors = n_sectors; acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]); 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. */ /* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE); memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
ret = vdi_schedule_bh(vdi_aio_rw_bh, acb); 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) { if (acb->header_modified) {
VdiHeader *header = acb->block_buffer; VdiHeader *header = acb->block_buffer;
logout("now writing modified header\n"); logout("now writing modified header\n");
assert(acb->bmap_first != VDI_UNALLOCATED); assert(VDI_IS_ALLOCATED(acb->bmap_first));
*header = s->header; *header = s->header;
vdi_header_to_le(header); vdi_header_to_le(header);
acb->header_modified = 0; acb->header_modified = 0;
@ -699,7 +704,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
goto done; goto done;
} }
return; return;
} else if (acb->bmap_first != VDI_UNALLOCATED) { } else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
/* One or more new blocks were allocated. */ /* One or more new blocks were allocated. */
uint64_t offset; uint64_t offset;
uint32_t bmap_first; uint32_t bmap_first;
@ -749,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
/* prepare next AIO request */ /* prepare next AIO request */
acb->n_sectors = n_sectors; acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]); 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. */ /* Allocate new block and write to it. */
uint64_t offset; uint64_t offset;
uint8_t *block; uint8_t *block;