2
* L2/refcount table cache for the QCOW2 format
4
* Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
#include "block/block_int.h"
26
#include "qemu-common.h"
30
typedef struct Qcow2CachedTable {
39
Qcow2CachedTable* entries;
40
struct Qcow2Cache* depends;
42
bool depends_on_flush;
45
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
47
BDRVQcowState *s = bs->opaque;
51
c = g_malloc0(sizeof(*c));
53
c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
55
for (i = 0; i < c->size; i++) {
56
c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
62
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
66
for (i = 0; i < c->size; i++) {
67
assert(c->entries[i].ref == 0);
68
qemu_vfree(c->entries[i].table);
77
static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
81
ret = qcow2_cache_flush(bs, c->depends);
87
c->depends_on_flush = false;
92
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
94
BDRVQcowState *s = bs->opaque;
97
if (!c->entries[i].dirty || !c->entries[i].offset) {
101
trace_qcow2_cache_entry_flush(qemu_coroutine_self(),
102
c == s->l2_table_cache, i);
105
ret = qcow2_cache_flush_dependency(bs, c);
106
} else if (c->depends_on_flush) {
107
ret = bdrv_flush(bs->file);
109
c->depends_on_flush = false;
117
if (c == s->refcount_block_cache) {
118
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
119
} else if (c == s->l2_table_cache) {
120
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
123
ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
129
c->entries[i].dirty = false;
134
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
136
BDRVQcowState *s = bs->opaque;
141
trace_qcow2_cache_flush(qemu_coroutine_self(), c == s->l2_table_cache);
143
for (i = 0; i < c->size; i++) {
144
ret = qcow2_cache_entry_flush(bs, c, i);
145
if (ret < 0 && result != -ENOSPC) {
151
ret = bdrv_flush(bs->file);
160
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
161
Qcow2Cache *dependency)
165
if (dependency->depends) {
166
ret = qcow2_cache_flush_dependency(bs, dependency);
172
if (c->depends && (c->depends != dependency)) {
173
ret = qcow2_cache_flush_dependency(bs, c);
179
c->depends = dependency;
183
void qcow2_cache_depends_on_flush(Qcow2Cache *c)
185
c->depends_on_flush = true;
188
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
191
int min_count = INT_MAX;
195
for (i = 0; i < c->size; i++) {
196
if (c->entries[i].ref) {
200
if (c->entries[i].cache_hits < min_count) {
202
min_count = c->entries[i].cache_hits;
205
/* Give newer hits priority */
206
/* TODO Check how to optimize the replacement strategy */
207
c->entries[i].cache_hits /= 2;
210
if (min_index == -1) {
211
/* This can't happen in current synchronous code, but leave the check
212
* here as a reminder for whoever starts using AIO with the cache */
218
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
219
uint64_t offset, void **table, bool read_from_disk)
221
BDRVQcowState *s = bs->opaque;
225
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
226
offset, read_from_disk);
228
/* Check if the table is already cached */
229
for (i = 0; i < c->size; i++) {
230
if (c->entries[i].offset == offset) {
235
/* If not, write a table back and replace it */
236
i = qcow2_cache_find_entry_to_replace(c);
237
trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
238
c == s->l2_table_cache, i);
243
ret = qcow2_cache_entry_flush(bs, c, i);
248
trace_qcow2_cache_get_read(qemu_coroutine_self(),
249
c == s->l2_table_cache, i);
250
c->entries[i].offset = 0;
251
if (read_from_disk) {
252
if (c == s->l2_table_cache) {
253
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
256
ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
262
/* Give the table some hits for the start so that it won't be replaced
263
* immediately. The number 32 is completely arbitrary. */
264
c->entries[i].cache_hits = 32;
265
c->entries[i].offset = offset;
267
/* And return the right table */
269
c->entries[i].cache_hits++;
271
*table = c->entries[i].table;
273
trace_qcow2_cache_get_done(qemu_coroutine_self(),
274
c == s->l2_table_cache, i);
279
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
282
return qcow2_cache_do_get(bs, c, offset, table, true);
285
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
288
return qcow2_cache_do_get(bs, c, offset, table, false);
291
int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
295
for (i = 0; i < c->size; i++) {
296
if (c->entries[i].table == *table) {
306
assert(c->entries[i].ref >= 0);
310
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
314
for (i = 0; i < c->size; i++) {
315
if (c->entries[i].table == table) {
322
c->entries[i].dirty = true;