mirror of https://github.com/xemu-project/xemu.git
A set of patches collected over the holidays. Mix of optimizations and
fixes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUuMDIAAoJEB6aO1+FQIO2RSEP/0QQvvRz9gv20VfGMvT6+tUQ NYcnJ1AAsykLD4upQax/hX8SLIoQ7dnHgBmuJK5GAxCTyxqrkjtQ1i/9ISqw1ZmG m+64RxNnENb4XWRKRt03YS/4JntB4o9UTEbxjKQb+KCslITzM4e1kf6NwUJK1exE vNibzt4vfbTrJrNeDbDpZg4zX6Gi+WPnXUyV6Fg4vsaW2lkfk8uCg7u6fu1VI8lG uQtfB4K8+DtlqjF2oqMD+a3NmDIKgHC3b25PBl02dJroNb2vTCNGxoO00xsynStR JeHOzApY0koWQIWzYfoCj5VEz5Dm1TkKxqOpWnN+Xh9PZiovLsM9JWMqCnujJHaa OS5nx7SueMBaz3qSxeV+8G3VI0x9l2R3aHOUP3VWS6mDb23HBXgbUNy5FihL4qKl hRhvkdA7VD05CS/x+4/tz3lrfzPMqeMbRBhnfxUhV1arZPQgc9PzNBJKF42u/eA4 H75xkPcn/HtQwZZY7tW9RN6o61OkDkWGtjAI4l5VXh9ARLUVVvR/AQJeXyiWklSQ ARqtqosXIUPUdMcAMjD8GA909cwZn+5yKci4VuK3+omStcuZioRrtarp2m0TfW5V F0f3BjTDMG1aXmhqBsPsMuAUHVrber1phrB6JjVK/adJ246v3MOqp1/woxaRzNrC mWJUBeOZwl1Ld+BMg4eX =xCqX -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/amit-migration/tags/mig-2.3-1' into staging A set of patches collected over the holidays. Mix of optimizations and fixes. # gpg: Signature made Fri 16 Jan 2015 07:42:00 GMT using RSA key ID 854083B6 # gpg: Good signature from "Amit Shah <amit@amitshah.net>" # gpg: aka "Amit Shah <amit@kernel.org>" # gpg: aka "Amit Shah <amitshah@gmx.net>" * remotes/amit-migration/tags/mig-2.3-1: vmstate: type-check sub-arrays migration_cancel: shutdown migration socket Handle bi-directional communication for fd migration socket shutdown Tests: QEMUSizedBuffer/QEMUBuffer QEMUSizedBuffer: only free qsb that qemu_bufopen allocated xbzrle: rebuild the cache_is_cached function xbzrle: optimize XBZRLE to decrease the cache misses Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e68cba3636
|
@ -346,7 +346,8 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
||||||
|
|
||||||
/* We don't care if this fails to allocate a new cache page
|
/* We don't care if this fails to allocate a new cache page
|
||||||
* as long as it updated an old one */
|
* as long as it updated an old one */
|
||||||
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE);
|
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE,
|
||||||
|
bitmap_sync_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENCODING_FLAG_XBZRLE 0x1
|
#define ENCODING_FLAG_XBZRLE 0x1
|
||||||
|
@ -358,10 +359,11 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||||
int encoded_len = 0, bytes_sent = -1;
|
int encoded_len = 0, bytes_sent = -1;
|
||||||
uint8_t *prev_cached_page;
|
uint8_t *prev_cached_page;
|
||||||
|
|
||||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
if (!cache_is_cached(XBZRLE.cache, current_addr, bitmap_sync_count)) {
|
||||||
acct_info.xbzrle_cache_miss++;
|
acct_info.xbzrle_cache_miss++;
|
||||||
if (!last_stage) {
|
if (!last_stage) {
|
||||||
if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) {
|
if (cache_insert(XBZRLE.cache, current_addr, *current_data,
|
||||||
|
bitmap_sync_count) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
/* update *current_data when the page has been
|
/* update *current_data when the page has been
|
||||||
|
|
|
@ -71,6 +71,14 @@ encoded buffer:
|
||||||
encoded length 24
|
encoded length 24
|
||||||
e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
|
e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
|
||||||
|
|
||||||
|
Cache update strategy
|
||||||
|
=====================
|
||||||
|
Keeping the hot pages in the cache is effective for decreased cache
|
||||||
|
misses. XBZRLE uses a counter as the age of each page. The counter will
|
||||||
|
increase after each ram dirty bitmap sync. When a cache conflict is
|
||||||
|
detected, XBZRLE will only evict pages in the cache that are older than
|
||||||
|
a threshold.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
======================
|
======================
|
||||||
1. Verify the destination QEMU version is able to decode the new format.
|
1. Verify the destination QEMU version is able to decode the new format.
|
||||||
|
|
|
@ -43,8 +43,10 @@ void cache_fini(PageCache *cache);
|
||||||
*
|
*
|
||||||
* @cache pointer to the PageCache struct
|
* @cache pointer to the PageCache struct
|
||||||
* @addr: page addr
|
* @addr: page addr
|
||||||
|
* @current_age: current bitmap generation
|
||||||
*/
|
*/
|
||||||
bool cache_is_cached(const PageCache *cache, uint64_t addr);
|
bool cache_is_cached(const PageCache *cache, uint64_t addr,
|
||||||
|
uint64_t current_age);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_cached_data: Get the data cached for an addr
|
* get_cached_data: Get the data cached for an addr
|
||||||
|
@ -60,13 +62,15 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr);
|
||||||
* cache_insert: insert the page into the cache. the page cache
|
* cache_insert: insert the page into the cache. the page cache
|
||||||
* will dup the data on insert. the previous value will be overwritten
|
* will dup the data on insert. the previous value will be overwritten
|
||||||
*
|
*
|
||||||
* Returns -1 on error
|
* Returns -1 when the page isn't inserted into cache
|
||||||
*
|
*
|
||||||
* @cache pointer to the PageCache struct
|
* @cache pointer to the PageCache struct
|
||||||
* @addr: page address
|
* @addr: page address
|
||||||
* @pdata: pointer to the page
|
* @pdata: pointer to the page
|
||||||
|
* @current_age: current bitmap generation
|
||||||
*/
|
*/
|
||||||
int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata);
|
int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata,
|
||||||
|
uint64_t current_age);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cache_resize: resize the page cache. In case of size reduction the extra
|
* cache_resize: resize the page cache. In case of size reduction the extra
|
||||||
|
|
|
@ -84,6 +84,14 @@ typedef size_t (QEMURamSaveFunc)(QEMUFile *f, void *opaque,
|
||||||
size_t size,
|
size_t size,
|
||||||
int *bytes_sent);
|
int *bytes_sent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop any read or write (depending on flags) on the underlying
|
||||||
|
* transport on the QEMUFile.
|
||||||
|
* Existing blocking reads/writes must be woken
|
||||||
|
* Returns 0 on success, -err on error
|
||||||
|
*/
|
||||||
|
typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
|
||||||
|
|
||||||
typedef struct QEMUFileOps {
|
typedef struct QEMUFileOps {
|
||||||
QEMUFilePutBufferFunc *put_buffer;
|
QEMUFilePutBufferFunc *put_buffer;
|
||||||
QEMUFileGetBufferFunc *get_buffer;
|
QEMUFileGetBufferFunc *get_buffer;
|
||||||
|
@ -94,6 +102,7 @@ typedef struct QEMUFileOps {
|
||||||
QEMURamHookFunc *after_ram_iterate;
|
QEMURamHookFunc *after_ram_iterate;
|
||||||
QEMURamHookFunc *hook_ram_load;
|
QEMURamHookFunc *hook_ram_load;
|
||||||
QEMURamSaveFunc *save_page;
|
QEMURamSaveFunc *save_page;
|
||||||
|
QEMUFileShutdownFunc *shut_down;
|
||||||
} QEMUFileOps;
|
} QEMUFileOps;
|
||||||
|
|
||||||
struct QEMUSizedBuffer {
|
struct QEMUSizedBuffer {
|
||||||
|
@ -177,6 +186,7 @@ void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
|
||||||
int64_t qemu_file_get_rate_limit(QEMUFile *f);
|
int64_t qemu_file_get_rate_limit(QEMUFile *f);
|
||||||
int qemu_file_get_error(QEMUFile *f);
|
int qemu_file_get_error(QEMUFile *f);
|
||||||
void qemu_file_set_error(QEMUFile *f, int ret);
|
void qemu_file_set_error(QEMUFile *f, int ret);
|
||||||
|
int qemu_file_shutdown(QEMUFile *f);
|
||||||
void qemu_fflush(QEMUFile *f);
|
void qemu_fflush(QEMUFile *f);
|
||||||
|
|
||||||
static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
|
static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
|
||||||
|
|
|
@ -189,7 +189,7 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||||
type_check_2darray(_type, typeof_field(_state, _field), _n1, _n2))
|
type_check_2darray(_type, typeof_field(_state, _field), _n1, _n2))
|
||||||
|
|
||||||
#define vmstate_offset_sub_array(_state, _field, _type, _start) \
|
#define vmstate_offset_sub_array(_state, _field, _type, _start) \
|
||||||
(offsetof(_state, _field[_start]))
|
vmstate_offset_value(_state, _field[_start], _type)
|
||||||
|
|
||||||
#define vmstate_offset_buffer(_state, _field) \
|
#define vmstate_offset_buffer(_state, _field) \
|
||||||
vmstate_offset_array(_state, _field, uint8_t, \
|
vmstate_offset_array(_state, _field, uint8_t, \
|
||||||
|
|
|
@ -44,6 +44,13 @@ int socket_set_fast_reuse(int fd);
|
||||||
int send_all(int fd, const void *buf, int len1);
|
int send_all(int fd, const void *buf, int len1);
|
||||||
int recv_all(int fd, void *buf, int len1, bool single_read);
|
int recv_all(int fd, void *buf, int len1, bool single_read);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/* Windows has different names for the same constants with the same values */
|
||||||
|
#define SHUT_RD 0
|
||||||
|
#define SHUT_WR 1
|
||||||
|
#define SHUT_RDWR 2
|
||||||
|
#endif
|
||||||
|
|
||||||
/* callback function for nonblocking connect
|
/* callback function for nonblocking connect
|
||||||
* valid fd on success, negative error code on failure
|
* valid fd on success, negative error code on failure
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,13 +31,29 @@
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool fd_is_socket(int fd)
|
||||||
|
{
|
||||||
|
struct stat stat;
|
||||||
|
int ret = fstat(fd, &stat);
|
||||||
|
if (ret == -1) {
|
||||||
|
/* When in doubt say no */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return S_ISSOCK(stat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
|
void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
|
||||||
{
|
{
|
||||||
int fd = monitor_get_fd(cur_mon, fdname, errp);
|
int fd = monitor_get_fd(cur_mon, fdname, errp);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s->file = qemu_fdopen(fd, "wb");
|
|
||||||
|
if (fd_is_socket(fd)) {
|
||||||
|
s->file = qemu_fopen_socket(fd, "wb");
|
||||||
|
} else {
|
||||||
|
s->file = qemu_fdopen(fd, "wb");
|
||||||
|
}
|
||||||
|
|
||||||
migrate_fd_connect(s);
|
migrate_fd_connect(s);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +74,11 @@ void fd_start_incoming_migration(const char *infd, Error **errp)
|
||||||
DPRINTF("Attempting to start an incoming migration via fd\n");
|
DPRINTF("Attempting to start an incoming migration via fd\n");
|
||||||
|
|
||||||
fd = strtol(infd, NULL, 0);
|
fd = strtol(infd, NULL, 0);
|
||||||
f = qemu_fdopen(fd, "rb");
|
if (fd_is_socket(fd)) {
|
||||||
|
f = qemu_fopen_socket(fd, "rb");
|
||||||
|
} else {
|
||||||
|
f = qemu_fdopen(fd, "rb");
|
||||||
|
}
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
error_setg_errno(errp, errno, "failed to open the source descriptor");
|
error_setg_errno(errp, errno, "failed to open the source descriptor");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -330,6 +330,7 @@ void migrate_fd_error(MigrationState *s)
|
||||||
static void migrate_fd_cancel(MigrationState *s)
|
static void migrate_fd_cancel(MigrationState *s)
|
||||||
{
|
{
|
||||||
int old_state ;
|
int old_state ;
|
||||||
|
QEMUFile *f = migrate_get_current()->file;
|
||||||
trace_migrate_fd_cancel();
|
trace_migrate_fd_cancel();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -339,6 +340,17 @@ static void migrate_fd_cancel(MigrationState *s)
|
||||||
}
|
}
|
||||||
migrate_set_state(s, old_state, MIG_STATE_CANCELLING);
|
migrate_set_state(s, old_state, MIG_STATE_CANCELLING);
|
||||||
} while (s->state != MIG_STATE_CANCELLING);
|
} while (s->state != MIG_STATE_CANCELLING);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're unlucky the migration code might be stuck somewhere in a
|
||||||
|
* send/write while the network has failed and is waiting to timeout;
|
||||||
|
* if we've got shutdown(2) available then we can force it to quit.
|
||||||
|
* The outgoing qemu file gets closed in migrate_fd_cleanup that is
|
||||||
|
* called in a bh, so there is no race against this cancel.
|
||||||
|
*/
|
||||||
|
if (s->state == MIG_STATE_CANCELLING && f) {
|
||||||
|
qemu_file_shutdown(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_migration_state_change_notifier(Notifier *notify)
|
void add_migration_state_change_notifier(Notifier *notify)
|
||||||
|
|
|
@ -395,6 +395,7 @@ QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *qsb)
|
||||||
typedef struct QEMUBuffer {
|
typedef struct QEMUBuffer {
|
||||||
QEMUSizedBuffer *qsb;
|
QEMUSizedBuffer *qsb;
|
||||||
QEMUFile *file;
|
QEMUFile *file;
|
||||||
|
bool qsb_allocated;
|
||||||
} QEMUBuffer;
|
} QEMUBuffer;
|
||||||
|
|
||||||
static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
|
static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
|
||||||
|
@ -424,7 +425,9 @@ static int buf_close(void *opaque)
|
||||||
{
|
{
|
||||||
QEMUBuffer *s = opaque;
|
QEMUBuffer *s = opaque;
|
||||||
|
|
||||||
qsb_free(s->qsb);
|
if (s->qsb_allocated) {
|
||||||
|
qsb_free(s->qsb);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
||||||
|
@ -463,12 +466,11 @@ QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
|
||||||
}
|
}
|
||||||
|
|
||||||
s = g_malloc0(sizeof(QEMUBuffer));
|
s = g_malloc0(sizeof(QEMUBuffer));
|
||||||
if (mode[0] == 'r') {
|
s->qsb = input;
|
||||||
s->qsb = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->qsb == NULL) {
|
if (s->qsb == NULL) {
|
||||||
s->qsb = qsb_create(NULL, 0);
|
s->qsb = qsb_create(NULL, 0);
|
||||||
|
s->qsb_allocated = true;
|
||||||
}
|
}
|
||||||
if (!s->qsb) {
|
if (!s->qsb) {
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
#include "migration/qemu-file.h"
|
#include "migration/qemu-file.h"
|
||||||
|
#include "migration/qemu-file-internal.h"
|
||||||
|
|
||||||
typedef struct QEMUFileSocket {
|
typedef struct QEMUFileSocket {
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -84,6 +85,17 @@ static int socket_close(void *opaque)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int socket_shutdown(void *opaque, bool rd, bool wr)
|
||||||
|
{
|
||||||
|
QEMUFileSocket *s = opaque;
|
||||||
|
|
||||||
|
if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
|
||||||
|
return -errno;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
||||||
int64_t pos)
|
int64_t pos)
|
||||||
{
|
{
|
||||||
|
@ -192,15 +204,18 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QEMUFileOps socket_read_ops = {
|
static const QEMUFileOps socket_read_ops = {
|
||||||
.get_fd = socket_get_fd,
|
.get_fd = socket_get_fd,
|
||||||
.get_buffer = socket_get_buffer,
|
.get_buffer = socket_get_buffer,
|
||||||
.close = socket_close
|
.close = socket_close,
|
||||||
|
.shut_down = socket_shutdown
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QEMUFileOps socket_write_ops = {
|
static const QEMUFileOps socket_write_ops = {
|
||||||
.get_fd = socket_get_fd,
|
.get_fd = socket_get_fd,
|
||||||
.writev_buffer = socket_writev_buffer,
|
.writev_buffer = socket_writev_buffer,
|
||||||
.close = socket_close
|
.close = socket_close,
|
||||||
|
.shut_down = socket_shutdown
|
||||||
};
|
};
|
||||||
|
|
||||||
QEMUFile *qemu_fopen_socket(int fd, const char *mode)
|
QEMUFile *qemu_fopen_socket(int fd, const char *mode)
|
||||||
|
|
|
@ -30,6 +30,18 @@
|
||||||
#include "migration/qemu-file-internal.h"
|
#include "migration/qemu-file-internal.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop a file from being read/written - not all backing files can do this
|
||||||
|
* typically only sockets can.
|
||||||
|
*/
|
||||||
|
int qemu_file_shutdown(QEMUFile *f)
|
||||||
|
{
|
||||||
|
if (!f->ops->shut_down) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
return f->ops->shut_down(f->opaque, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
bool qemu_file_mode_is_not_valid(const char *mode)
|
bool qemu_file_mode_is_not_valid(const char *mode)
|
||||||
{
|
{
|
||||||
if (mode == NULL ||
|
if (mode == NULL ||
|
||||||
|
|
45
page_cache.c
45
page_cache.c
|
@ -33,6 +33,9 @@
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* the page in cache will not be replaced in two cycles */
|
||||||
|
#define CACHED_PAGE_LIFETIME 2
|
||||||
|
|
||||||
typedef struct CacheItem CacheItem;
|
typedef struct CacheItem CacheItem;
|
||||||
|
|
||||||
struct CacheItem {
|
struct CacheItem {
|
||||||
|
@ -122,18 +125,6 @@ static size_t cache_get_cache_pos(const PageCache *cache,
|
||||||
return pos;
|
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)
|
static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr)
|
||||||
{
|
{
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
@ -151,17 +142,35 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr)
|
||||||
return cache_get_by_addr(cache, addr)->it_data;
|
return cache_get_by_addr(cache, addr)->it_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata)
|
bool cache_is_cached(const PageCache *cache, uint64_t addr,
|
||||||
|
uint64_t current_age)
|
||||||
|
{
|
||||||
|
CacheItem *it;
|
||||||
|
|
||||||
|
it = cache_get_by_addr(cache, addr);
|
||||||
|
|
||||||
|
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 = NULL;
|
CacheItem *it;
|
||||||
|
|
||||||
g_assert(cache);
|
|
||||||
g_assert(cache->page_cache);
|
|
||||||
|
|
||||||
/* actual update of entry */
|
/* actual update of entry */
|
||||||
it = cache_get_by_addr(cache, addr);
|
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 */
|
/* allocate page */
|
||||||
if (!it->it_data) {
|
if (!it->it_data) {
|
||||||
it->it_data = g_try_malloc(cache->page_size);
|
it->it_data = g_try_malloc(cache->page_size);
|
||||||
|
@ -174,7 +183,7 @@ int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata)
|
||||||
|
|
||||||
memcpy(it->it_data, pdata, cache->page_size);
|
memcpy(it->it_data, pdata, cache->page_size);
|
||||||
|
|
||||||
it->it_age = ++cache->max_item_age;
|
it->it_age = current_age;
|
||||||
it->it_addr = addr;
|
it->it_addr = addr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -60,16 +60,6 @@ static QEMUFile *open_test_file(bool write)
|
||||||
return qemu_fdopen(fd, write ? "wb" : "rb");
|
return qemu_fdopen(fd, write ? "wb" : "rb");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open a read-only qemu-file from an existing memory block */
|
|
||||||
static QEMUFile *open_mem_file_read(const void *data, size_t len)
|
|
||||||
{
|
|
||||||
/* The qsb gets freed by qemu_fclose */
|
|
||||||
QEMUSizedBuffer *qsb = qsb_create(data, len);
|
|
||||||
g_assert(qsb);
|
|
||||||
|
|
||||||
return qemu_bufopen("r", qsb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the contents of the memory-buffered file f match
|
* Check that the contents of the memory-buffered file f match
|
||||||
* the given size/data.
|
* the given size/data.
|
||||||
|
@ -450,7 +440,9 @@ static void test_load_noskip(void)
|
||||||
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
|
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
|
||||||
};
|
};
|
||||||
|
|
||||||
QEMUFile *loading = open_mem_file_read(buf, sizeof(buf));
|
QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
|
||||||
|
g_assert(qsb);
|
||||||
|
QEMUFile *loading = qemu_bufopen("r", qsb);
|
||||||
TestStruct obj = { .skip_c_e = false };
|
TestStruct obj = { .skip_c_e = false };
|
||||||
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
|
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
|
||||||
g_assert(!qemu_file_get_error(loading));
|
g_assert(!qemu_file_get_error(loading));
|
||||||
|
@ -461,6 +453,7 @@ static void test_load_noskip(void)
|
||||||
g_assert_cmpint(obj.e, ==, 50);
|
g_assert_cmpint(obj.e, ==, 50);
|
||||||
g_assert_cmpint(obj.f, ==, 60);
|
g_assert_cmpint(obj.f, ==, 60);
|
||||||
qemu_fclose(loading);
|
qemu_fclose(loading);
|
||||||
|
qsb_free(qsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_load_skip(void)
|
static void test_load_skip(void)
|
||||||
|
@ -473,7 +466,9 @@ static void test_load_skip(void)
|
||||||
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
|
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
|
||||||
};
|
};
|
||||||
|
|
||||||
QEMUFile *loading = open_mem_file_read(buf, sizeof(buf));
|
QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
|
||||||
|
g_assert(qsb);
|
||||||
|
QEMUFile *loading = qemu_bufopen("r", qsb);
|
||||||
TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
|
TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
|
||||||
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
|
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
|
||||||
g_assert(!qemu_file_get_error(loading));
|
g_assert(!qemu_file_get_error(loading));
|
||||||
|
@ -484,6 +479,7 @@ static void test_load_skip(void)
|
||||||
g_assert_cmpint(obj.e, ==, 500);
|
g_assert_cmpint(obj.e, ==, 500);
|
||||||
g_assert_cmpint(obj.f, ==, 60);
|
g_assert_cmpint(obj.f, ==, 60);
|
||||||
qemu_fclose(loading);
|
qemu_fclose(loading);
|
||||||
|
qsb_free(qsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
|
Loading…
Reference in New Issue