X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=page_cache.c;h=5f8578736e041b32774ad23aa69d31b9e30194a1;hb=b8dc35b2526278296390fffa80b5c82573ed178a;hp=ba5640bd73120314f81f2014de5ffb8247cdb0cc;hpb=34daffa04886444dafd4a6951167225e824003d0;p=mirror_qemu.git diff --git a/page_cache.c b/page_cache.c index ba5640bd73..5f8578736e 100644 --- a/page_cache.c +++ b/page_cache.c @@ -12,18 +12,10 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/host-utils.h" #include "migration/page_cache.h" #ifdef DEBUG_CACHE @@ -34,6 +26,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 +56,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 +74,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,28 +105,14 @@ 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, uint64_t address) { - size_t pos; - g_assert(cache->max_num_items); - pos = (address / cache->page_size) & (cache->max_num_items - 1); - 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); + return (address / cache->page_size) & (cache->max_num_items - 1); } static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) @@ -141,24 +132,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); + 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 = pdata; - 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) @@ -192,22 +210,22 @@ int64_t cache_resize(PageCache *cache, int64_t new_num_pages) if (old_it->it_addr != -1) { /* check for collision, if there is, keep MRU page */ new_it = cache_get_by_addr(new_cache, old_it->it_addr); - if (new_it->it_data) { + if (new_it->it_data && new_it->it_age >= old_it->it_age) { /* keep the MRU page */ - if (new_it->it_age >= old_it->it_age) { - g_free(old_it->it_data); - } else { - g_free(new_it->it_data); - new_it->it_data = old_it->it_data; - new_it->it_age = old_it->it_age; - new_it->it_addr = old_it->it_addr; - } + g_free(old_it->it_data); } else { - cache_insert(new_cache, old_it->it_addr, old_it->it_data); + if (!new_it->it_data) { + new_cache->num_items++; + } + g_free(new_it->it_data); + new_it->it_data = old_it->it_data; + new_it->it_age = old_it->it_age; + new_it->it_addr = old_it->it_addr; } } } + g_free(cache->page_cache); cache->page_cache = new_cache->page_cache; cache->max_num_items = new_cache->max_num_items; cache->num_items = new_cache->num_items;