QCowL2Meta l2meta;
} QCowAIOCB;
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+ if (acb->hd_aiocb)
+ bdrv_aio_cancel(acb->hd_aiocb);
+ qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+ .aiocb_size = sizeof(QCowAIOCB),
+ .cancel = qcow_aio_cancel,
+};
+
static void qcow_aio_read_cb(void *opaque, int ret);
static void qcow_aio_read_bh(void *opaque)
{
{
QCowAIOCB *acb;
- acb = qemu_aio_get(bs, cb, opaque);
+ acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
return &acb->common;
}
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- QCowAIOCB *acb = (QCowAIOCB *)blockacb;
- if (acb->hd_aiocb)
- bdrv_aio_cancel(acb->hd_aiocb);
- qemu_aio_release(acb);
-}
-
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
+ int64_t refcount_block_offset = 0;
+ int64_t table_index = -1, old_table_index;
+ int first_index = -1, last_index = -1;
#ifdef DEBUG_ALLOC2
printf("update_refcount: offset=%lld size=%lld addend=%d\n",
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size)
{
- int64_t refcount_block_offset;
int block_index, refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
+ /* Only write refcount block to disk when we are done with it */
+ old_table_index = table_index;
+ table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+ if ((old_table_index >= 0) && (table_index != old_table_index)) {
+ size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
+ if (bdrv_pwrite(s->hd,
+ refcount_block_offset + (first_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[first_index], size) != size)
+ {
+ return -EIO;
+ }
+
+ first_index = -1;
+ last_index = -1;
+ }
+
/* Load the refcount block and allocate it if needed */
refcount_block_offset = alloc_refcount_block(bs, cluster_index);
if (refcount_block_offset < 0) {
/* we can update the count and save it */
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+ if (first_index == -1 || block_index < first_index) {
+ first_index = block_index;
+ }
+ if (block_index > last_index) {
+ last_index = block_index;
+ }
+
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
refcount += addend;
if (refcount < 0 || refcount > 0xffff)
s->free_cluster_index = cluster_index;
}
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+ }
+
+ /* Write last changed block to disk */
+ if (refcount_block_offset != 0) {
+ size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
if (bdrv_pwrite(s->hd,
- refcount_block_offset + (block_index << REFCOUNT_SHIFT),
- &s->refcount_block_cache[block_index], 2) != 2)
+ refcount_block_offset + (first_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[first_index], size) != size)
+ {
return -EIO;
-
+ }
}
+
return 0;
}
}
static QEMUOptionParameter qcow_create_options[] = {
- { BLOCK_OPT_SIZE, OPT_SIZE },
- { BLOCK_OPT_BACKING_FILE, OPT_STRING },
- { BLOCK_OPT_BACKING_FMT, OPT_STRING },
- { BLOCK_OPT_ENCRYPT, OPT_FLAG },
- { BLOCK_OPT_CLUSTER_SIZE, OPT_SIZE },
+ {
+ .name = BLOCK_OPT_SIZE,
+ .type = OPT_SIZE,
+ .help = "Virtual disk size"
+ },
+ {
+ .name = BLOCK_OPT_BACKING_FILE,
+ .type = OPT_STRING,
+ .help = "File name of a base image"
+ },
+ {
+ .name = BLOCK_OPT_BACKING_FMT,
+ .type = OPT_STRING,
+ .help = "Image format of the base image"
+ },
+ {
+ .name = BLOCK_OPT_ENCRYPT,
+ .type = OPT_FLAG,
+ .help = "Encrypt the image"
+ },
+ {
+ .name = BLOCK_OPT_CLUSTER_SIZE,
+ .type = OPT_SIZE,
+ .help = "qcow2 cluster size"
+ },
{ NULL }
};
.bdrv_aio_readv = qcow_aio_readv,
.bdrv_aio_writev = qcow_aio_writev,
- .bdrv_aio_cancel = qcow_aio_cancel,
- .aiocb_size = sizeof(QCowAIOCB),
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_snapshot_create = qcow_snapshot_create,