qcow2: Batch flushes for COW
qcow2 calls bdrv_flush() after performing COW in order to ensure that the L2 table change is never written before the copy is safe on disk. Now that the L2 table is cached, we can wait with flushing until we write out the next L2 table. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
29c1a7301a
commit
3de0a2944b
@ -38,6 +38,7 @@ struct Qcow2Cache {
|
|||||||
int size;
|
int size;
|
||||||
Qcow2CachedTable* entries;
|
Qcow2CachedTable* entries;
|
||||||
struct Qcow2Cache* depends;
|
struct Qcow2Cache* depends;
|
||||||
|
bool depends_on_flush;
|
||||||
bool writethrough;
|
bool writethrough;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,13 +86,15 @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->depends = NULL;
|
c->depends = NULL;
|
||||||
|
c->depends_on_flush = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (!c->entries[i].dirty || !c->entries[i].offset) {
|
if (!c->entries[i].dirty || !c->entries[i].offset) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -99,11 +102,17 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
|||||||
|
|
||||||
if (c->depends) {
|
if (c->depends) {
|
||||||
ret = qcow2_cache_flush_dependency(bs, c);
|
ret = qcow2_cache_flush_dependency(bs, c);
|
||||||
if (ret < 0) {
|
} else if (c->depends_on_flush) {
|
||||||
return ret;
|
ret = bdrv_flush(bs->file);
|
||||||
|
if (ret >= 0) {
|
||||||
|
c->depends_on_flush = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (c == s->refcount_block_cache) {
|
if (c == s->refcount_block_cache) {
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
|
||||||
} else if (c == s->l2_table_cache) {
|
} else if (c == s->l2_table_cache) {
|
||||||
@ -167,6 +176,11 @@ int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qcow2_cache_depends_on_flush(Qcow2Cache *c)
|
||||||
|
{
|
||||||
|
c->depends_on_flush = true;
|
||||||
|
}
|
||||||
|
|
||||||
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
|
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -637,7 +637,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
|||||||
* handled.
|
* handled.
|
||||||
*/
|
*/
|
||||||
if (cow) {
|
if (cow) {
|
||||||
bdrv_flush(bs->file);
|
qcow2_cache_depends_on_flush(s->l2_table_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
|
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
|
||||||
|
@ -229,6 +229,7 @@ void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
|
|||||||
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
|
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
|
||||||
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
|
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
|
||||||
Qcow2Cache *dependency);
|
Qcow2Cache *dependency);
|
||||||
|
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
|
||||||
|
|
||||||
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
|
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
|
||||||
void **table);
|
void **table);
|
||||||
|
Loading…
Reference in New Issue
Block a user