X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/fe3cc14fd83e0c8f376d849ccd0fc3433388442d..9fbe302b2a4c349c1a8fa93a3f79f08e7007d80c:/page_cache.c diff --git a/page_cache.c b/page_cache.c index 938a79c9ea..cf8878d1d7 100644 --- a/page_cache.c +++ b/page_cache.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "qemu-common.h" #include "migration/page_cache.h" @@ -34,6 +33,9 @@ do { } while (0) #endif +/* the page in cache will not be replaced in two cycles */ +#define CACHED_PAGE_LIFETIME 2 + typedef struct CacheItem CacheItem; struct CacheItem { @@ -61,8 +63,12 @@ PageCache *cache_init(int64_t num_pages, unsigned int page_size) return NULL; } - cache = g_malloc(sizeof(*cache)); - + /* We prefer not to abort if there is no memory */ + cache = g_try_malloc(sizeof(*cache)); + if (!cache) { + DPRINTF("Failed to allocate cache\n"); + return NULL; + } /* round down to the nearest power of 2 */ if (!is_power_of_2(num_pages)) { num_pages = pow2floor(num_pages); @@ -75,8 +81,14 @@ PageCache *cache_init(int64_t num_pages, unsigned int page_size) DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items); - cache->page_cache = g_malloc((cache->max_num_items) * - sizeof(*cache->page_cache)); + /* We prefer not to abort if there is no memory */ + cache->page_cache = g_try_malloc((cache->max_num_items) * + sizeof(*cache->page_cache)); + if (!cache->page_cache) { + DPRINTF("Failed to allocate cache->page_cache\n"); + g_free(cache); + return NULL; + } for (i = 0; i < cache->max_num_items; i++) { cache->page_cache[i].it_data = NULL; @@ -100,6 +112,7 @@ void cache_fini(PageCache *cache) g_free(cache->page_cache); cache->page_cache = NULL; + g_free(cache); } static size_t cache_get_cache_pos(const PageCache *cache, @@ -112,18 +125,6 @@ static size_t cache_get_cache_pos(const PageCache *cache, return pos; } -bool cache_is_cached(const PageCache *cache, uint64_t addr) -{ - size_t pos; - - g_assert(cache); - g_assert(cache->page_cache); - - pos = cache_get_cache_pos(cache, addr); - - return (cache->page_cache[pos].it_addr == addr); -} - static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) { size_t pos; @@ -141,27 +142,51 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr) return cache_get_by_addr(cache, addr)->it_data; } -void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata) +bool cache_is_cached(const PageCache *cache, uint64_t addr, + uint64_t current_age) { + CacheItem *it; - CacheItem *it = NULL; + it = cache_get_by_addr(cache, addr); - g_assert(cache); - g_assert(cache->page_cache); + if (it->it_addr == addr) { + /* update the it_age when the cache hit */ + it->it_age = current_age; + return true; + } + return false; +} + +int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, + uint64_t current_age) +{ + + CacheItem *it; /* actual update of entry */ it = cache_get_by_addr(cache, addr); - /* free old cached data if any */ - g_free(it->it_data); - + if (it->it_data && it->it_addr != addr && + it->it_age + CACHED_PAGE_LIFETIME > current_age) { + /* the cache page is fresh, don't replace it */ + return -1; + } + /* allocate page */ if (!it->it_data) { + it->it_data = g_try_malloc(cache->page_size); + if (!it->it_data) { + DPRINTF("Error allocating page\n"); + return -1; + } cache->num_items++; } - it->it_data = g_memdup(pdata, cache->page_size); - it->it_age = ++cache->max_item_age; + memcpy(it->it_data, pdata, cache->page_size); + + it->it_age = current_age; it->it_addr = addr; + + return 0; } int64_t cache_resize(PageCache *cache, int64_t new_num_pages)