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