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 | } |