xref: /qemu/block/qcow2-cache.c (revision 80c71a24)
149381094SKevin Wolf /*
249381094SKevin Wolf  * L2/refcount table cache for the QCOW2 format
349381094SKevin Wolf  *
449381094SKevin Wolf  * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
549381094SKevin Wolf  *
649381094SKevin Wolf  * Permission is hereby granted, free of charge, to any person obtaining a copy
749381094SKevin Wolf  * of this software and associated documentation files (the "Software"), to deal
849381094SKevin Wolf  * in the Software without restriction, including without limitation the rights
949381094SKevin Wolf  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049381094SKevin Wolf  * copies of the Software, and to permit persons to whom the Software is
1149381094SKevin Wolf  * furnished to do so, subject to the following conditions:
1249381094SKevin Wolf  *
1349381094SKevin Wolf  * The above copyright notice and this permission notice shall be included in
1449381094SKevin Wolf  * all copies or substantial portions of the Software.
1549381094SKevin Wolf  *
1649381094SKevin Wolf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749381094SKevin Wolf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849381094SKevin Wolf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949381094SKevin Wolf  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049381094SKevin Wolf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149381094SKevin Wolf  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249381094SKevin Wolf  * THE SOFTWARE.
2349381094SKevin Wolf  */
2449381094SKevin Wolf 
25355ee2d0SAlberto Garcia /* Needed for CONFIG_MADVISE */
26*80c71a24SPeter Maydell #include "qemu/osdep.h"
27355ee2d0SAlberto Garcia 
28355ee2d0SAlberto Garcia #if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
29355ee2d0SAlberto Garcia #include <sys/mman.h>
30355ee2d0SAlberto Garcia #endif
31355ee2d0SAlberto Garcia 
32737e150eSPaolo Bonzini #include "block/block_int.h"
3349381094SKevin Wolf #include "qemu-common.h"
3449381094SKevin Wolf #include "qcow2.h"
353cce16f4SKevin Wolf #include "trace.h"
3649381094SKevin Wolf 
3749381094SKevin Wolf typedef struct Qcow2CachedTable {
3849381094SKevin Wolf     int64_t  offset;
392693310eSAlberto Garcia     uint64_t lru_counter;
4049381094SKevin Wolf     int      ref;
41909c260cSAlberto Garcia     bool     dirty;
4249381094SKevin Wolf } Qcow2CachedTable;
4349381094SKevin Wolf 
4449381094SKevin Wolf struct Qcow2Cache {
4549381094SKevin Wolf     Qcow2CachedTable       *entries;
4649381094SKevin Wolf     struct Qcow2Cache      *depends;
47bf595021SJes Sorensen     int                     size;
483de0a294SKevin Wolf     bool                    depends_on_flush;
4972e80b89SAlberto Garcia     void                   *table_array;
502693310eSAlberto Garcia     uint64_t                lru_counter;
51279621c0SAlberto Garcia     uint64_t                cache_clean_lru_counter;
5249381094SKevin Wolf };
5349381094SKevin Wolf 
5472e80b89SAlberto Garcia static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
5572e80b89SAlberto Garcia                     Qcow2Cache *c, int table)
5672e80b89SAlberto Garcia {
57ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
5872e80b89SAlberto Garcia     return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
5972e80b89SAlberto Garcia }
6072e80b89SAlberto Garcia 
61baf07d60SAlberto Garcia static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
62baf07d60SAlberto Garcia                   Qcow2Cache *c, void *table)
63baf07d60SAlberto Garcia {
64ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
65baf07d60SAlberto Garcia     ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
66baf07d60SAlberto Garcia     int idx = table_offset / s->cluster_size;
67baf07d60SAlberto Garcia     assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
68baf07d60SAlberto Garcia     return idx;
69baf07d60SAlberto Garcia }
70baf07d60SAlberto Garcia 
71355ee2d0SAlberto Garcia static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
72355ee2d0SAlberto Garcia                                       int i, int num_tables)
73355ee2d0SAlberto Garcia {
74355ee2d0SAlberto Garcia #if QEMU_MADV_DONTNEED != QEMU_MADV_INVALID
75ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
76355ee2d0SAlberto Garcia     void *t = qcow2_cache_get_table_addr(bs, c, i);
77355ee2d0SAlberto Garcia     int align = getpagesize();
78355ee2d0SAlberto Garcia     size_t mem_size = (size_t) s->cluster_size * num_tables;
79355ee2d0SAlberto Garcia     size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
80355ee2d0SAlberto Garcia     size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
81355ee2d0SAlberto Garcia     if (length > 0) {
82355ee2d0SAlberto Garcia         qemu_madvise((uint8_t *) t + offset, length, QEMU_MADV_DONTNEED);
83355ee2d0SAlberto Garcia     }
84355ee2d0SAlberto Garcia #endif
85355ee2d0SAlberto Garcia }
86355ee2d0SAlberto Garcia 
87279621c0SAlberto Garcia static inline bool can_clean_entry(Qcow2Cache *c, int i)
88279621c0SAlberto Garcia {
89279621c0SAlberto Garcia     Qcow2CachedTable *t = &c->entries[i];
90279621c0SAlberto Garcia     return t->ref == 0 && !t->dirty && t->offset != 0 &&
91279621c0SAlberto Garcia         t->lru_counter <= c->cache_clean_lru_counter;
92279621c0SAlberto Garcia }
93279621c0SAlberto Garcia 
94279621c0SAlberto Garcia void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
95279621c0SAlberto Garcia {
96279621c0SAlberto Garcia     int i = 0;
97279621c0SAlberto Garcia     while (i < c->size) {
98279621c0SAlberto Garcia         int to_clean = 0;
99279621c0SAlberto Garcia 
100279621c0SAlberto Garcia         /* Skip the entries that we don't need to clean */
101279621c0SAlberto Garcia         while (i < c->size && !can_clean_entry(c, i)) {
102279621c0SAlberto Garcia             i++;
103279621c0SAlberto Garcia         }
104279621c0SAlberto Garcia 
105279621c0SAlberto Garcia         /* And count how many we can clean in a row */
106279621c0SAlberto Garcia         while (i < c->size && can_clean_entry(c, i)) {
107279621c0SAlberto Garcia             c->entries[i].offset = 0;
108279621c0SAlberto Garcia             c->entries[i].lru_counter = 0;
109279621c0SAlberto Garcia             i++;
110279621c0SAlberto Garcia             to_clean++;
111279621c0SAlberto Garcia         }
112279621c0SAlberto Garcia 
113279621c0SAlberto Garcia         if (to_clean > 0) {
114279621c0SAlberto Garcia             qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
115279621c0SAlberto Garcia         }
116279621c0SAlberto Garcia     }
117279621c0SAlberto Garcia 
118279621c0SAlberto Garcia     c->cache_clean_lru_counter = c->lru_counter;
119279621c0SAlberto Garcia }
120279621c0SAlberto Garcia 
1216af4e9eaSPaolo Bonzini Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
12249381094SKevin Wolf {
123ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
12449381094SKevin Wolf     Qcow2Cache *c;
12549381094SKevin Wolf 
12602004bd4SMax Reitz     c = g_new0(Qcow2Cache, 1);
12749381094SKevin Wolf     c->size = num_tables;
12802004bd4SMax Reitz     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
1299a4f4c31SKevin Wolf     c->table_array = qemu_try_blockalign(bs->file->bs,
13072e80b89SAlberto Garcia                                          (size_t) num_tables * s->cluster_size);
13149381094SKevin Wolf 
13272e80b89SAlberto Garcia     if (!c->entries || !c->table_array) {
13372e80b89SAlberto Garcia         qemu_vfree(c->table_array);
13472e80b89SAlberto Garcia         g_free(c->entries);
13572e80b89SAlberto Garcia         g_free(c);
13672e80b89SAlberto Garcia         c = NULL;
13749381094SKevin Wolf     }
13849381094SKevin Wolf 
13949381094SKevin Wolf     return c;
14049381094SKevin Wolf }
14149381094SKevin Wolf 
14249381094SKevin Wolf int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
14349381094SKevin Wolf {
14449381094SKevin Wolf     int i;
14549381094SKevin Wolf 
14649381094SKevin Wolf     for (i = 0; i < c->size; i++) {
14749381094SKevin Wolf         assert(c->entries[i].ref == 0);
14849381094SKevin Wolf     }
14949381094SKevin Wolf 
15072e80b89SAlberto Garcia     qemu_vfree(c->table_array);
1517267c094SAnthony Liguori     g_free(c->entries);
1527267c094SAnthony Liguori     g_free(c);
15349381094SKevin Wolf 
15449381094SKevin Wolf     return 0;
15549381094SKevin Wolf }
15649381094SKevin Wolf 
15749381094SKevin Wolf static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
15849381094SKevin Wolf {
15949381094SKevin Wolf     int ret;
16049381094SKevin Wolf 
16149381094SKevin Wolf     ret = qcow2_cache_flush(bs, c->depends);
16249381094SKevin Wolf     if (ret < 0) {
16349381094SKevin Wolf         return ret;
16449381094SKevin Wolf     }
16549381094SKevin Wolf 
16649381094SKevin Wolf     c->depends = NULL;
1673de0a294SKevin Wolf     c->depends_on_flush = false;
1683de0a294SKevin Wolf 
16949381094SKevin Wolf     return 0;
17049381094SKevin Wolf }
17149381094SKevin Wolf 
17249381094SKevin Wolf static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
17349381094SKevin Wolf {
174ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
1753de0a294SKevin Wolf     int ret = 0;
17649381094SKevin Wolf 
17749381094SKevin Wolf     if (!c->entries[i].dirty || !c->entries[i].offset) {
17849381094SKevin Wolf         return 0;
17949381094SKevin Wolf     }
18049381094SKevin Wolf 
1813cce16f4SKevin Wolf     trace_qcow2_cache_entry_flush(qemu_coroutine_self(),
1823cce16f4SKevin Wolf                                   c == s->l2_table_cache, i);
1833cce16f4SKevin Wolf 
18449381094SKevin Wolf     if (c->depends) {
18549381094SKevin Wolf         ret = qcow2_cache_flush_dependency(bs, c);
1863de0a294SKevin Wolf     } else if (c->depends_on_flush) {
1879a4f4c31SKevin Wolf         ret = bdrv_flush(bs->file->bs);
1883de0a294SKevin Wolf         if (ret >= 0) {
1893de0a294SKevin Wolf             c->depends_on_flush = false;
1903de0a294SKevin Wolf         }
1913de0a294SKevin Wolf     }
1923de0a294SKevin Wolf 
19349381094SKevin Wolf     if (ret < 0) {
19449381094SKevin Wolf         return ret;
19549381094SKevin Wolf     }
19649381094SKevin Wolf 
19729c1a730SKevin Wolf     if (c == s->refcount_block_cache) {
198231bb267SMax Reitz         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
199cf93980eSMax Reitz                 c->entries[i].offset, s->cluster_size);
200cf93980eSMax Reitz     } else if (c == s->l2_table_cache) {
201231bb267SMax Reitz         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
202cf93980eSMax Reitz                 c->entries[i].offset, s->cluster_size);
203cf93980eSMax Reitz     } else {
204231bb267SMax Reitz         ret = qcow2_pre_write_overlap_check(bs, 0,
205cf93980eSMax Reitz                 c->entries[i].offset, s->cluster_size);
206cf93980eSMax Reitz     }
207cf93980eSMax Reitz 
208cf93980eSMax Reitz     if (ret < 0) {
209cf93980eSMax Reitz         return ret;
210cf93980eSMax Reitz     }
211cf93980eSMax Reitz 
212cf93980eSMax Reitz     if (c == s->refcount_block_cache) {
21329c1a730SKevin Wolf         BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
21429c1a730SKevin Wolf     } else if (c == s->l2_table_cache) {
21529c1a730SKevin Wolf         BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
21629c1a730SKevin Wolf     }
21729c1a730SKevin Wolf 
2189a4f4c31SKevin Wolf     ret = bdrv_pwrite(bs->file->bs, c->entries[i].offset,
21972e80b89SAlberto Garcia                       qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
22049381094SKevin Wolf     if (ret < 0) {
22149381094SKevin Wolf         return ret;
22249381094SKevin Wolf     }
22349381094SKevin Wolf 
22449381094SKevin Wolf     c->entries[i].dirty = false;
22549381094SKevin Wolf 
22649381094SKevin Wolf     return 0;
22749381094SKevin Wolf }
22849381094SKevin Wolf 
22949381094SKevin Wolf int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
23049381094SKevin Wolf {
231ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
23249381094SKevin Wolf     int result = 0;
23349381094SKevin Wolf     int ret;
23449381094SKevin Wolf     int i;
23549381094SKevin Wolf 
2363cce16f4SKevin Wolf     trace_qcow2_cache_flush(qemu_coroutine_self(), c == s->l2_table_cache);
2373cce16f4SKevin Wolf 
23849381094SKevin Wolf     for (i = 0; i < c->size; i++) {
23949381094SKevin Wolf         ret = qcow2_cache_entry_flush(bs, c, i);
24049381094SKevin Wolf         if (ret < 0 && result != -ENOSPC) {
24149381094SKevin Wolf             result = ret;
24249381094SKevin Wolf         }
24349381094SKevin Wolf     }
24449381094SKevin Wolf 
24549381094SKevin Wolf     if (result == 0) {
2469a4f4c31SKevin Wolf         ret = bdrv_flush(bs->file->bs);
24749381094SKevin Wolf         if (ret < 0) {
24849381094SKevin Wolf             result = ret;
24949381094SKevin Wolf         }
25049381094SKevin Wolf     }
25149381094SKevin Wolf 
25249381094SKevin Wolf     return result;
25349381094SKevin Wolf }
25449381094SKevin Wolf 
25549381094SKevin Wolf int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
25649381094SKevin Wolf     Qcow2Cache *dependency)
25749381094SKevin Wolf {
25849381094SKevin Wolf     int ret;
25949381094SKevin Wolf 
26049381094SKevin Wolf     if (dependency->depends) {
26149381094SKevin Wolf         ret = qcow2_cache_flush_dependency(bs, dependency);
26249381094SKevin Wolf         if (ret < 0) {
26349381094SKevin Wolf             return ret;
26449381094SKevin Wolf         }
26549381094SKevin Wolf     }
26649381094SKevin Wolf 
26749381094SKevin Wolf     if (c->depends && (c->depends != dependency)) {
26849381094SKevin Wolf         ret = qcow2_cache_flush_dependency(bs, c);
26949381094SKevin Wolf         if (ret < 0) {
27049381094SKevin Wolf             return ret;
27149381094SKevin Wolf         }
27249381094SKevin Wolf     }
27349381094SKevin Wolf 
27449381094SKevin Wolf     c->depends = dependency;
27549381094SKevin Wolf     return 0;
27649381094SKevin Wolf }
27749381094SKevin Wolf 
2783de0a294SKevin Wolf void qcow2_cache_depends_on_flush(Qcow2Cache *c)
2793de0a294SKevin Wolf {
2803de0a294SKevin Wolf     c->depends_on_flush = true;
2813de0a294SKevin Wolf }
2823de0a294SKevin Wolf 
283e7108feaSMax Reitz int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
284e7108feaSMax Reitz {
285e7108feaSMax Reitz     int ret, i;
286e7108feaSMax Reitz 
287e7108feaSMax Reitz     ret = qcow2_cache_flush(bs, c);
288e7108feaSMax Reitz     if (ret < 0) {
289e7108feaSMax Reitz         return ret;
290e7108feaSMax Reitz     }
291e7108feaSMax Reitz 
292e7108feaSMax Reitz     for (i = 0; i < c->size; i++) {
293e7108feaSMax Reitz         assert(c->entries[i].ref == 0);
294e7108feaSMax Reitz         c->entries[i].offset = 0;
2952693310eSAlberto Garcia         c->entries[i].lru_counter = 0;
296e7108feaSMax Reitz     }
297e7108feaSMax Reitz 
298355ee2d0SAlberto Garcia     qcow2_cache_table_release(bs, c, 0, c->size);
299355ee2d0SAlberto Garcia 
3002693310eSAlberto Garcia     c->lru_counter = 0;
3012693310eSAlberto Garcia 
302e7108feaSMax Reitz     return 0;
303e7108feaSMax Reitz }
304e7108feaSMax Reitz 
30549381094SKevin Wolf static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
30649381094SKevin Wolf     uint64_t offset, void **table, bool read_from_disk)
30749381094SKevin Wolf {
308ff99129aSKevin Wolf     BDRVQcow2State *s = bs->opaque;
30949381094SKevin Wolf     int i;
31049381094SKevin Wolf     int ret;
311812e4082SAlberto Garcia     int lookup_index;
312fdfbca82SAlberto Garcia     uint64_t min_lru_counter = UINT64_MAX;
313fdfbca82SAlberto Garcia     int min_lru_index = -1;
31449381094SKevin Wolf 
3153cce16f4SKevin Wolf     trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
3163cce16f4SKevin Wolf                           offset, read_from_disk);
3173cce16f4SKevin Wolf 
31849381094SKevin Wolf     /* Check if the table is already cached */
319812e4082SAlberto Garcia     i = lookup_index = (offset / s->cluster_size * 4) % c->size;
320812e4082SAlberto Garcia     do {
321fdfbca82SAlberto Garcia         const Qcow2CachedTable *t = &c->entries[i];
322fdfbca82SAlberto Garcia         if (t->offset == offset) {
32349381094SKevin Wolf             goto found;
32449381094SKevin Wolf         }
325fdfbca82SAlberto Garcia         if (t->ref == 0 && t->lru_counter < min_lru_counter) {
326fdfbca82SAlberto Garcia             min_lru_counter = t->lru_counter;
327fdfbca82SAlberto Garcia             min_lru_index = i;
328fdfbca82SAlberto Garcia         }
329812e4082SAlberto Garcia         if (++i == c->size) {
330812e4082SAlberto Garcia             i = 0;
33149381094SKevin Wolf         }
332812e4082SAlberto Garcia     } while (i != lookup_index);
33349381094SKevin Wolf 
334fdfbca82SAlberto Garcia     if (min_lru_index == -1) {
335fdfbca82SAlberto Garcia         /* This can't happen in current synchronous code, but leave the check
336fdfbca82SAlberto Garcia          * here as a reminder for whoever starts using AIO with the cache */
337fdfbca82SAlberto Garcia         abort();
338fdfbca82SAlberto Garcia     }
339fdfbca82SAlberto Garcia 
340fdfbca82SAlberto Garcia     /* Cache miss: write a table back and replace it */
341fdfbca82SAlberto Garcia     i = min_lru_index;
3423cce16f4SKevin Wolf     trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
3433cce16f4SKevin Wolf                                         c == s->l2_table_cache, i);
34449381094SKevin Wolf 
34549381094SKevin Wolf     ret = qcow2_cache_entry_flush(bs, c, i);
34649381094SKevin Wolf     if (ret < 0) {
34749381094SKevin Wolf         return ret;
34849381094SKevin Wolf     }
34949381094SKevin Wolf 
3503cce16f4SKevin Wolf     trace_qcow2_cache_get_read(qemu_coroutine_self(),
3513cce16f4SKevin Wolf                                c == s->l2_table_cache, i);
35249381094SKevin Wolf     c->entries[i].offset = 0;
35349381094SKevin Wolf     if (read_from_disk) {
35429c1a730SKevin Wolf         if (c == s->l2_table_cache) {
35529c1a730SKevin Wolf             BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
35629c1a730SKevin Wolf         }
35729c1a730SKevin Wolf 
3589a4f4c31SKevin Wolf         ret = bdrv_pread(bs->file->bs, offset,
3599a4f4c31SKevin Wolf                          qcow2_cache_get_table_addr(bs, c, i),
36072e80b89SAlberto Garcia                          s->cluster_size);
36149381094SKevin Wolf         if (ret < 0) {
36249381094SKevin Wolf             return ret;
36349381094SKevin Wolf         }
36449381094SKevin Wolf     }
36549381094SKevin Wolf 
36649381094SKevin Wolf     c->entries[i].offset = offset;
36749381094SKevin Wolf 
36849381094SKevin Wolf     /* And return the right table */
36949381094SKevin Wolf found:
37049381094SKevin Wolf     c->entries[i].ref++;
37172e80b89SAlberto Garcia     *table = qcow2_cache_get_table_addr(bs, c, i);
3723cce16f4SKevin Wolf 
3733cce16f4SKevin Wolf     trace_qcow2_cache_get_done(qemu_coroutine_self(),
3743cce16f4SKevin Wolf                                c == s->l2_table_cache, i);
3753cce16f4SKevin Wolf 
37649381094SKevin Wolf     return 0;
37749381094SKevin Wolf }
37849381094SKevin Wolf 
37949381094SKevin Wolf int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
38049381094SKevin Wolf     void **table)
38149381094SKevin Wolf {
38249381094SKevin Wolf     return qcow2_cache_do_get(bs, c, offset, table, true);
38349381094SKevin Wolf }
38449381094SKevin Wolf 
38549381094SKevin Wolf int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
38649381094SKevin Wolf     void **table)
38749381094SKevin Wolf {
38849381094SKevin Wolf     return qcow2_cache_do_get(bs, c, offset, table, false);
38949381094SKevin Wolf }
39049381094SKevin Wolf 
391a3f1afb4SAlberto Garcia void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
39249381094SKevin Wolf {
393baf07d60SAlberto Garcia     int i = qcow2_cache_get_table_idx(bs, c, *table);
39449381094SKevin Wolf 
39549381094SKevin Wolf     c->entries[i].ref--;
39649381094SKevin Wolf     *table = NULL;
39749381094SKevin Wolf 
3982693310eSAlberto Garcia     if (c->entries[i].ref == 0) {
3992693310eSAlberto Garcia         c->entries[i].lru_counter = ++c->lru_counter;
4002693310eSAlberto Garcia     }
4012693310eSAlberto Garcia 
40249381094SKevin Wolf     assert(c->entries[i].ref >= 0);
40349381094SKevin Wolf }
40449381094SKevin Wolf 
40572e80b89SAlberto Garcia void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
40672e80b89SAlberto Garcia      void *table)
40749381094SKevin Wolf {
408baf07d60SAlberto Garcia     int i = qcow2_cache_get_table_idx(bs, c, table);
409baf07d60SAlberto Garcia     assert(c->entries[i].offset != 0);
41049381094SKevin Wolf     c->entries[i].dirty = true;
41149381094SKevin Wolf }
412