Statistics
| Branch: | Revision:

root / block / qcow2-cache.c @ c6df7102

History | View | Annotate | Download (7.3 kB)

1 49381094 Kevin Wolf
/*
2 49381094 Kevin Wolf
 * L2/refcount table cache for the QCOW2 format
3 49381094 Kevin Wolf
 *
4 49381094 Kevin Wolf
 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
5 49381094 Kevin Wolf
 *
6 49381094 Kevin Wolf
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 49381094 Kevin Wolf
 * of this software and associated documentation files (the "Software"), to deal
8 49381094 Kevin Wolf
 * in the Software without restriction, including without limitation the rights
9 49381094 Kevin Wolf
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 49381094 Kevin Wolf
 * copies of the Software, and to permit persons to whom the Software is
11 49381094 Kevin Wolf
 * furnished to do so, subject to the following conditions:
12 49381094 Kevin Wolf
 *
13 49381094 Kevin Wolf
 * The above copyright notice and this permission notice shall be included in
14 49381094 Kevin Wolf
 * all copies or substantial portions of the Software.
15 49381094 Kevin Wolf
 *
16 49381094 Kevin Wolf
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 49381094 Kevin Wolf
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 49381094 Kevin Wolf
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 49381094 Kevin Wolf
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 49381094 Kevin Wolf
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 49381094 Kevin Wolf
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 49381094 Kevin Wolf
 * THE SOFTWARE.
23 49381094 Kevin Wolf
 */
24 49381094 Kevin Wolf
25 49381094 Kevin Wolf
#include "block_int.h"
26 49381094 Kevin Wolf
#include "qemu-common.h"
27 49381094 Kevin Wolf
#include "qcow2.h"
28 49381094 Kevin Wolf
29 49381094 Kevin Wolf
typedef struct Qcow2CachedTable {
30 49381094 Kevin Wolf
    void*   table;
31 49381094 Kevin Wolf
    int64_t offset;
32 49381094 Kevin Wolf
    bool    dirty;
33 49381094 Kevin Wolf
    int     cache_hits;
34 49381094 Kevin Wolf
    int     ref;
35 49381094 Kevin Wolf
} Qcow2CachedTable;
36 49381094 Kevin Wolf
37 49381094 Kevin Wolf
struct Qcow2Cache {
38 49381094 Kevin Wolf
    Qcow2CachedTable*       entries;
39 49381094 Kevin Wolf
    struct Qcow2Cache*      depends;
40 bf595021 Jes Sorensen
    int                     size;
41 3de0a294 Kevin Wolf
    bool                    depends_on_flush;
42 49381094 Kevin Wolf
    bool                    writethrough;
43 49381094 Kevin Wolf
};
44 49381094 Kevin Wolf
45 49381094 Kevin Wolf
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
46 49381094 Kevin Wolf
    bool writethrough)
47 49381094 Kevin Wolf
{
48 49381094 Kevin Wolf
    BDRVQcowState *s = bs->opaque;
49 49381094 Kevin Wolf
    Qcow2Cache *c;
50 49381094 Kevin Wolf
    int i;
51 49381094 Kevin Wolf
52 49381094 Kevin Wolf
    c = qemu_mallocz(sizeof(*c));
53 49381094 Kevin Wolf
    c->size = num_tables;
54 49381094 Kevin Wolf
    c->entries = qemu_mallocz(sizeof(*c->entries) * num_tables);
55 49381094 Kevin Wolf
    c->writethrough = writethrough;
56 49381094 Kevin Wolf
57 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
58 49381094 Kevin Wolf
        c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
59 49381094 Kevin Wolf
    }
60 49381094 Kevin Wolf
61 49381094 Kevin Wolf
    return c;
62 49381094 Kevin Wolf
}
63 49381094 Kevin Wolf
64 49381094 Kevin Wolf
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
65 49381094 Kevin Wolf
{
66 49381094 Kevin Wolf
    int i;
67 49381094 Kevin Wolf
68 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
69 49381094 Kevin Wolf
        assert(c->entries[i].ref == 0);
70 49381094 Kevin Wolf
        qemu_vfree(c->entries[i].table);
71 49381094 Kevin Wolf
    }
72 49381094 Kevin Wolf
73 49381094 Kevin Wolf
    qemu_free(c->entries);
74 49381094 Kevin Wolf
    qemu_free(c);
75 49381094 Kevin Wolf
76 49381094 Kevin Wolf
    return 0;
77 49381094 Kevin Wolf
}
78 49381094 Kevin Wolf
79 49381094 Kevin Wolf
static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
80 49381094 Kevin Wolf
{
81 49381094 Kevin Wolf
    int ret;
82 49381094 Kevin Wolf
83 49381094 Kevin Wolf
    ret = qcow2_cache_flush(bs, c->depends);
84 49381094 Kevin Wolf
    if (ret < 0) {
85 49381094 Kevin Wolf
        return ret;
86 49381094 Kevin Wolf
    }
87 49381094 Kevin Wolf
88 49381094 Kevin Wolf
    c->depends = NULL;
89 3de0a294 Kevin Wolf
    c->depends_on_flush = false;
90 3de0a294 Kevin Wolf
91 49381094 Kevin Wolf
    return 0;
92 49381094 Kevin Wolf
}
93 49381094 Kevin Wolf
94 49381094 Kevin Wolf
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
95 49381094 Kevin Wolf
{
96 49381094 Kevin Wolf
    BDRVQcowState *s = bs->opaque;
97 3de0a294 Kevin Wolf
    int ret = 0;
98 49381094 Kevin Wolf
99 49381094 Kevin Wolf
    if (!c->entries[i].dirty || !c->entries[i].offset) {
100 49381094 Kevin Wolf
        return 0;
101 49381094 Kevin Wolf
    }
102 49381094 Kevin Wolf
103 49381094 Kevin Wolf
    if (c->depends) {
104 49381094 Kevin Wolf
        ret = qcow2_cache_flush_dependency(bs, c);
105 3de0a294 Kevin Wolf
    } else if (c->depends_on_flush) {
106 3de0a294 Kevin Wolf
        ret = bdrv_flush(bs->file);
107 3de0a294 Kevin Wolf
        if (ret >= 0) {
108 3de0a294 Kevin Wolf
            c->depends_on_flush = false;
109 49381094 Kevin Wolf
        }
110 49381094 Kevin Wolf
    }
111 49381094 Kevin Wolf
112 3de0a294 Kevin Wolf
    if (ret < 0) {
113 3de0a294 Kevin Wolf
        return ret;
114 3de0a294 Kevin Wolf
    }
115 3de0a294 Kevin Wolf
116 29c1a730 Kevin Wolf
    if (c == s->refcount_block_cache) {
117 29c1a730 Kevin Wolf
        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
118 29c1a730 Kevin Wolf
    } else if (c == s->l2_table_cache) {
119 29c1a730 Kevin Wolf
        BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
120 29c1a730 Kevin Wolf
    }
121 29c1a730 Kevin Wolf
122 49381094 Kevin Wolf
    ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
123 49381094 Kevin Wolf
        s->cluster_size);
124 49381094 Kevin Wolf
    if (ret < 0) {
125 49381094 Kevin Wolf
        return ret;
126 49381094 Kevin Wolf
    }
127 49381094 Kevin Wolf
128 49381094 Kevin Wolf
    c->entries[i].dirty = false;
129 49381094 Kevin Wolf
130 49381094 Kevin Wolf
    return 0;
131 49381094 Kevin Wolf
}
132 49381094 Kevin Wolf
133 49381094 Kevin Wolf
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
134 49381094 Kevin Wolf
{
135 49381094 Kevin Wolf
    int result = 0;
136 49381094 Kevin Wolf
    int ret;
137 49381094 Kevin Wolf
    int i;
138 49381094 Kevin Wolf
139 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
140 49381094 Kevin Wolf
        ret = qcow2_cache_entry_flush(bs, c, i);
141 49381094 Kevin Wolf
        if (ret < 0 && result != -ENOSPC) {
142 49381094 Kevin Wolf
            result = ret;
143 49381094 Kevin Wolf
        }
144 49381094 Kevin Wolf
    }
145 49381094 Kevin Wolf
146 49381094 Kevin Wolf
    if (result == 0) {
147 49381094 Kevin Wolf
        ret = bdrv_flush(bs->file);
148 49381094 Kevin Wolf
        if (ret < 0) {
149 49381094 Kevin Wolf
            result = ret;
150 49381094 Kevin Wolf
        }
151 49381094 Kevin Wolf
    }
152 49381094 Kevin Wolf
153 49381094 Kevin Wolf
    return result;
154 49381094 Kevin Wolf
}
155 49381094 Kevin Wolf
156 49381094 Kevin Wolf
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
157 49381094 Kevin Wolf
    Qcow2Cache *dependency)
158 49381094 Kevin Wolf
{
159 49381094 Kevin Wolf
    int ret;
160 49381094 Kevin Wolf
161 49381094 Kevin Wolf
    if (dependency->depends) {
162 49381094 Kevin Wolf
        ret = qcow2_cache_flush_dependency(bs, dependency);
163 49381094 Kevin Wolf
        if (ret < 0) {
164 49381094 Kevin Wolf
            return ret;
165 49381094 Kevin Wolf
        }
166 49381094 Kevin Wolf
    }
167 49381094 Kevin Wolf
168 49381094 Kevin Wolf
    if (c->depends && (c->depends != dependency)) {
169 49381094 Kevin Wolf
        ret = qcow2_cache_flush_dependency(bs, c);
170 49381094 Kevin Wolf
        if (ret < 0) {
171 49381094 Kevin Wolf
            return ret;
172 49381094 Kevin Wolf
        }
173 49381094 Kevin Wolf
    }
174 49381094 Kevin Wolf
175 49381094 Kevin Wolf
    c->depends = dependency;
176 49381094 Kevin Wolf
    return 0;
177 49381094 Kevin Wolf
}
178 49381094 Kevin Wolf
179 3de0a294 Kevin Wolf
void qcow2_cache_depends_on_flush(Qcow2Cache *c)
180 3de0a294 Kevin Wolf
{
181 3de0a294 Kevin Wolf
    c->depends_on_flush = true;
182 3de0a294 Kevin Wolf
}
183 3de0a294 Kevin Wolf
184 49381094 Kevin Wolf
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
185 49381094 Kevin Wolf
{
186 49381094 Kevin Wolf
    int i;
187 49381094 Kevin Wolf
    int min_count = INT_MAX;
188 49381094 Kevin Wolf
    int min_index = -1;
189 49381094 Kevin Wolf
190 49381094 Kevin Wolf
191 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
192 49381094 Kevin Wolf
        if (c->entries[i].ref) {
193 49381094 Kevin Wolf
            continue;
194 49381094 Kevin Wolf
        }
195 49381094 Kevin Wolf
196 49381094 Kevin Wolf
        if (c->entries[i].cache_hits < min_count) {
197 49381094 Kevin Wolf
            min_index = i;
198 49381094 Kevin Wolf
            min_count = c->entries[i].cache_hits;
199 49381094 Kevin Wolf
        }
200 49381094 Kevin Wolf
201 49381094 Kevin Wolf
        /* Give newer hits priority */
202 49381094 Kevin Wolf
        /* TODO Check how to optimize the replacement strategy */
203 49381094 Kevin Wolf
        c->entries[i].cache_hits /= 2;
204 49381094 Kevin Wolf
    }
205 49381094 Kevin Wolf
206 49381094 Kevin Wolf
    if (min_index == -1) {
207 49381094 Kevin Wolf
        /* This can't happen in current synchronous code, but leave the check
208 49381094 Kevin Wolf
         * here as a reminder for whoever starts using AIO with the cache */
209 49381094 Kevin Wolf
        abort();
210 49381094 Kevin Wolf
    }
211 49381094 Kevin Wolf
    return min_index;
212 49381094 Kevin Wolf
}
213 49381094 Kevin Wolf
214 49381094 Kevin Wolf
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
215 49381094 Kevin Wolf
    uint64_t offset, void **table, bool read_from_disk)
216 49381094 Kevin Wolf
{
217 49381094 Kevin Wolf
    BDRVQcowState *s = bs->opaque;
218 49381094 Kevin Wolf
    int i;
219 49381094 Kevin Wolf
    int ret;
220 49381094 Kevin Wolf
221 49381094 Kevin Wolf
    /* Check if the table is already cached */
222 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
223 49381094 Kevin Wolf
        if (c->entries[i].offset == offset) {
224 49381094 Kevin Wolf
            goto found;
225 49381094 Kevin Wolf
        }
226 49381094 Kevin Wolf
    }
227 49381094 Kevin Wolf
228 49381094 Kevin Wolf
    /* If not, write a table back and replace it */
229 49381094 Kevin Wolf
    i = qcow2_cache_find_entry_to_replace(c);
230 49381094 Kevin Wolf
    if (i < 0) {
231 49381094 Kevin Wolf
        return i;
232 49381094 Kevin Wolf
    }
233 49381094 Kevin Wolf
234 49381094 Kevin Wolf
    ret = qcow2_cache_entry_flush(bs, c, i);
235 49381094 Kevin Wolf
    if (ret < 0) {
236 49381094 Kevin Wolf
        return ret;
237 49381094 Kevin Wolf
    }
238 49381094 Kevin Wolf
239 49381094 Kevin Wolf
    c->entries[i].offset = 0;
240 49381094 Kevin Wolf
    if (read_from_disk) {
241 29c1a730 Kevin Wolf
        if (c == s->l2_table_cache) {
242 29c1a730 Kevin Wolf
            BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
243 29c1a730 Kevin Wolf
        }
244 29c1a730 Kevin Wolf
245 49381094 Kevin Wolf
        ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
246 49381094 Kevin Wolf
        if (ret < 0) {
247 49381094 Kevin Wolf
            return ret;
248 49381094 Kevin Wolf
        }
249 49381094 Kevin Wolf
    }
250 49381094 Kevin Wolf
251 49381094 Kevin Wolf
    /* Give the table some hits for the start so that it won't be replaced
252 49381094 Kevin Wolf
     * immediately. The number 32 is completely arbitrary. */
253 49381094 Kevin Wolf
    c->entries[i].cache_hits = 32;
254 49381094 Kevin Wolf
    c->entries[i].offset = offset;
255 49381094 Kevin Wolf
256 49381094 Kevin Wolf
    /* And return the right table */
257 49381094 Kevin Wolf
found:
258 49381094 Kevin Wolf
    c->entries[i].cache_hits++;
259 49381094 Kevin Wolf
    c->entries[i].ref++;
260 49381094 Kevin Wolf
    *table = c->entries[i].table;
261 49381094 Kevin Wolf
    return 0;
262 49381094 Kevin Wolf
}
263 49381094 Kevin Wolf
264 49381094 Kevin Wolf
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
265 49381094 Kevin Wolf
    void **table)
266 49381094 Kevin Wolf
{
267 49381094 Kevin Wolf
    return qcow2_cache_do_get(bs, c, offset, table, true);
268 49381094 Kevin Wolf
}
269 49381094 Kevin Wolf
270 49381094 Kevin Wolf
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
271 49381094 Kevin Wolf
    void **table)
272 49381094 Kevin Wolf
{
273 49381094 Kevin Wolf
    return qcow2_cache_do_get(bs, c, offset, table, false);
274 49381094 Kevin Wolf
}
275 49381094 Kevin Wolf
276 49381094 Kevin Wolf
int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
277 49381094 Kevin Wolf
{
278 49381094 Kevin Wolf
    int i;
279 49381094 Kevin Wolf
280 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
281 49381094 Kevin Wolf
        if (c->entries[i].table == *table) {
282 49381094 Kevin Wolf
            goto found;
283 49381094 Kevin Wolf
        }
284 49381094 Kevin Wolf
    }
285 49381094 Kevin Wolf
    return -ENOENT;
286 49381094 Kevin Wolf
287 49381094 Kevin Wolf
found:
288 49381094 Kevin Wolf
    c->entries[i].ref--;
289 49381094 Kevin Wolf
    *table = NULL;
290 49381094 Kevin Wolf
291 49381094 Kevin Wolf
    assert(c->entries[i].ref >= 0);
292 49381094 Kevin Wolf
293 49381094 Kevin Wolf
    if (c->writethrough) {
294 49381094 Kevin Wolf
        return qcow2_cache_entry_flush(bs, c, i);
295 49381094 Kevin Wolf
    } else {
296 49381094 Kevin Wolf
        return 0;
297 49381094 Kevin Wolf
    }
298 49381094 Kevin Wolf
}
299 49381094 Kevin Wolf
300 49381094 Kevin Wolf
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
301 49381094 Kevin Wolf
{
302 49381094 Kevin Wolf
    int i;
303 49381094 Kevin Wolf
304 49381094 Kevin Wolf
    for (i = 0; i < c->size; i++) {
305 49381094 Kevin Wolf
        if (c->entries[i].table == table) {
306 49381094 Kevin Wolf
            goto found;
307 49381094 Kevin Wolf
        }
308 49381094 Kevin Wolf
    }
309 49381094 Kevin Wolf
    abort();
310 49381094 Kevin Wolf
311 49381094 Kevin Wolf
found:
312 49381094 Kevin Wolf
    c->entries[i].dirty = true;
313 49381094 Kevin Wolf
}