xref: /openbmc/qemu/block/qcow2-cache.c (revision 8e3b0cbb)
1 /*
2  * L2/refcount table cache for the QCOW2 format
3  *
4  * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include "qemu/memalign.h"
27 #include "qcow2.h"
28 #include "trace.h"
29 
30 typedef struct Qcow2CachedTable {
31     int64_t  offset;
32     uint64_t lru_counter;
33     int      ref;
34     bool     dirty;
35 } Qcow2CachedTable;
36 
37 struct Qcow2Cache {
38     Qcow2CachedTable       *entries;
39     struct Qcow2Cache      *depends;
40     int                     size;
41     int                     table_size;
42     bool                    depends_on_flush;
43     void                   *table_array;
44     uint64_t                lru_counter;
45     uint64_t                cache_clean_lru_counter;
46 };
47 
48 static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
49 {
50     return (uint8_t *) c->table_array + (size_t) table * c->table_size;
51 }
52 
53 static inline int qcow2_cache_get_table_idx(Qcow2Cache *c, void *table)
54 {
55     ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
56     int idx = table_offset / c->table_size;
57     assert(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
58     return idx;
59 }
60 
61 static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
62 {
63     if (c == s->refcount_block_cache) {
64         return "refcount block";
65     } else if (c == s->l2_table_cache) {
66         return "L2 table";
67     } else {
68         /* Do not abort, because this is not critical */
69         return "unknown";
70     }
71 }
72 
73 static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables)
74 {
75 /* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
76 #ifdef CONFIG_LINUX
77     void *t = qcow2_cache_get_table_addr(c, i);
78     int align = qemu_real_host_page_size();
79     size_t mem_size = (size_t) c->table_size * num_tables;
80     size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
81     size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
82     if (mem_size > offset && length > 0) {
83         madvise((uint8_t *) t + offset, length, MADV_DONTNEED);
84     }
85 #endif
86 }
87 
88 static inline bool can_clean_entry(Qcow2Cache *c, int i)
89 {
90     Qcow2CachedTable *t = &c->entries[i];
91     return t->ref == 0 && !t->dirty && t->offset != 0 &&
92         t->lru_counter <= c->cache_clean_lru_counter;
93 }
94 
95 void qcow2_cache_clean_unused(Qcow2Cache *c)
96 {
97     int i = 0;
98     while (i < c->size) {
99         int to_clean = 0;
100 
101         /* Skip the entries that we don't need to clean */
102         while (i < c->size && !can_clean_entry(c, i)) {
103             i++;
104         }
105 
106         /* And count how many we can clean in a row */
107         while (i < c->size && can_clean_entry(c, i)) {
108             c->entries[i].offset = 0;
109             c->entries[i].lru_counter = 0;
110             i++;
111             to_clean++;
112         }
113 
114         if (to_clean > 0) {
115             qcow2_cache_table_release(c, i - to_clean, to_clean);
116         }
117     }
118 
119     c->cache_clean_lru_counter = c->lru_counter;
120 }
121 
122 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
123                                unsigned table_size)
124 {
125     BDRVQcow2State *s = bs->opaque;
126     Qcow2Cache *c;
127 
128     assert(num_tables > 0);
129     assert(is_power_of_2(table_size));
130     assert(table_size >= (1 << MIN_CLUSTER_BITS));
131     assert(table_size <= s->cluster_size);
132 
133     c = g_new0(Qcow2Cache, 1);
134     c->size = num_tables;
135     c->table_size = table_size;
136     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
137     c->table_array = qemu_try_blockalign(bs->file->bs,
138                                          (size_t) num_tables * c->table_size);
139 
140     if (!c->entries || !c->table_array) {
141         qemu_vfree(c->table_array);
142         g_free(c->entries);
143         g_free(c);
144         c = NULL;
145     }
146 
147     return c;
148 }
149 
150 int qcow2_cache_destroy(Qcow2Cache *c)
151 {
152     int i;
153 
154     for (i = 0; i < c->size; i++) {
155         assert(c->entries[i].ref == 0);
156     }
157 
158     qemu_vfree(c->table_array);
159     g_free(c->entries);
160     g_free(c);
161 
162     return 0;
163 }
164 
165 static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
166 {
167     int ret;
168 
169     ret = qcow2_cache_flush(bs, c->depends);
170     if (ret < 0) {
171         return ret;
172     }
173 
174     c->depends = NULL;
175     c->depends_on_flush = false;
176 
177     return 0;
178 }
179 
180 static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
181 {
182     BDRVQcow2State *s = bs->opaque;
183     int ret = 0;
184 
185     if (!c->entries[i].dirty || !c->entries[i].offset) {
186         return 0;
187     }
188 
189     trace_qcow2_cache_entry_flush(qemu_coroutine_self(),
190                                   c == s->l2_table_cache, i);
191 
192     if (c->depends) {
193         ret = qcow2_cache_flush_dependency(bs, c);
194     } else if (c->depends_on_flush) {
195         ret = bdrv_flush(bs->file->bs);
196         if (ret >= 0) {
197             c->depends_on_flush = false;
198         }
199     }
200 
201     if (ret < 0) {
202         return ret;
203     }
204 
205     if (c == s->refcount_block_cache) {
206         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
207                 c->entries[i].offset, c->table_size, false);
208     } else if (c == s->l2_table_cache) {
209         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
210                 c->entries[i].offset, c->table_size, false);
211     } else {
212         ret = qcow2_pre_write_overlap_check(bs, 0,
213                 c->entries[i].offset, c->table_size, false);
214     }
215 
216     if (ret < 0) {
217         return ret;
218     }
219 
220     if (c == s->refcount_block_cache) {
221         BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
222     } else if (c == s->l2_table_cache) {
223         BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
224     }
225 
226     ret = bdrv_pwrite(bs->file, c->entries[i].offset,
227                       qcow2_cache_get_table_addr(c, i), c->table_size);
228     if (ret < 0) {
229         return ret;
230     }
231 
232     c->entries[i].dirty = false;
233 
234     return 0;
235 }
236 
237 int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c)
238 {
239     BDRVQcow2State *s = bs->opaque;
240     int result = 0;
241     int ret;
242     int i;
243 
244     trace_qcow2_cache_flush(qemu_coroutine_self(), c == s->l2_table_cache);
245 
246     for (i = 0; i < c->size; i++) {
247         ret = qcow2_cache_entry_flush(bs, c, i);
248         if (ret < 0 && result != -ENOSPC) {
249             result = ret;
250         }
251     }
252 
253     return result;
254 }
255 
256 int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
257 {
258     int result = qcow2_cache_write(bs, c);
259 
260     if (result == 0) {
261         int ret = bdrv_flush(bs->file->bs);
262         if (ret < 0) {
263             result = ret;
264         }
265     }
266 
267     return result;
268 }
269 
270 int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
271     Qcow2Cache *dependency)
272 {
273     int ret;
274 
275     if (dependency->depends) {
276         ret = qcow2_cache_flush_dependency(bs, dependency);
277         if (ret < 0) {
278             return ret;
279         }
280     }
281 
282     if (c->depends && (c->depends != dependency)) {
283         ret = qcow2_cache_flush_dependency(bs, c);
284         if (ret < 0) {
285             return ret;
286         }
287     }
288 
289     c->depends = dependency;
290     return 0;
291 }
292 
293 void qcow2_cache_depends_on_flush(Qcow2Cache *c)
294 {
295     c->depends_on_flush = true;
296 }
297 
298 int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
299 {
300     int ret, i;
301 
302     ret = qcow2_cache_flush(bs, c);
303     if (ret < 0) {
304         return ret;
305     }
306 
307     for (i = 0; i < c->size; i++) {
308         assert(c->entries[i].ref == 0);
309         c->entries[i].offset = 0;
310         c->entries[i].lru_counter = 0;
311     }
312 
313     qcow2_cache_table_release(c, 0, c->size);
314 
315     c->lru_counter = 0;
316 
317     return 0;
318 }
319 
320 static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
321     uint64_t offset, void **table, bool read_from_disk)
322 {
323     BDRVQcow2State *s = bs->opaque;
324     int i;
325     int ret;
326     int lookup_index;
327     uint64_t min_lru_counter = UINT64_MAX;
328     int min_lru_index = -1;
329 
330     assert(offset != 0);
331 
332     trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
333                           offset, read_from_disk);
334 
335     if (!QEMU_IS_ALIGNED(offset, c->table_size)) {
336         qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
337                                 "cache: Offset %#" PRIx64 " is unaligned",
338                                 qcow2_cache_get_name(s, c), offset);
339         return -EIO;
340     }
341 
342     /* Check if the table is already cached */
343     i = lookup_index = (offset / c->table_size * 4) % c->size;
344     do {
345         const Qcow2CachedTable *t = &c->entries[i];
346         if (t->offset == offset) {
347             goto found;
348         }
349         if (t->ref == 0 && t->lru_counter < min_lru_counter) {
350             min_lru_counter = t->lru_counter;
351             min_lru_index = i;
352         }
353         if (++i == c->size) {
354             i = 0;
355         }
356     } while (i != lookup_index);
357 
358     if (min_lru_index == -1) {
359         /* This can't happen in current synchronous code, but leave the check
360          * here as a reminder for whoever starts using AIO with the cache */
361         abort();
362     }
363 
364     /* Cache miss: write a table back and replace it */
365     i = min_lru_index;
366     trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
367                                         c == s->l2_table_cache, i);
368 
369     ret = qcow2_cache_entry_flush(bs, c, i);
370     if (ret < 0) {
371         return ret;
372     }
373 
374     trace_qcow2_cache_get_read(qemu_coroutine_self(),
375                                c == s->l2_table_cache, i);
376     c->entries[i].offset = 0;
377     if (read_from_disk) {
378         if (c == s->l2_table_cache) {
379             BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
380         }
381 
382         ret = bdrv_pread(bs->file, offset,
383                          qcow2_cache_get_table_addr(c, i),
384                          c->table_size);
385         if (ret < 0) {
386             return ret;
387         }
388     }
389 
390     c->entries[i].offset = offset;
391 
392     /* And return the right table */
393 found:
394     c->entries[i].ref++;
395     *table = qcow2_cache_get_table_addr(c, i);
396 
397     trace_qcow2_cache_get_done(qemu_coroutine_self(),
398                                c == s->l2_table_cache, i);
399 
400     return 0;
401 }
402 
403 int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
404     void **table)
405 {
406     return qcow2_cache_do_get(bs, c, offset, table, true);
407 }
408 
409 int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
410     void **table)
411 {
412     return qcow2_cache_do_get(bs, c, offset, table, false);
413 }
414 
415 void qcow2_cache_put(Qcow2Cache *c, void **table)
416 {
417     int i = qcow2_cache_get_table_idx(c, *table);
418 
419     c->entries[i].ref--;
420     *table = NULL;
421 
422     if (c->entries[i].ref == 0) {
423         c->entries[i].lru_counter = ++c->lru_counter;
424     }
425 
426     assert(c->entries[i].ref >= 0);
427 }
428 
429 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
430 {
431     int i = qcow2_cache_get_table_idx(c, table);
432     assert(c->entries[i].offset != 0);
433     c->entries[i].dirty = true;
434 }
435 
436 void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
437 {
438     int i;
439 
440     for (i = 0; i < c->size; i++) {
441         if (c->entries[i].offset == offset) {
442             return qcow2_cache_get_table_addr(c, i);
443         }
444     }
445     return NULL;
446 }
447 
448 void qcow2_cache_discard(Qcow2Cache *c, void *table)
449 {
450     int i = qcow2_cache_get_table_idx(c, table);
451 
452     assert(c->entries[i].ref == 0);
453 
454     c->entries[i].offset = 0;
455     c->entries[i].lru_counter = 0;
456     c->entries[i].dirty = false;
457 
458     qcow2_cache_table_release(c, i, 1);
459 }
460