migration:fix free XBZRLE decoded_buf wrong

When qemu do live migration with xbzrle, qemu malloc decoded_buf
at destination end but free it at source end. It will crash qemu
by double free error in some scenarios. Splitting the XBZRLE structure
for clear logic distinguishing src/dst side.

Signed-off-by: ChenLiang <chenliang88@huawei.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: GongLei <arei.gonglei@huawei.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
Gonglei (Arei) 2014-01-30 20:08:35 +02:00 committed by Juan Quintela
parent c91e681a55
commit 905f26f222
3 changed files with 14 additions and 10 deletions

View File

@ -164,17 +164,15 @@ static struct {
uint8_t *encoded_buf; uint8_t *encoded_buf;
/* buffer for storing page content */ /* buffer for storing page content */
uint8_t *current_buf; uint8_t *current_buf;
/* buffer used for XBZRLE decoding */
uint8_t *decoded_buf;
/* Cache for XBZRLE */ /* Cache for XBZRLE */
PageCache *cache; PageCache *cache;
} XBZRLE = { } XBZRLE = {
.encoded_buf = NULL, .encoded_buf = NULL,
.current_buf = NULL, .current_buf = NULL,
.decoded_buf = NULL,
.cache = NULL, .cache = NULL,
}; };
/* buffer used for XBZRLE decoding */
static uint8_t *xbzrle_decoded_buf;
int64_t xbzrle_cache_resize(int64_t new_size) int64_t xbzrle_cache_resize(int64_t new_size)
{ {
@ -606,6 +604,12 @@ uint64_t ram_bytes_total(void)
return total; return total;
} }
void free_xbzrle_decoded_buf(void)
{
g_free(xbzrle_decoded_buf);
xbzrle_decoded_buf = NULL;
}
static void migration_end(void) static void migration_end(void)
{ {
if (migration_bitmap) { if (migration_bitmap) {
@ -619,11 +623,9 @@ static void migration_end(void)
g_free(XBZRLE.cache); g_free(XBZRLE.cache);
g_free(XBZRLE.encoded_buf); g_free(XBZRLE.encoded_buf);
g_free(XBZRLE.current_buf); g_free(XBZRLE.current_buf);
g_free(XBZRLE.decoded_buf);
XBZRLE.cache = NULL; XBZRLE.cache = NULL;
XBZRLE.encoded_buf = NULL; XBZRLE.encoded_buf = NULL;
XBZRLE.current_buf = NULL; XBZRLE.current_buf = NULL;
XBZRLE.decoded_buf = NULL;
} }
} }
@ -814,8 +816,8 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
unsigned int xh_len; unsigned int xh_len;
int xh_flags; int xh_flags;
if (!XBZRLE.decoded_buf) { if (!xbzrle_decoded_buf) {
XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE); xbzrle_decoded_buf = g_malloc(TARGET_PAGE_SIZE);
} }
/* extract RLE header */ /* extract RLE header */
@ -832,10 +834,10 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
return -1; return -1;
} }
/* load data and decode */ /* load data and decode */
qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len); qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
/* decode RLE */ /* decode RLE */
ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host, ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
TARGET_PAGE_SIZE); TARGET_PAGE_SIZE);
if (ret == -1) { if (ret == -1) {
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n"); fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");

View File

@ -109,6 +109,7 @@ MigrationState *migrate_get_current(void);
uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_transferred(void); uint64_t ram_bytes_transferred(void);
uint64_t ram_bytes_total(void); uint64_t ram_bytes_total(void);
void free_xbzrle_decoded_buf(void);
void acct_update_position(QEMUFile *f, size_t size, bool zero); void acct_update_position(QEMUFile *f, size_t size, bool zero);

View File

@ -105,6 +105,7 @@ static void process_incoming_migration_co(void *opaque)
ret = qemu_loadvm_state(f); ret = qemu_loadvm_state(f);
qemu_fclose(f); qemu_fclose(f);
free_xbzrle_decoded_buf();
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "load of migration failed\n"); fprintf(stderr, "load of migration failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);