migration/next for 20140505
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJTZ/QsAAoJEPSH7xhYctcjJ4wP/31lNMpPLxdRpxpUoTPK39L0 zEoBTUH5dzG2FG34p8/znNH0Lbmc3GALqP9UzyM0sL3QU0EDwqAP0idLJ/8zHrYN ZNJnNH6wexlpEypAsyQiayAFYAq6bc3hYtnEurN56dQgPVgb6jCicuOAt26JafLg xuGIuencgaEFZaIb8iobxloqDX9raoq0+JfnoV8r02+ES+PG+HHfZsAlbDiWpj/Z o06WBq9Xvf8X/zvuGHb9PCLGK36+kxPJ2G2531TJGZ6BjjewDExF2xlQH+PQ8pQB d2OKCP0In66JfyLu6JBz21APrks7DJxsuenvoqPhxhtlIcBSm+grZElNLbccDMLQ 3fteWOCcri5WSwKNAkZ138D5SzIArZFBlqD9qW0GQsiaj3tCxfy162JAmzRPa94i R5OJCTDclwjCH6JvRsOs8NrQyYcXHcEl2rfeymfr68YOH5XBMeRPhcR91tVr03ow ZVgvwC/TJHntKnW+qtGIOa9Wfq4KghjddD37ayPAqKM/GQ0TV2sAPEr2htDaBZ0l 5O/YGsAZPKax72OnMR2ObqoIMokympeanQLxG3Q8VKQSU2c+aU3rGVQrG1juiVYw NiC/nzarFzFWU8UYToXIu2QBDTde2vuRLX/myzL7L4OLavOcv8EXZBp60DP/bktE Pd+jdeLMh9kWu1tFrE8F =VoYL -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20140505' into staging migration/next for 20140505 # gpg: Signature made Mon 05 May 2014 21:27:24 BST using RSA key ID 5872D723 # gpg: Can't check signature: public key not found * remotes/juanquintela/tags/migration/20140505: (36 commits) migration: expose xbzrle cache miss rate migration: expose the bitmap_sync_count to the end migration: Add counts of updating the dirty bitmap XBZRLE: Fix one XBZRLE corruption issues migration: remove duplicate code Coverity: Fix failure path for qemu_accept in migration Init the XBZRLE.lock in ram_mig_init Provide init function for ram migration Count used RAMBlock pages for migration_dirty_pages Make qemu_peek_buffer loop until it gets it's data Disallow outward migration while awaiting incoming migration virtio: validate config_len on load virtio-net: out-of-bounds buffer write on load openpic: avoid buffer overrun on incoming migration ssi-sd: fix buffer overrun on invalid state load savevm: Ignore minimum_version_id_old if there is no load_state_old usb: sanity check setup_index+setup_len in post_load vmstate: s/VMSTATE_INT32_LE/VMSTATE_INT32_POSITIVE_LE/ virtio-scsi: fix buffer overrun on invalid state load zaurus: fix buffer overrun on invalid state load ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						c9541f67df
					
				
							
								
								
									
										202
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								arch_init.c
									
									
									
									
									
								
							@ -45,6 +45,7 @@
 | 
				
			|||||||
#include "hw/audio/pcspk.h"
 | 
					#include "hw/audio/pcspk.h"
 | 
				
			||||||
#include "migration/page_cache.h"
 | 
					#include "migration/page_cache.h"
 | 
				
			||||||
#include "qemu/config-file.h"
 | 
					#include "qemu/config-file.h"
 | 
				
			||||||
 | 
					#include "qemu/error-report.h"
 | 
				
			||||||
#include "qmp-commands.h"
 | 
					#include "qmp-commands.h"
 | 
				
			||||||
#include "trace.h"
 | 
					#include "trace.h"
 | 
				
			||||||
#include "exec/cpu-all.h"
 | 
					#include "exec/cpu-all.h"
 | 
				
			||||||
@ -110,6 +111,8 @@ static bool mig_throttle_on;
 | 
				
			|||||||
static int dirty_rate_high_cnt;
 | 
					static int dirty_rate_high_cnt;
 | 
				
			||||||
static void check_guest_throttling(void);
 | 
					static void check_guest_throttling(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t bitmap_sync_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***********************************************************/
 | 
					/***********************************************************/
 | 
				
			||||||
/* ram save/restore */
 | 
					/* ram save/restore */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -167,11 +170,8 @@ static struct {
 | 
				
			|||||||
    /* Cache for XBZRLE, Protected by lock. */
 | 
					    /* Cache for XBZRLE, Protected by lock. */
 | 
				
			||||||
    PageCache *cache;
 | 
					    PageCache *cache;
 | 
				
			||||||
    QemuMutex lock;
 | 
					    QemuMutex lock;
 | 
				
			||||||
} XBZRLE = {
 | 
					} XBZRLE;
 | 
				
			||||||
    .encoded_buf = NULL,
 | 
					
 | 
				
			||||||
    .current_buf = NULL,
 | 
					 | 
				
			||||||
    .cache = NULL,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
/* buffer used for XBZRLE decoding */
 | 
					/* buffer used for XBZRLE decoding */
 | 
				
			||||||
static uint8_t *xbzrle_decoded_buf;
 | 
					static uint8_t *xbzrle_decoded_buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -187,41 +187,44 @@ static void XBZRLE_cache_unlock(void)
 | 
				
			|||||||
        qemu_mutex_unlock(&XBZRLE.lock);
 | 
					        qemu_mutex_unlock(&XBZRLE.lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * called from qmp_migrate_set_cache_size in main thread, possibly while
 | 
				
			||||||
 | 
					 * a migration is in progress.
 | 
				
			||||||
 | 
					 * A running migration maybe using the cache and might finish during this
 | 
				
			||||||
 | 
					 * call, hence changes to the cache are protected by XBZRLE.lock().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int64_t xbzrle_cache_resize(int64_t new_size)
 | 
					int64_t xbzrle_cache_resize(int64_t new_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PageCache *new_cache, *cache_to_free;
 | 
					    PageCache *new_cache;
 | 
				
			||||||
 | 
					    int64_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (new_size < TARGET_PAGE_SIZE) {
 | 
					    if (new_size < TARGET_PAGE_SIZE) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* no need to lock, the current thread holds qemu big lock */
 | 
					    XBZRLE_cache_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (XBZRLE.cache != NULL) {
 | 
					    if (XBZRLE.cache != NULL) {
 | 
				
			||||||
        /* check XBZRLE.cache again later */
 | 
					 | 
				
			||||||
        if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
 | 
					        if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
 | 
				
			||||||
            return pow2floor(new_size);
 | 
					            goto out_new_size;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
 | 
					        new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
 | 
				
			||||||
                                        TARGET_PAGE_SIZE);
 | 
					                                        TARGET_PAGE_SIZE);
 | 
				
			||||||
        if (!new_cache) {
 | 
					        if (!new_cache) {
 | 
				
			||||||
            DPRINTF("Error creating cache\n");
 | 
					            error_report("Error creating cache");
 | 
				
			||||||
            return -1;
 | 
					            ret = -1;
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XBZRLE_cache_lock();
 | 
					        cache_fini(XBZRLE.cache);
 | 
				
			||||||
        /* the XBZRLE.cache may have be destroyed, check it again */
 | 
					        XBZRLE.cache = new_cache;
 | 
				
			||||||
        if (XBZRLE.cache != NULL) {
 | 
					 | 
				
			||||||
            cache_to_free = XBZRLE.cache;
 | 
					 | 
				
			||||||
            XBZRLE.cache = new_cache;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            cache_to_free = new_cache;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        XBZRLE_cache_unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cache_fini(cache_to_free);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return pow2floor(new_size);
 | 
					out_new_size:
 | 
				
			||||||
 | 
					    ret = pow2floor(new_size);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    XBZRLE_cache_unlock();
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* accounting for migration statistics */
 | 
					/* accounting for migration statistics */
 | 
				
			||||||
@ -233,6 +236,7 @@ typedef struct AccountingInfo {
 | 
				
			|||||||
    uint64_t xbzrle_bytes;
 | 
					    uint64_t xbzrle_bytes;
 | 
				
			||||||
    uint64_t xbzrle_pages;
 | 
					    uint64_t xbzrle_pages;
 | 
				
			||||||
    uint64_t xbzrle_cache_miss;
 | 
					    uint64_t xbzrle_cache_miss;
 | 
				
			||||||
 | 
					    double xbzrle_cache_miss_rate;
 | 
				
			||||||
    uint64_t xbzrle_overflows;
 | 
					    uint64_t xbzrle_overflows;
 | 
				
			||||||
} AccountingInfo;
 | 
					} AccountingInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -288,6 +292,11 @@ uint64_t xbzrle_mig_pages_cache_miss(void)
 | 
				
			|||||||
    return acct_info.xbzrle_cache_miss;
 | 
					    return acct_info.xbzrle_cache_miss;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					double xbzrle_mig_cache_miss_rate(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return acct_info.xbzrle_cache_miss_rate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t xbzrle_mig_pages_overflow(void)
 | 
					uint64_t xbzrle_mig_pages_overflow(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return acct_info.xbzrle_overflows;
 | 
					    return acct_info.xbzrle_overflows;
 | 
				
			||||||
@ -340,7 +349,7 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define ENCODING_FLAG_XBZRLE 0x1
 | 
					#define ENCODING_FLAG_XBZRLE 0x1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
 | 
					static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
 | 
				
			||||||
                            ram_addr_t current_addr, RAMBlock *block,
 | 
					                            ram_addr_t current_addr, RAMBlock *block,
 | 
				
			||||||
                            ram_addr_t offset, int cont, bool last_stage)
 | 
					                            ram_addr_t offset, int cont, bool last_stage)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -348,19 +357,23 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
 | 
				
			|||||||
    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)) {
 | 
				
			||||||
 | 
					        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) == -1) {
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                /* update *current_data when the page has been
 | 
				
			||||||
 | 
					                   inserted into cache */
 | 
				
			||||||
 | 
					                *current_data = get_cached_data(XBZRLE.cache, current_addr);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        acct_info.xbzrle_cache_miss++;
 | 
					 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
 | 
					    prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* save current buffer into memory */
 | 
					    /* save current buffer into memory */
 | 
				
			||||||
    memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
 | 
					    memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* XBZRLE encoding (if there is no overflow) */
 | 
					    /* XBZRLE encoding (if there is no overflow) */
 | 
				
			||||||
    encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
 | 
					    encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
 | 
				
			||||||
@ -373,7 +386,10 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
 | 
				
			|||||||
        DPRINTF("Overflow\n");
 | 
					        DPRINTF("Overflow\n");
 | 
				
			||||||
        acct_info.xbzrle_overflows++;
 | 
					        acct_info.xbzrle_overflows++;
 | 
				
			||||||
        /* update data in the cache */
 | 
					        /* update data in the cache */
 | 
				
			||||||
        memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
 | 
					        if (!last_stage) {
 | 
				
			||||||
 | 
					            memcpy(prev_cached_page, *current_data, TARGET_PAGE_SIZE);
 | 
				
			||||||
 | 
					            *current_data = prev_cached_page;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -479,6 +495,10 @@ static void migration_bitmap_sync(void)
 | 
				
			|||||||
    static int64_t num_dirty_pages_period;
 | 
					    static int64_t num_dirty_pages_period;
 | 
				
			||||||
    int64_t end_time;
 | 
					    int64_t end_time;
 | 
				
			||||||
    int64_t bytes_xfer_now;
 | 
					    int64_t bytes_xfer_now;
 | 
				
			||||||
 | 
					    static uint64_t xbzrle_cache_miss_prev;
 | 
				
			||||||
 | 
					    static uint64_t iterations_prev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bitmap_sync_count++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!bytes_xfer_prev) {
 | 
					    if (!bytes_xfer_prev) {
 | 
				
			||||||
        bytes_xfer_prev = ram_bytes_transferred();
 | 
					        bytes_xfer_prev = ram_bytes_transferred();
 | 
				
			||||||
@ -520,11 +540,22 @@ static void migration_bitmap_sync(void)
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
             mig_throttle_on = false;
 | 
					             mig_throttle_on = false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (migrate_use_xbzrle()) {
 | 
				
			||||||
 | 
					            if (iterations_prev != 0) {
 | 
				
			||||||
 | 
					                acct_info.xbzrle_cache_miss_rate =
 | 
				
			||||||
 | 
					                   (double)(acct_info.xbzrle_cache_miss -
 | 
				
			||||||
 | 
					                            xbzrle_cache_miss_prev) /
 | 
				
			||||||
 | 
					                   (acct_info.iterations - iterations_prev);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            iterations_prev = acct_info.iterations;
 | 
				
			||||||
 | 
					            xbzrle_cache_miss_prev = acct_info.xbzrle_cache_miss;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        s->dirty_pages_rate = num_dirty_pages_period * 1000
 | 
					        s->dirty_pages_rate = num_dirty_pages_period * 1000
 | 
				
			||||||
            / (end_time - start_time);
 | 
					            / (end_time - start_time);
 | 
				
			||||||
        s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
 | 
					        s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
 | 
				
			||||||
        start_time = end_time;
 | 
					        start_time = end_time;
 | 
				
			||||||
        num_dirty_pages_period = 0;
 | 
					        num_dirty_pages_period = 0;
 | 
				
			||||||
 | 
					        s->dirty_sync_count = bitmap_sync_count;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -598,15 +629,9 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
 | 
				
			|||||||
                 */
 | 
					                 */
 | 
				
			||||||
                xbzrle_cache_zero_page(current_addr);
 | 
					                xbzrle_cache_zero_page(current_addr);
 | 
				
			||||||
            } else if (!ram_bulk_stage && migrate_use_xbzrle()) {
 | 
					            } else if (!ram_bulk_stage && migrate_use_xbzrle()) {
 | 
				
			||||||
                bytes_sent = save_xbzrle_page(f, p, current_addr, block,
 | 
					                bytes_sent = save_xbzrle_page(f, &p, current_addr, block,
 | 
				
			||||||
                                              offset, cont, last_stage);
 | 
					                                              offset, cont, last_stage);
 | 
				
			||||||
                if (!last_stage) {
 | 
					                if (!last_stage) {
 | 
				
			||||||
                    /* We must send exactly what's in the xbzrle cache
 | 
					 | 
				
			||||||
                     * even if the page wasn't xbzrle compressed, so that
 | 
					 | 
				
			||||||
                     * it's right next time.
 | 
					 | 
				
			||||||
                     */
 | 
					 | 
				
			||||||
                    p = get_cached_data(XBZRLE.cache, current_addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    /* Can't send this cached data async, since the cache page
 | 
					                    /* Can't send this cached data async, since the cache page
 | 
				
			||||||
                     * might get updated before it gets to the wire
 | 
					                     * might get updated before it gets to the wire
 | 
				
			||||||
                     */
 | 
					                     */
 | 
				
			||||||
@ -726,37 +751,34 @@ static void reset_ram_globals(void)
 | 
				
			|||||||
static int ram_save_setup(QEMUFile *f, void *opaque)
 | 
					static int ram_save_setup(QEMUFile *f, void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    RAMBlock *block;
 | 
					    RAMBlock *block;
 | 
				
			||||||
    int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;
 | 
					    int64_t ram_bitmap_pages; /* Size of bitmap in pages, including gaps */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    migration_bitmap = bitmap_new(ram_pages);
 | 
					 | 
				
			||||||
    bitmap_set(migration_bitmap, 0, ram_pages);
 | 
					 | 
				
			||||||
    migration_dirty_pages = ram_pages;
 | 
					 | 
				
			||||||
    mig_throttle_on = false;
 | 
					    mig_throttle_on = false;
 | 
				
			||||||
    dirty_rate_high_cnt = 0;
 | 
					    dirty_rate_high_cnt = 0;
 | 
				
			||||||
 | 
					    bitmap_sync_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (migrate_use_xbzrle()) {
 | 
					    if (migrate_use_xbzrle()) {
 | 
				
			||||||
        qemu_mutex_lock_iothread();
 | 
					        XBZRLE_cache_lock();
 | 
				
			||||||
        XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
 | 
					        XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
 | 
				
			||||||
                                  TARGET_PAGE_SIZE,
 | 
					                                  TARGET_PAGE_SIZE,
 | 
				
			||||||
                                  TARGET_PAGE_SIZE);
 | 
					                                  TARGET_PAGE_SIZE);
 | 
				
			||||||
        if (!XBZRLE.cache) {
 | 
					        if (!XBZRLE.cache) {
 | 
				
			||||||
            qemu_mutex_unlock_iothread();
 | 
					            XBZRLE_cache_unlock();
 | 
				
			||||||
            DPRINTF("Error creating cache\n");
 | 
					            error_report("Error creating cache");
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        qemu_mutex_init(&XBZRLE.lock);
 | 
					        XBZRLE_cache_unlock();
 | 
				
			||||||
        qemu_mutex_unlock_iothread();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* We prefer not to abort if there is no memory */
 | 
					        /* We prefer not to abort if there is no memory */
 | 
				
			||||||
        XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
 | 
					        XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
 | 
				
			||||||
        if (!XBZRLE.encoded_buf) {
 | 
					        if (!XBZRLE.encoded_buf) {
 | 
				
			||||||
            DPRINTF("Error allocating encoded_buf\n");
 | 
					            error_report("Error allocating encoded_buf");
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
 | 
					        XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
 | 
				
			||||||
        if (!XBZRLE.current_buf) {
 | 
					        if (!XBZRLE.current_buf) {
 | 
				
			||||||
            DPRINTF("Error allocating current_buf\n");
 | 
					            error_report("Error allocating current_buf");
 | 
				
			||||||
            g_free(XBZRLE.encoded_buf);
 | 
					            g_free(XBZRLE.encoded_buf);
 | 
				
			||||||
            XBZRLE.encoded_buf = NULL;
 | 
					            XBZRLE.encoded_buf = NULL;
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
@ -770,6 +792,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
 | 
				
			|||||||
    bytes_transferred = 0;
 | 
					    bytes_transferred = 0;
 | 
				
			||||||
    reset_ram_globals();
 | 
					    reset_ram_globals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					    migration_bitmap = bitmap_new(ram_bitmap_pages);
 | 
				
			||||||
 | 
					    bitmap_set(migration_bitmap, 0, ram_bitmap_pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Count the total number of pages used by ram blocks not including any
 | 
				
			||||||
 | 
					     * gaps due to alignment or unplugs.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    migration_dirty_pages = 0;
 | 
				
			||||||
 | 
					    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
 | 
				
			||||||
 | 
					        uint64_t block_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        block_pages = block->length >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					        migration_dirty_pages += block_pages;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memory_global_dirty_log_start();
 | 
					    memory_global_dirty_log_start();
 | 
				
			||||||
    migration_bitmap_sync();
 | 
					    migration_bitmap_sync();
 | 
				
			||||||
    qemu_mutex_unlock_iothread();
 | 
					    qemu_mutex_unlock_iothread();
 | 
				
			||||||
@ -997,7 +1035,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    seq_iter++;
 | 
					    seq_iter++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (version_id < 4 || version_id > 4) {
 | 
					    if (version_id != 4) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1008,44 +1046,42 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
        addr &= TARGET_PAGE_MASK;
 | 
					        addr &= TARGET_PAGE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
 | 
					        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
 | 
				
			||||||
            if (version_id == 4) {
 | 
					            /* Synchronize RAM block list */
 | 
				
			||||||
                /* Synchronize RAM block list */
 | 
					            char id[256];
 | 
				
			||||||
                char id[256];
 | 
					            ram_addr_t length;
 | 
				
			||||||
                ram_addr_t length;
 | 
					            ram_addr_t total_ram_bytes = addr;
 | 
				
			||||||
                ram_addr_t total_ram_bytes = addr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while (total_ram_bytes) {
 | 
					            while (total_ram_bytes) {
 | 
				
			||||||
                    RAMBlock *block;
 | 
					                RAMBlock *block;
 | 
				
			||||||
                    uint8_t len;
 | 
					                uint8_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    len = qemu_get_byte(f);
 | 
					                len = qemu_get_byte(f);
 | 
				
			||||||
                    qemu_get_buffer(f, (uint8_t *)id, len);
 | 
					                qemu_get_buffer(f, (uint8_t *)id, len);
 | 
				
			||||||
                    id[len] = 0;
 | 
					                id[len] = 0;
 | 
				
			||||||
                    length = qemu_get_be64(f);
 | 
					                length = qemu_get_be64(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
 | 
					                QTAILQ_FOREACH(block, &ram_list.blocks, next) {
 | 
				
			||||||
                        if (!strncmp(id, block->idstr, sizeof(id))) {
 | 
					                    if (!strncmp(id, block->idstr, sizeof(id))) {
 | 
				
			||||||
                            if (block->length != length) {
 | 
					                        if (block->length != length) {
 | 
				
			||||||
                                fprintf(stderr,
 | 
					                            fprintf(stderr,
 | 
				
			||||||
                                        "Length mismatch: %s: " RAM_ADDR_FMT
 | 
					                                    "Length mismatch: %s: " RAM_ADDR_FMT
 | 
				
			||||||
                                        " in != " RAM_ADDR_FMT "\n", id, length,
 | 
					                                    " in != " RAM_ADDR_FMT "\n", id, length,
 | 
				
			||||||
                                        block->length);
 | 
					                                    block->length);
 | 
				
			||||||
                                ret =  -EINVAL;
 | 
					                            ret =  -EINVAL;
 | 
				
			||||||
                                goto done;
 | 
					                            goto done;
 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (!block) {
 | 
					 | 
				
			||||||
                        fprintf(stderr, "Unknown ramblock \"%s\", cannot "
 | 
					 | 
				
			||||||
                                "accept migration\n", id);
 | 
					 | 
				
			||||||
                        ret = -EINVAL;
 | 
					 | 
				
			||||||
                        goto done;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    total_ram_bytes -= length;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!block) {
 | 
				
			||||||
 | 
					                    fprintf(stderr, "Unknown ramblock \"%s\", cannot "
 | 
				
			||||||
 | 
					                            "accept migration\n", id);
 | 
				
			||||||
 | 
					                    ret = -EINVAL;
 | 
				
			||||||
 | 
					                    goto done;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                total_ram_bytes -= length;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1095,7 +1131,7 @@ done:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SaveVMHandlers savevm_ram_handlers = {
 | 
					static SaveVMHandlers savevm_ram_handlers = {
 | 
				
			||||||
    .save_live_setup = ram_save_setup,
 | 
					    .save_live_setup = ram_save_setup,
 | 
				
			||||||
    .save_live_iterate = ram_save_iterate,
 | 
					    .save_live_iterate = ram_save_iterate,
 | 
				
			||||||
    .save_live_complete = ram_save_complete,
 | 
					    .save_live_complete = ram_save_complete,
 | 
				
			||||||
@ -1104,6 +1140,12 @@ SaveVMHandlers savevm_ram_handlers = {
 | 
				
			|||||||
    .cancel = ram_migration_cancel,
 | 
					    .cancel = ram_migration_cancel,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ram_mig_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_init(&XBZRLE.lock);
 | 
				
			||||||
 | 
					    register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct soundhw {
 | 
					struct soundhw {
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
    const char *descr;
 | 
					    const char *descr;
 | 
				
			||||||
 | 
				
			|||||||
@ -139,7 +139,6 @@ static const VMStateDescription vmstate_kbd = {
 | 
				
			|||||||
    .name = "pckbd",
 | 
					    .name = "pckbd",
 | 
				
			||||||
    .version_id = 3,
 | 
					    .version_id = 3,
 | 
				
			||||||
    .minimum_version_id = 3,
 | 
					    .minimum_version_id = 3,
 | 
				
			||||||
    .minimum_version_id_old = 3,
 | 
					 | 
				
			||||||
    .fields      = (VMStateField []) {
 | 
					    .fields      = (VMStateField []) {
 | 
				
			||||||
        VMSTATE_UINT8(write_cmd, KBDState),
 | 
					        VMSTATE_UINT8(write_cmd, KBDState),
 | 
				
			||||||
        VMSTATE_UINT8(status, KBDState),
 | 
					        VMSTATE_UINT8(status, KBDState),
 | 
				
			||||||
@ -168,12 +167,13 @@ You can see that there are several version fields:
 | 
				
			|||||||
- minimum_version_id: the minimum version_id that VMState is able to understand
 | 
					- minimum_version_id: the minimum version_id that VMState is able to understand
 | 
				
			||||||
  for that device.
 | 
					  for that device.
 | 
				
			||||||
- minimum_version_id_old: For devices that were not able to port to vmstate, we can
 | 
					- minimum_version_id_old: For devices that were not able to port to vmstate, we can
 | 
				
			||||||
  assign a function that knows how to read this old state.
 | 
					  assign a function that knows how to read this old state. This field is
 | 
				
			||||||
 | 
					  ignored if there is no load_state_old handler.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
So, VMState is able to read versions from minimum_version_id to
 | 
					So, VMState is able to read versions from minimum_version_id to
 | 
				
			||||||
version_id.  And the function load_state_old() is able to load state
 | 
					version_id.  And the function load_state_old() (if present) is able to
 | 
				
			||||||
from minimum_version_id_old to minimum_version_id.  This function is
 | 
					load state from minimum_version_id_old to minimum_version_id.  This
 | 
				
			||||||
deprecated and will be removed when no more users are left.
 | 
					function is deprecated and will be removed when no more users are left.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
===  Massaging functions ===
 | 
					===  Massaging functions ===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -255,7 +255,6 @@ const VMStateDescription vmstate_ide_drive_pio_state = {
 | 
				
			|||||||
    .name = "ide_drive/pio_state",
 | 
					    .name = "ide_drive/pio_state",
 | 
				
			||||||
    .version_id = 1,
 | 
					    .version_id = 1,
 | 
				
			||||||
    .minimum_version_id = 1,
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
    .minimum_version_id_old = 1,
 | 
					 | 
				
			||||||
    .pre_save = ide_drive_pio_pre_save,
 | 
					    .pre_save = ide_drive_pio_pre_save,
 | 
				
			||||||
    .post_load = ide_drive_pio_post_load,
 | 
					    .post_load = ide_drive_pio_post_load,
 | 
				
			||||||
    .fields      = (VMStateField []) {
 | 
					    .fields      = (VMStateField []) {
 | 
				
			||||||
@ -275,7 +274,6 @@ const VMStateDescription vmstate_ide_drive = {
 | 
				
			|||||||
    .name = "ide_drive",
 | 
					    .name = "ide_drive",
 | 
				
			||||||
    .version_id = 3,
 | 
					    .version_id = 3,
 | 
				
			||||||
    .minimum_version_id = 0,
 | 
					    .minimum_version_id = 0,
 | 
				
			||||||
    .minimum_version_id_old = 0,
 | 
					 | 
				
			||||||
    .post_load = ide_drive_post_load,
 | 
					    .post_load = ide_drive_post_load,
 | 
				
			||||||
    .fields      = (VMStateField []) {
 | 
					    .fields      = (VMStateField []) {
 | 
				
			||||||
        .... several fields ....
 | 
					        .... several fields ....
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								hmp.c
									
									
									
									
									
								
							@ -188,6 +188,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
 | 
				
			|||||||
                       info->ram->normal);
 | 
					                       info->ram->normal);
 | 
				
			||||||
        monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
 | 
					        monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
 | 
				
			||||||
                       info->ram->normal_bytes >> 10);
 | 
					                       info->ram->normal_bytes >> 10);
 | 
				
			||||||
 | 
					        monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
 | 
				
			||||||
 | 
					                       info->ram->dirty_sync_count);
 | 
				
			||||||
        if (info->ram->dirty_pages_rate) {
 | 
					        if (info->ram->dirty_pages_rate) {
 | 
				
			||||||
            monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
 | 
					            monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
 | 
				
			||||||
                           info->ram->dirty_pages_rate);
 | 
					                           info->ram->dirty_pages_rate);
 | 
				
			||||||
@ -212,6 +214,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
 | 
				
			|||||||
                       info->xbzrle_cache->pages);
 | 
					                       info->xbzrle_cache->pages);
 | 
				
			||||||
        monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
 | 
					        monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
 | 
				
			||||||
                       info->xbzrle_cache->cache_miss);
 | 
					                       info->xbzrle_cache->cache_miss);
 | 
				
			||||||
 | 
					        monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
 | 
				
			||||||
 | 
					                       info->xbzrle_cache->cache_miss_rate);
 | 
				
			||||||
        monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
 | 
					        monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
 | 
				
			||||||
                       info->xbzrle_cache->overflow);
 | 
					                       info->xbzrle_cache->overflow);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -732,7 +732,7 @@ static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
 | 
				
			|||||||
static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
 | 
					static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
 | 
					    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
 | 
				
			||||||
    int i;
 | 
					    int i, v;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->enable = qemu_get_be32(f);
 | 
					    s->enable = qemu_get_be32(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -746,7 +746,11 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    qemu_get_8s(f, &s->ssrsa);
 | 
					    qemu_get_8s(f, &s->ssrsa);
 | 
				
			||||||
    qemu_get_8s(f, &s->ssacd);
 | 
					    qemu_get_8s(f, &s->ssacd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->rx_level = qemu_get_byte(f);
 | 
					    v = qemu_get_byte(f);
 | 
				
			||||||
 | 
					    if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    s->rx_level = v;
 | 
				
			||||||
    s->rx_start = 0;
 | 
					    s->rx_start = 0;
 | 
				
			||||||
    for (i = 0; i < s->rx_level; i ++)
 | 
					    for (i = 0; i < s->rx_level; i ++)
 | 
				
			||||||
        s->rx_fifo[i] = qemu_get_byte(f);
 | 
					        s->rx_fifo[i] = qemu_get_byte(f);
 | 
				
			||||||
 | 
				
			|||||||
@ -312,18 +312,42 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->cmd_len = qemu_get_be32(f);
 | 
					    s->cmd_len = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->cmd = qemu_get_be32(f);
 | 
					    s->cmd = qemu_get_be32(f);
 | 
				
			||||||
    for (i = 0; i < 8; i++)
 | 
					    for (i = 0; i < 8; i++)
 | 
				
			||||||
        s->cmd_data[i] = qemu_get_be32(f);
 | 
					        s->cmd_data[i] = qemu_get_be32(f);
 | 
				
			||||||
    s->row = qemu_get_be32(f);
 | 
					    s->row = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->row < 0 || s->row >= 80) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->row_start = qemu_get_be32(f);
 | 
					    s->row_start = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->row_start < 0 || s->row_start >= 80) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->row_end = qemu_get_be32(f);
 | 
					    s->row_end = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->row_end < 0 || s->row_end >= 80) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->col = qemu_get_be32(f);
 | 
					    s->col = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->col < 0 || s->col >= 64) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->col_start = qemu_get_be32(f);
 | 
					    s->col_start = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->col_start < 0 || s->col_start >= 64) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->col_end = qemu_get_be32(f);
 | 
					    s->col_end = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->col_end < 0 || s->col_end >= 64) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->redraw = qemu_get_be32(f);
 | 
					    s->redraw = qemu_get_be32(f);
 | 
				
			||||||
    s->remap = qemu_get_be32(f);
 | 
					    s->remap = qemu_get_be32(f);
 | 
				
			||||||
    s->mode = qemu_get_be32(f);
 | 
					    s->mode = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
 | 
					    qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss->cs = qemu_get_be32(f);
 | 
					    ss->cs = qemu_get_be32(f);
 | 
				
			||||||
 | 
				
			|||||||
@ -203,6 +203,15 @@ static bool is_version_0 (void *opaque, int version_id)
 | 
				
			|||||||
    return version_id == 0;
 | 
					    return version_id == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool vmstate_scoop_validate(void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ScoopInfo *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return !(s->prev_level & 0xffff0000) &&
 | 
				
			||||||
 | 
					        !(s->gpio_level & 0xffff0000) &&
 | 
				
			||||||
 | 
					        !(s->gpio_dir & 0xffff0000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const VMStateDescription vmstate_scoop_regs = {
 | 
					static const VMStateDescription vmstate_scoop_regs = {
 | 
				
			||||||
    .name = "scoop",
 | 
					    .name = "scoop",
 | 
				
			||||||
    .version_id = 1,
 | 
					    .version_id = 1,
 | 
				
			||||||
@ -215,6 +224,7 @@ static const VMStateDescription vmstate_scoop_regs = {
 | 
				
			|||||||
        VMSTATE_UINT32(gpio_level, ScoopInfo),
 | 
					        VMSTATE_UINT32(gpio_level, ScoopInfo),
 | 
				
			||||||
        VMSTATE_UINT32(gpio_dir, ScoopInfo),
 | 
					        VMSTATE_UINT32(gpio_dir, ScoopInfo),
 | 
				
			||||||
        VMSTATE_UINT32(prev_level, ScoopInfo),
 | 
					        VMSTATE_UINT32(prev_level, ScoopInfo),
 | 
				
			||||||
 | 
					        VMSTATE_VALIDATE("irq levels are 16 bit", vmstate_scoop_validate),
 | 
				
			||||||
        VMSTATE_UINT16(mcr, ScoopInfo),
 | 
					        VMSTATE_UINT16(mcr, ScoopInfo),
 | 
				
			||||||
        VMSTATE_UINT16(cdr, ScoopInfo),
 | 
					        VMSTATE_UINT16(cdr, ScoopInfo),
 | 
				
			||||||
        VMSTATE_UINT16(ccr, ScoopInfo),
 | 
					        VMSTATE_UINT16(ccr, ScoopInfo),
 | 
				
			||||||
 | 
				
			|||||||
@ -1293,7 +1293,7 @@ const VMStateDescription vmstate_ahci = {
 | 
				
			|||||||
        VMSTATE_UINT32(control_regs.impl, AHCIState),
 | 
					        VMSTATE_UINT32(control_regs.impl, AHCIState),
 | 
				
			||||||
        VMSTATE_UINT32(control_regs.version, AHCIState),
 | 
					        VMSTATE_UINT32(control_regs.version, AHCIState),
 | 
				
			||||||
        VMSTATE_UINT32(idp_index, AHCIState),
 | 
					        VMSTATE_UINT32(idp_index, AHCIState),
 | 
				
			||||||
        VMSTATE_INT32(ports, AHCIState),
 | 
					        VMSTATE_INT32_EQUAL(ports, AHCIState),
 | 
				
			||||||
        VMSTATE_END_OF_LIST()
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1070,9 +1070,21 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    s->enabled = qemu_get_byte(f);
 | 
					    s->enabled = qemu_get_byte(f);
 | 
				
			||||||
    s->host_mode = qemu_get_byte(f);
 | 
					    s->host_mode = qemu_get_byte(f);
 | 
				
			||||||
    s->function = qemu_get_byte(f);
 | 
					    s->function = qemu_get_byte(f);
 | 
				
			||||||
 | 
					    if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->nextfunction = qemu_get_byte(f);
 | 
					    s->nextfunction = qemu_get_byte(f);
 | 
				
			||||||
 | 
					    if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->precision = qemu_get_byte(f);
 | 
					    s->precision = qemu_get_byte(f);
 | 
				
			||||||
 | 
					    if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->nextprecision = qemu_get_byte(f);
 | 
					    s->nextprecision = qemu_get_byte(f);
 | 
				
			||||||
 | 
					    if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->filter = qemu_get_byte(f);
 | 
					    s->filter = qemu_get_byte(f);
 | 
				
			||||||
    s->pin_func = qemu_get_byte(f);
 | 
					    s->pin_func = qemu_get_byte(f);
 | 
				
			||||||
    s->ref = qemu_get_byte(f);
 | 
					    s->ref = qemu_get_byte(f);
 | 
				
			||||||
 | 
				
			|||||||
@ -41,6 +41,7 @@
 | 
				
			|||||||
#include "hw/sysbus.h"
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
#include "hw/pci/msi.h"
 | 
					#include "hw/pci/msi.h"
 | 
				
			||||||
#include "qemu/bitops.h"
 | 
					#include "qemu/bitops.h"
 | 
				
			||||||
 | 
					#include "qapi/qmp/qerror.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define DEBUG_OPENPIC
 | 
					//#define DEBUG_OPENPIC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1416,7 +1417,7 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
 | 
				
			|||||||
static int openpic_load(QEMUFile* f, void *opaque, int version_id)
 | 
					static int openpic_load(QEMUFile* f, void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    OpenPICState *opp = (OpenPICState *)opaque;
 | 
					    OpenPICState *opp = (OpenPICState *)opaque;
 | 
				
			||||||
    unsigned int i;
 | 
					    unsigned int i, nb_cpus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (version_id != 1) {
 | 
					    if (version_id != 1) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
@ -1428,7 +1429,11 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
 | 
				
			|||||||
    qemu_get_be32s(f, &opp->spve);
 | 
					    qemu_get_be32s(f, &opp->spve);
 | 
				
			||||||
    qemu_get_be32s(f, &opp->tfrr);
 | 
					    qemu_get_be32s(f, &opp->tfrr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_get_be32s(f, &opp->nb_cpus);
 | 
					    qemu_get_be32s(f, &nb_cpus);
 | 
				
			||||||
 | 
					    if (opp->nb_cpus != nb_cpus) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(nb_cpus > 0 && nb_cpus <= MAX_CPU);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < opp->nb_cpus; i++) {
 | 
					    for (i = 0; i < opp->nb_cpus; i++) {
 | 
				
			||||||
        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
 | 
					        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
 | 
				
			||||||
@ -1567,6 +1572,13 @@ static void openpic_realize(DeviceState *dev, Error **errp)
 | 
				
			|||||||
        {NULL}
 | 
					        {NULL}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opp->nb_cpus > MAX_CPU) {
 | 
				
			||||||
 | 
					        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
 | 
				
			||||||
 | 
					                  TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
 | 
				
			||||||
 | 
					                  (uint64_t)0, (uint64_t)MAX_CPU);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (opp->model) {
 | 
					    switch (opp->model) {
 | 
				
			||||||
    case OPENPIC_MODEL_FSL_MPIC_20:
 | 
					    case OPENPIC_MODEL_FSL_MPIC_20:
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
 | 
				
			|||||||
@ -1362,10 +1362,17 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
        if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
 | 
					        if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
 | 
				
			||||||
            qemu_get_buffer(f, n->mac_table.macs,
 | 
					            qemu_get_buffer(f, n->mac_table.macs,
 | 
				
			||||||
                            n->mac_table.in_use * ETH_ALEN);
 | 
					                            n->mac_table.in_use * ETH_ALEN);
 | 
				
			||||||
        } else if (n->mac_table.in_use) {
 | 
					        } else {
 | 
				
			||||||
            uint8_t *buf = g_malloc0(n->mac_table.in_use);
 | 
					            int64_t i;
 | 
				
			||||||
            qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN);
 | 
					
 | 
				
			||||||
            g_free(buf);
 | 
					            /* Overflow detected - can happen if source has a larger MAC table.
 | 
				
			||||||
 | 
					             * We simply set overflow flag so there's no need to maintain the
 | 
				
			||||||
 | 
					             * table of addresses, discard them all.
 | 
				
			||||||
 | 
					             * Note: 64 bit math to avoid integer overflow.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) {
 | 
				
			||||||
 | 
					                qemu_get_byte(f);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
 | 
					            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
 | 
				
			||||||
            n->mac_table.in_use = 0;
 | 
					            n->mac_table.in_use = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1407,6 +1414,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        n->curr_queues = qemu_get_be16(f);
 | 
					        n->curr_queues = qemu_get_be16(f);
 | 
				
			||||||
 | 
					        if (n->curr_queues > n->max_queues) {
 | 
				
			||||||
 | 
					            error_report("virtio-net: curr_queues %x > max_queues %x",
 | 
				
			||||||
 | 
					                         n->curr_queues, n->max_queues);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        for (i = 1; i < n->curr_queues; i++) {
 | 
					        for (i = 1; i < n->curr_queues; i++) {
 | 
				
			||||||
            n->vqs[i].tx_waiting = qemu_get_be32(f);
 | 
					            n->vqs[i].tx_waiting = qemu_get_be32(f);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -475,7 +475,7 @@ const VMStateDescription vmstate_pci_device = {
 | 
				
			|||||||
    .minimum_version_id = 1,
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
    .minimum_version_id_old = 1,
 | 
					    .minimum_version_id_old = 1,
 | 
				
			||||||
    .fields      = (VMStateField []) {
 | 
					    .fields      = (VMStateField []) {
 | 
				
			||||||
        VMSTATE_INT32_LE(version_id, PCIDevice),
 | 
					        VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
 | 
				
			||||||
        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
					        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
				
			||||||
                                   vmstate_info_pci_config,
 | 
					                                   vmstate_info_pci_config,
 | 
				
			||||||
                                   PCI_CONFIG_SPACE_SIZE),
 | 
					                                   PCI_CONFIG_SPACE_SIZE),
 | 
				
			||||||
@ -492,7 +492,7 @@ const VMStateDescription vmstate_pcie_device = {
 | 
				
			|||||||
    .minimum_version_id = 1,
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
    .minimum_version_id_old = 1,
 | 
					    .minimum_version_id_old = 1,
 | 
				
			||||||
    .fields      = (VMStateField []) {
 | 
					    .fields      = (VMStateField []) {
 | 
				
			||||||
        VMSTATE_INT32_LE(version_id, PCIDevice),
 | 
					        VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
 | 
				
			||||||
        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
					        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
				
			||||||
                                   vmstate_info_pci_config,
 | 
					                                   vmstate_info_pci_config,
 | 
				
			||||||
                                   PCIE_CONFIG_SPACE_SIZE),
 | 
					                                   PCIE_CONFIG_SPACE_SIZE),
 | 
				
			||||||
 | 
				
			|||||||
@ -795,6 +795,13 @@ static const VMStateDescription vmstate_pcie_aer_err = {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool pcie_aer_state_log_num_valid(void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PCIEAERLog *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s->log_num <= s->log_max;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const VMStateDescription vmstate_pcie_aer_log = {
 | 
					const VMStateDescription vmstate_pcie_aer_log = {
 | 
				
			||||||
    .name = "PCIE_AER_ERROR_LOG",
 | 
					    .name = "PCIE_AER_ERROR_LOG",
 | 
				
			||||||
    .version_id = 1,
 | 
					    .version_id = 1,
 | 
				
			||||||
@ -802,7 +809,8 @@ const VMStateDescription vmstate_pcie_aer_log = {
 | 
				
			|||||||
    .minimum_version_id_old = 1,
 | 
					    .minimum_version_id_old = 1,
 | 
				
			||||||
    .fields     = (VMStateField[]) {
 | 
					    .fields     = (VMStateField[]) {
 | 
				
			||||||
        VMSTATE_UINT16(log_num, PCIEAERLog),
 | 
					        VMSTATE_UINT16(log_num, PCIEAERLog),
 | 
				
			||||||
        VMSTATE_UINT16(log_max, PCIEAERLog),
 | 
					        VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog),
 | 
				
			||||||
 | 
					        VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid),
 | 
				
			||||||
        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
 | 
					        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
 | 
				
			||||||
                              vmstate_pcie_aer_err, PCIEAERErr),
 | 
					                              vmstate_pcie_aer_err, PCIEAERErr),
 | 
				
			||||||
        VMSTATE_END_OF_LIST()
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
				
			|||||||
@ -147,6 +147,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
 | 
				
			|||||||
    qemu_get_be32s(f, &n);
 | 
					    qemu_get_be32s(f, &n);
 | 
				
			||||||
    assert(n < vs->conf.num_queues);
 | 
					    assert(n < vs->conf.num_queues);
 | 
				
			||||||
    qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
 | 
					    qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
 | 
				
			||||||
 | 
					    /* TODO: add a way for SCSIBusInfo's load_request to fail,
 | 
				
			||||||
 | 
					     * and fail migration instead of asserting here.
 | 
				
			||||||
 | 
					     * When we do, we might be able to re-enable NDEBUG below.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					#ifdef NDEBUG
 | 
				
			||||||
 | 
					#error building with NDEBUG is not supported
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg));
 | 
				
			||||||
 | 
					    assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg));
 | 
				
			||||||
    virtio_scsi_parse_req(s, vs->cmd_vqs[n], req);
 | 
					    virtio_scsi_parse_req(s, vs->cmd_vqs[n], req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scsi_req_ref(sreq);
 | 
					    scsi_req_ref(sreq);
 | 
				
			||||||
 | 
				
			|||||||
@ -230,8 +230,17 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    for (i = 0; i < 5; i++)
 | 
					    for (i = 0; i < 5; i++)
 | 
				
			||||||
        s->response[i] = qemu_get_be32(f);
 | 
					        s->response[i] = qemu_get_be32(f);
 | 
				
			||||||
    s->arglen = qemu_get_be32(f);
 | 
					    s->arglen = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->mode == SSI_SD_CMDARG &&
 | 
				
			||||||
 | 
					        (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    s->response_pos = qemu_get_be32(f);
 | 
					    s->response_pos = qemu_get_be32(f);
 | 
				
			||||||
    s->stopping = qemu_get_be32(f);
 | 
					    s->stopping = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (s->mode == SSI_SD_RESPONSE &&
 | 
				
			||||||
 | 
					        (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) ||
 | 
				
			||||||
 | 
					        (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss->cs = qemu_get_be32(f);
 | 
					    ss->cs = qemu_get_be32(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -240,11 +240,25 @@ static const MemoryRegionOps pl022_ops = {
 | 
				
			|||||||
    .endianness = DEVICE_NATIVE_ENDIAN,
 | 
					    .endianness = DEVICE_NATIVE_ENDIAN,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pl022_post_load(void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PL022State *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->tx_fifo_head < 0 ||
 | 
				
			||||||
 | 
					        s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) ||
 | 
				
			||||||
 | 
					        s->rx_fifo_head < 0 ||
 | 
				
			||||||
 | 
					        s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const VMStateDescription vmstate_pl022 = {
 | 
					static const VMStateDescription vmstate_pl022 = {
 | 
				
			||||||
    .name = "pl022_ssp",
 | 
					    .name = "pl022_ssp",
 | 
				
			||||||
    .version_id = 1,
 | 
					    .version_id = 1,
 | 
				
			||||||
    .minimum_version_id = 1,
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
    .minimum_version_id_old = 1,
 | 
					    .minimum_version_id_old = 1,
 | 
				
			||||||
 | 
					    .post_load = pl022_post_load,
 | 
				
			||||||
    .fields      = (VMStateField[]) {
 | 
					    .fields      = (VMStateField[]) {
 | 
				
			||||||
        VMSTATE_UINT32(cr0, PL022State),
 | 
					        VMSTATE_UINT32(cr0, PL022State),
 | 
				
			||||||
        VMSTATE_UINT32(cr1, PL022State),
 | 
					        VMSTATE_UINT32(cr1, PL022State),
 | 
				
			||||||
 | 
				
			|||||||
@ -239,6 +239,18 @@ static int hpet_pre_load(void *opaque)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool hpet_validate_num_timers(void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HPETState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->num_timers < HPET_MIN_TIMERS) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    } else if (s->num_timers > HPET_MAX_TIMERS) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int hpet_post_load(void *opaque, int version_id)
 | 
					static int hpet_post_load(void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HPETState *s = opaque;
 | 
					    HPETState *s = opaque;
 | 
				
			||||||
@ -307,6 +319,7 @@ static const VMStateDescription vmstate_hpet = {
 | 
				
			|||||||
        VMSTATE_UINT64(isr, HPETState),
 | 
					        VMSTATE_UINT64(isr, HPETState),
 | 
				
			||||||
        VMSTATE_UINT64(hpet_counter, HPETState),
 | 
					        VMSTATE_UINT64(hpet_counter, HPETState),
 | 
				
			||||||
        VMSTATE_UINT8_V(num_timers, HPETState, 2),
 | 
					        VMSTATE_UINT8_V(num_timers, HPETState, 2),
 | 
				
			||||||
 | 
					        VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers),
 | 
				
			||||||
        VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
 | 
					        VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
 | 
				
			||||||
                                    vmstate_hpet_timer, HPETTimer),
 | 
					                                    vmstate_hpet_timer, HPETTimer),
 | 
				
			||||||
        VMSTATE_END_OF_LIST()
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,9 @@ static int usb_device_post_load(void *opaque, int version_id)
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        dev->attached = 1;
 | 
					        dev->attached = 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (dev->setup_index >= sizeof(dev->data_buf) ||
 | 
					    if (dev->setup_index < 0 ||
 | 
				
			||||||
 | 
					        dev->setup_len < 0 ||
 | 
				
			||||||
 | 
					        dev->setup_index >= sizeof(dev->data_buf) ||
 | 
				
			||||||
        dev->setup_len >= sizeof(dev->data_buf)) {
 | 
					        dev->setup_len >= sizeof(dev->data_buf)) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -430,6 +430,12 @@ void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
 | 
				
			|||||||
    unsigned int i;
 | 
					    unsigned int i;
 | 
				
			||||||
    hwaddr len;
 | 
					    hwaddr len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (num_sg >= VIRTQUEUE_MAX_SIZE) {
 | 
				
			||||||
 | 
					        error_report("virtio: map attempt out of bounds: %zd > %d",
 | 
				
			||||||
 | 
					                     num_sg, VIRTQUEUE_MAX_SIZE);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < num_sg; i++) {
 | 
					    for (i = 0; i < num_sg; i++) {
 | 
				
			||||||
        len = sg[i].iov_len;
 | 
					        len = sg[i].iov_len;
 | 
				
			||||||
        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
 | 
					        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
 | 
				
			||||||
@ -891,7 +897,9 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 | 
					int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int num, i, ret;
 | 
					    int i, ret;
 | 
				
			||||||
 | 
					    int32_t config_len;
 | 
				
			||||||
 | 
					    uint32_t num;
 | 
				
			||||||
    uint32_t features;
 | 
					    uint32_t features;
 | 
				
			||||||
    uint32_t supported_features;
 | 
					    uint32_t supported_features;
 | 
				
			||||||
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
 | 
					    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
 | 
				
			||||||
@ -906,6 +914,9 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 | 
				
			|||||||
    qemu_get_8s(f, &vdev->status);
 | 
					    qemu_get_8s(f, &vdev->status);
 | 
				
			||||||
    qemu_get_8s(f, &vdev->isr);
 | 
					    qemu_get_8s(f, &vdev->isr);
 | 
				
			||||||
    qemu_get_be16s(f, &vdev->queue_sel);
 | 
					    qemu_get_be16s(f, &vdev->queue_sel);
 | 
				
			||||||
 | 
					    if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    qemu_get_be32s(f, &features);
 | 
					    qemu_get_be32s(f, &features);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (virtio_set_features(vdev, features) < 0) {
 | 
					    if (virtio_set_features(vdev, features) < 0) {
 | 
				
			||||||
@ -914,11 +925,21 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 | 
				
			|||||||
                     features, supported_features);
 | 
					                     features, supported_features);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vdev->config_len = qemu_get_be32(f);
 | 
					    config_len = qemu_get_be32(f);
 | 
				
			||||||
 | 
					    if (config_len != vdev->config_len) {
 | 
				
			||||||
 | 
					        error_report("Unexpected config length 0x%x. Expected 0x%zx",
 | 
				
			||||||
 | 
					                     config_len, vdev->config_len);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    qemu_get_buffer(f, vdev->config, vdev->config_len);
 | 
					    qemu_get_buffer(f, vdev->config, vdev->config_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    num = qemu_get_be32(f);
 | 
					    num = qemu_get_be32(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (num > VIRTIO_PCI_QUEUE_MAX) {
 | 
				
			||||||
 | 
					        error_report("Invalid number of PCI queues: 0x%x", num);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < num; i++) {
 | 
					    for (i = 0; i < num; i++) {
 | 
				
			||||||
        vdev->vq[i].vring.num = qemu_get_be32(f);
 | 
					        vdev->vq[i].vring.num = qemu_get_be32(f);
 | 
				
			||||||
        if (k->has_variable_vring_alignment) {
 | 
					        if (k->has_variable_vring_alignment) {
 | 
				
			||||||
 | 
				
			|||||||
@ -176,8 +176,8 @@ typedef struct VirtIONet {
 | 
				
			|||||||
    uint8_t nobcast;
 | 
					    uint8_t nobcast;
 | 
				
			||||||
    uint8_t vhost_started;
 | 
					    uint8_t vhost_started;
 | 
				
			||||||
    struct {
 | 
					    struct {
 | 
				
			||||||
        int in_use;
 | 
					        uint32_t in_use;
 | 
				
			||||||
        int first_multi;
 | 
					        uint32_t first_multi;
 | 
				
			||||||
        uint8_t multi_overflow;
 | 
					        uint8_t multi_overflow;
 | 
				
			||||||
        uint8_t uni_overflow;
 | 
					        uint8_t uni_overflow;
 | 
				
			||||||
        uint8_t *macs;
 | 
					        uint8_t *macs;
 | 
				
			||||||
 | 
				
			|||||||
@ -61,6 +61,7 @@ struct MigrationState
 | 
				
			|||||||
    bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
 | 
					    bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
 | 
				
			||||||
    int64_t xbzrle_cache_size;
 | 
					    int64_t xbzrle_cache_size;
 | 
				
			||||||
    int64_t setup_time;
 | 
					    int64_t setup_time;
 | 
				
			||||||
 | 
					    int64_t dirty_sync_count;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_incoming_migration(QEMUFile *f);
 | 
					void process_incoming_migration(QEMUFile *f);
 | 
				
			||||||
@ -113,8 +114,6 @@ 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern SaveVMHandlers savevm_ram_handlers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint64_t dup_mig_bytes_transferred(void);
 | 
					uint64_t dup_mig_bytes_transferred(void);
 | 
				
			||||||
uint64_t dup_mig_pages_transferred(void);
 | 
					uint64_t dup_mig_pages_transferred(void);
 | 
				
			||||||
uint64_t skipped_mig_bytes_transferred(void);
 | 
					uint64_t skipped_mig_bytes_transferred(void);
 | 
				
			||||||
@ -125,6 +124,7 @@ uint64_t xbzrle_mig_bytes_transferred(void);
 | 
				
			|||||||
uint64_t xbzrle_mig_pages_transferred(void);
 | 
					uint64_t xbzrle_mig_pages_transferred(void);
 | 
				
			||||||
uint64_t xbzrle_mig_pages_overflow(void);
 | 
					uint64_t xbzrle_mig_pages_overflow(void);
 | 
				
			||||||
uint64_t xbzrle_mig_pages_cache_miss(void);
 | 
					uint64_t xbzrle_mig_pages_cache_miss(void);
 | 
				
			||||||
 | 
					double xbzrle_mig_cache_miss_rate(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
 | 
					void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -123,6 +123,11 @@ void qemu_put_be32(QEMUFile *f, unsigned int v);
 | 
				
			|||||||
void qemu_put_be64(QEMUFile *f, uint64_t v);
 | 
					void qemu_put_be64(QEMUFile *f, uint64_t v);
 | 
				
			||||||
int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset);
 | 
					int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset);
 | 
				
			||||||
int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
 | 
					int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Note that you can only peek continuous bytes from where the current pointer
 | 
				
			||||||
 | 
					 * is; you aren't guaranteed to be able to peak to +n bytes unless you've
 | 
				
			||||||
 | 
					 * previously peeked +n-1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int qemu_peek_byte(QEMUFile *f, int offset);
 | 
					int qemu_peek_byte(QEMUFile *f, int offset);
 | 
				
			||||||
int qemu_get_byte(QEMUFile *f);
 | 
					int qemu_get_byte(QEMUFile *f);
 | 
				
			||||||
void qemu_file_skip(QEMUFile *f, int size);
 | 
					void qemu_file_skip(QEMUFile *f, int size);
 | 
				
			||||||
 | 
				
			|||||||
@ -100,6 +100,7 @@ enum VMStateFlags {
 | 
				
			|||||||
    VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
 | 
					    VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
 | 
				
			||||||
    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
 | 
					    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
 | 
				
			||||||
    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
 | 
					    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
 | 
				
			||||||
 | 
					    VMS_MUST_EXIST       = 0x1000, /* Field must exist in input */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
@ -203,6 +204,14 @@ extern const VMStateInfo vmstate_info_bitmap;
 | 
				
			|||||||
    .offset       = vmstate_offset_value(_state, _field, _type),     \
 | 
					    .offset       = vmstate_offset_value(_state, _field, _type),     \
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Validate state using a boolean predicate. */
 | 
				
			||||||
 | 
					#define VMSTATE_VALIDATE(_name, _test) { \
 | 
				
			||||||
 | 
					    .name         = (_name),                                         \
 | 
				
			||||||
 | 
					    .field_exists = (_test),                                         \
 | 
				
			||||||
 | 
					    .flags        = VMS_ARRAY | VMS_MUST_EXIST,                      \
 | 
				
			||||||
 | 
					    .num          = 0, /* 0 elements: no data, only run _test */     \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VMSTATE_POINTER(_field, _state, _version, _info, _type) {    \
 | 
					#define VMSTATE_POINTER(_field, _state, _version, _info, _type) {    \
 | 
				
			||||||
    .name       = (stringify(_field)),                               \
 | 
					    .name       = (stringify(_field)),                               \
 | 
				
			||||||
    .version_id = (_version),                                        \
 | 
					    .version_id = (_version),                                        \
 | 
				
			||||||
@ -592,7 +601,7 @@ extern const VMStateInfo vmstate_info_bitmap;
 | 
				
			|||||||
#define VMSTATE_UINT64_EQUAL(_f, _s)                                  \
 | 
					#define VMSTATE_UINT64_EQUAL(_f, _s)                                  \
 | 
				
			||||||
    VMSTATE_UINT64_EQUAL_V(_f, _s, 0)
 | 
					    VMSTATE_UINT64_EQUAL_V(_f, _s, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VMSTATE_INT32_LE(_f, _s)                                   \
 | 
					#define VMSTATE_INT32_POSITIVE_LE(_f, _s)                             \
 | 
				
			||||||
    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
 | 
					    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
 | 
					#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ extern const uint32_t arch_type;
 | 
				
			|||||||
void select_soundhw(const char *optarg);
 | 
					void select_soundhw(const char *optarg);
 | 
				
			||||||
void do_acpitable_option(const QemuOpts *opts);
 | 
					void do_acpitable_option(const QemuOpts *opts);
 | 
				
			||||||
void do_smbios_option(QemuOpts *opts);
 | 
					void do_smbios_option(QemuOpts *opts);
 | 
				
			||||||
 | 
					void ram_mig_init(void);
 | 
				
			||||||
void cpudef_init(void);
 | 
					void cpudef_init(void);
 | 
				
			||||||
void audio_init(void);
 | 
					void audio_init(void);
 | 
				
			||||||
int tcg_available(void);
 | 
					int tcg_available(void);
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,10 @@
 | 
				
			|||||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
					 * GNU GPL, version 2 or (at your option) any later version.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "qemu/error-report.h"
 | 
				
			||||||
#include "qemu/sockets.h"
 | 
					#include "qemu/sockets.h"
 | 
				
			||||||
#include "migration/migration.h"
 | 
					#include "migration/migration.h"
 | 
				
			||||||
#include "migration/qemu-file.h"
 | 
					#include "migration/qemu-file.h"
 | 
				
			||||||
@ -56,24 +59,26 @@ static void tcp_accept_incoming_migration(void *opaque)
 | 
				
			|||||||
    socklen_t addrlen = sizeof(addr);
 | 
					    socklen_t addrlen = sizeof(addr);
 | 
				
			||||||
    int s = (intptr_t)opaque;
 | 
					    int s = (intptr_t)opaque;
 | 
				
			||||||
    QEMUFile *f;
 | 
					    QEMUFile *f;
 | 
				
			||||||
    int c;
 | 
					    int c, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
 | 
					        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
 | 
				
			||||||
    } while (c == -1 && socket_error() == EINTR);
 | 
					        err = socket_error();
 | 
				
			||||||
 | 
					    } while (c < 0 && err == EINTR);
 | 
				
			||||||
    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
 | 
					    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
 | 
				
			||||||
    closesocket(s);
 | 
					    closesocket(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("accepted migration\n");
 | 
					    DPRINTF("accepted migration\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (c == -1) {
 | 
					    if (c < 0) {
 | 
				
			||||||
        fprintf(stderr, "could not accept migration connection\n");
 | 
					        error_report("could not accept migration connection (%s)",
 | 
				
			||||||
        goto out;
 | 
					                     strerror(err));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    f = qemu_fopen_socket(c, "rb");
 | 
					    f = qemu_fopen_socket(c, "rb");
 | 
				
			||||||
    if (f == NULL) {
 | 
					    if (f == NULL) {
 | 
				
			||||||
        fprintf(stderr, "could not qemu_fopen socket\n");
 | 
					        error_report("could not qemu_fopen socket");
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,10 @@
 | 
				
			|||||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
					 * GNU GPL, version 2 or (at your option) any later version.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "qemu/error-report.h"
 | 
				
			||||||
#include "qemu/sockets.h"
 | 
					#include "qemu/sockets.h"
 | 
				
			||||||
#include "qemu/main-loop.h"
 | 
					#include "qemu/main-loop.h"
 | 
				
			||||||
#include "migration/migration.h"
 | 
					#include "migration/migration.h"
 | 
				
			||||||
@ -56,24 +59,26 @@ static void unix_accept_incoming_migration(void *opaque)
 | 
				
			|||||||
    socklen_t addrlen = sizeof(addr);
 | 
					    socklen_t addrlen = sizeof(addr);
 | 
				
			||||||
    int s = (intptr_t)opaque;
 | 
					    int s = (intptr_t)opaque;
 | 
				
			||||||
    QEMUFile *f;
 | 
					    QEMUFile *f;
 | 
				
			||||||
    int c;
 | 
					    int c, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
 | 
					        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
 | 
				
			||||||
    } while (c == -1 && errno == EINTR);
 | 
					        err = errno;
 | 
				
			||||||
 | 
					    } while (c < 0 && err == EINTR);
 | 
				
			||||||
    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
 | 
					    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
 | 
				
			||||||
    close(s);
 | 
					    close(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("accepted migration\n");
 | 
					    DPRINTF("accepted migration\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (c == -1) {
 | 
					    if (c < 0) {
 | 
				
			||||||
        fprintf(stderr, "could not accept migration connection\n");
 | 
					        error_report("could not accept migration connection (%s)",
 | 
				
			||||||
        goto out;
 | 
					                     strerror(err));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    f = qemu_fopen_socket(c, "rb");
 | 
					    f = qemu_fopen_socket(c, "rb");
 | 
				
			||||||
    if (f == NULL) {
 | 
					    if (f == NULL) {
 | 
				
			||||||
        fprintf(stderr, "could not qemu_fopen socket\n");
 | 
					        error_report("could not qemu_fopen socket");
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -174,6 +174,7 @@ static void get_xbzrle_cache_stats(MigrationInfo *info)
 | 
				
			|||||||
        info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
 | 
					        info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
 | 
				
			||||||
        info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
 | 
					        info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
 | 
				
			||||||
        info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
 | 
					        info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
 | 
				
			||||||
 | 
					        info->xbzrle_cache->cache_miss_rate = xbzrle_mig_cache_miss_rate();
 | 
				
			||||||
        info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
 | 
					        info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -215,6 +216,7 @@ MigrationInfo *qmp_query_migrate(Error **errp)
 | 
				
			|||||||
        info->ram->normal_bytes = norm_mig_bytes_transferred();
 | 
					        info->ram->normal_bytes = norm_mig_bytes_transferred();
 | 
				
			||||||
        info->ram->dirty_pages_rate = s->dirty_pages_rate;
 | 
					        info->ram->dirty_pages_rate = s->dirty_pages_rate;
 | 
				
			||||||
        info->ram->mbps = s->mbps;
 | 
					        info->ram->mbps = s->mbps;
 | 
				
			||||||
 | 
					        info->ram->dirty_sync_count = s->dirty_sync_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (blk_mig_active()) {
 | 
					        if (blk_mig_active()) {
 | 
				
			||||||
            info->has_disk = true;
 | 
					            info->has_disk = true;
 | 
				
			||||||
@ -248,6 +250,7 @@ MigrationInfo *qmp_query_migrate(Error **errp)
 | 
				
			|||||||
        info->ram->normal = norm_mig_pages_transferred();
 | 
					        info->ram->normal = norm_mig_pages_transferred();
 | 
				
			||||||
        info->ram->normal_bytes = norm_mig_bytes_transferred();
 | 
					        info->ram->normal_bytes = norm_mig_bytes_transferred();
 | 
				
			||||||
        info->ram->mbps = s->mbps;
 | 
					        info->ram->mbps = s->mbps;
 | 
				
			||||||
 | 
					        info->ram->dirty_sync_count = s->dirty_sync_count;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case MIG_STATE_ERROR:
 | 
					    case MIG_STATE_ERROR:
 | 
				
			||||||
        info->has_status = true;
 | 
					        info->has_status = true;
 | 
				
			||||||
@ -419,6 +422,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (runstate_check(RUN_STATE_INMIGRATE)) {
 | 
				
			||||||
 | 
					        error_setg(errp, "Guest is waiting for an incoming migration");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (qemu_savevm_state_blocked(errp)) {
 | 
					    if (qemu_savevm_state_blocked(errp)) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -651,13 +651,15 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# @mbps: throughput in megabits/sec. (since 1.6)
 | 
					# @mbps: throughput in megabits/sec. (since 1.6)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# @dirty-sync-count: number of times that dirty ram was synchronized (since 2.1)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# Since: 0.14.0
 | 
					# Since: 0.14.0
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
{ 'type': 'MigrationStats',
 | 
					{ 'type': 'MigrationStats',
 | 
				
			||||||
  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
 | 
					  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
 | 
				
			||||||
           'duplicate': 'int', 'skipped': 'int', 'normal': 'int',
 | 
					           'duplicate': 'int', 'skipped': 'int', 'normal': 'int',
 | 
				
			||||||
           'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
 | 
					           'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
 | 
				
			||||||
           'mbps' : 'number' } }
 | 
					           'mbps' : 'number', 'dirty-sync-count' : 'int' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
# @XBZRLECacheStats
 | 
					# @XBZRLECacheStats
 | 
				
			||||||
@ -672,13 +674,16 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# @cache-miss: number of cache miss
 | 
					# @cache-miss: number of cache miss
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# @cache-miss-rate: rate of cache miss (since 2.1)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# @overflow: number of overflows
 | 
					# @overflow: number of overflows
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Since: 1.2
 | 
					# Since: 1.2
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
{ 'type': 'XBZRLECacheStats',
 | 
					{ 'type': 'XBZRLECacheStats',
 | 
				
			||||||
  'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
 | 
					  'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
 | 
				
			||||||
           'cache-miss': 'int', 'overflow': 'int' } }
 | 
					           'cache-miss': 'int', 'cache-miss-rate': 'number',
 | 
				
			||||||
 | 
					           'overflow': 'int' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
# @MigrationInfo
 | 
					# @MigrationInfo
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										53
									
								
								qemu-file.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								qemu-file.c
									
									
									
									
									
								
							@ -530,7 +530,15 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
 | 
				
			|||||||
    return RAM_SAVE_CONTROL_NOT_SUPP;
 | 
					    return RAM_SAVE_CONTROL_NOT_SUPP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void qemu_fill_buffer(QEMUFile *f)
 | 
					/*
 | 
				
			||||||
 | 
					 * Attempt to fill the buffer from the underlying file
 | 
				
			||||||
 | 
					 * Returns the number of bytes read, or negative value for an error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that it can return a partially full buffer even in a not error/not EOF
 | 
				
			||||||
 | 
					 * case if the underlying file descriptor gives a short read, and that can
 | 
				
			||||||
 | 
					 * happen even on a blocking fd.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static ssize_t qemu_fill_buffer(QEMUFile *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int len;
 | 
					    int len;
 | 
				
			||||||
    int pending;
 | 
					    int pending;
 | 
				
			||||||
@ -554,6 +562,8 @@ static void qemu_fill_buffer(QEMUFile *f)
 | 
				
			|||||||
    } else if (len != -EAGAIN) {
 | 
					    } else if (len != -EAGAIN) {
 | 
				
			||||||
        qemu_file_set_error(f, len);
 | 
					        qemu_file_set_error(f, len);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qemu_get_fd(QEMUFile *f)
 | 
					int qemu_get_fd(QEMUFile *f)
 | 
				
			||||||
@ -685,17 +695,39 @@ void qemu_file_skip(QEMUFile *f, int size)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Read 'size' bytes from file (at 'offset') into buf without moving the
 | 
				
			||||||
 | 
					 * pointer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It will return size bytes unless there was an error, in which case it will
 | 
				
			||||||
 | 
					 * return as many as it managed to read (assuming blocking fd's which
 | 
				
			||||||
 | 
					 * all current QEMUFile are)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
 | 
					int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int pending;
 | 
					    int pending;
 | 
				
			||||||
    int index;
 | 
					    int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(!qemu_file_is_writable(f));
 | 
					    assert(!qemu_file_is_writable(f));
 | 
				
			||||||
 | 
					    assert(offset < IO_BUF_SIZE);
 | 
				
			||||||
 | 
					    assert(size <= IO_BUF_SIZE - offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* The 1st byte to read from */
 | 
				
			||||||
    index = f->buf_index + offset;
 | 
					    index = f->buf_index + offset;
 | 
				
			||||||
 | 
					    /* The number of available bytes starting at index */
 | 
				
			||||||
    pending = f->buf_size - index;
 | 
					    pending = f->buf_size - index;
 | 
				
			||||||
    if (pending < size) {
 | 
					
 | 
				
			||||||
        qemu_fill_buffer(f);
 | 
					    /*
 | 
				
			||||||
 | 
					     * qemu_fill_buffer might return just a few bytes, even when there isn't
 | 
				
			||||||
 | 
					     * an error, so loop collecting them until we get enough.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    while (pending < size) {
 | 
				
			||||||
 | 
					        int received = qemu_fill_buffer(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (received <= 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        index = f->buf_index + offset;
 | 
					        index = f->buf_index + offset;
 | 
				
			||||||
        pending = f->buf_size - index;
 | 
					        pending = f->buf_size - index;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -711,6 +743,14 @@ int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
 | 
				
			|||||||
    return size;
 | 
					    return size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Read 'size' bytes of data from the file into buf.
 | 
				
			||||||
 | 
					 * 'size' can be larger than the internal buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It will return size bytes unless there was an error, in which case it will
 | 
				
			||||||
 | 
					 * return as many as it managed to read (assuming blocking fd's which
 | 
				
			||||||
 | 
					 * all current QEMUFile are)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
 | 
					int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int pending = size;
 | 
					    int pending = size;
 | 
				
			||||||
@ -719,7 +759,7 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
 | 
				
			|||||||
    while (pending > 0) {
 | 
					    while (pending > 0) {
 | 
				
			||||||
        int res;
 | 
					        int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        res = qemu_peek_buffer(f, buf, pending, 0);
 | 
					        res = qemu_peek_buffer(f, buf, MIN(pending, IO_BUF_SIZE), 0);
 | 
				
			||||||
        if (res == 0) {
 | 
					        if (res == 0) {
 | 
				
			||||||
            return done;
 | 
					            return done;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -731,11 +771,16 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
 | 
				
			|||||||
    return done;
 | 
					    return done;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Peeks a single byte from the buffer; this isn't guaranteed to work if
 | 
				
			||||||
 | 
					 * offset leaves a gap after the previous read/peeked data.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int qemu_peek_byte(QEMUFile *f, int offset)
 | 
					int qemu_peek_byte(QEMUFile *f, int offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int index = f->buf_index + offset;
 | 
					    int index = f->buf_index + offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(!qemu_file_is_writable(f));
 | 
					    assert(!qemu_file_is_writable(f));
 | 
				
			||||||
 | 
					    assert(offset < IO_BUF_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (index >= f->buf_size) {
 | 
					    if (index >= f->buf_size) {
 | 
				
			||||||
        qemu_fill_buffer(f);
 | 
					        qemu_fill_buffer(f);
 | 
				
			||||||
 | 
				
			|||||||
@ -2967,6 +2967,7 @@ The main json-object contains the following:
 | 
				
			|||||||
            pages. This is just normal pages times size of one page,
 | 
					            pages. This is just normal pages times size of one page,
 | 
				
			||||||
            but this way upper levels don't need to care about page
 | 
					            but this way upper levels don't need to care about page
 | 
				
			||||||
            size (json-int)
 | 
					            size (json-int)
 | 
				
			||||||
 | 
					         - "dirty-sync-count": times that dirty ram was synchronized (json-int)
 | 
				
			||||||
- "disk": only present if "status" is "active" and it is a block migration,
 | 
					- "disk": only present if "status" is "active" and it is a block migration,
 | 
				
			||||||
  it is a json-object with the following disk information:
 | 
					  it is a json-object with the following disk information:
 | 
				
			||||||
         - "transferred": amount transferred in bytes (json-int)
 | 
					         - "transferred": amount transferred in bytes (json-int)
 | 
				
			||||||
@ -2978,6 +2979,7 @@ The main json-object contains the following:
 | 
				
			|||||||
         - "bytes": number of bytes transferred for XBZRLE compressed pages
 | 
					         - "bytes": number of bytes transferred for XBZRLE compressed pages
 | 
				
			||||||
         - "pages": number of XBZRLE compressed pages
 | 
					         - "pages": number of XBZRLE compressed pages
 | 
				
			||||||
         - "cache-miss": number of XBRZRLE page cache misses
 | 
					         - "cache-miss": number of XBRZRLE page cache misses
 | 
				
			||||||
 | 
					         - "cache-miss-rate": rate of XBRZRLE page cache misses
 | 
				
			||||||
         - "overflow": number of times XBZRLE overflows.  This means
 | 
					         - "overflow": number of times XBZRLE overflows.  This means
 | 
				
			||||||
           that the XBZRLE encoding was bigger than just sent the
 | 
					           that the XBZRLE encoding was bigger than just sent the
 | 
				
			||||||
           whole page, and then we sent the whole page instead (as as
 | 
					           whole page, and then we sent the whole page instead (as as
 | 
				
			||||||
@ -3004,7 +3006,8 @@ Examples:
 | 
				
			|||||||
          "downtime":12345,
 | 
					          "downtime":12345,
 | 
				
			||||||
          "duplicate":123,
 | 
					          "duplicate":123,
 | 
				
			||||||
          "normal":123,
 | 
					          "normal":123,
 | 
				
			||||||
          "normal-bytes":123456
 | 
					          "normal-bytes":123456,
 | 
				
			||||||
 | 
					          "dirty-sync-count":15
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
@ -3029,7 +3032,8 @@ Examples:
 | 
				
			|||||||
            "expected-downtime":12345,
 | 
					            "expected-downtime":12345,
 | 
				
			||||||
            "duplicate":123,
 | 
					            "duplicate":123,
 | 
				
			||||||
            "normal":123,
 | 
					            "normal":123,
 | 
				
			||||||
            "normal-bytes":123456
 | 
					            "normal-bytes":123456,
 | 
				
			||||||
 | 
					            "dirty-sync-count":15
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
@ -3049,7 +3053,8 @@ Examples:
 | 
				
			|||||||
            "expected-downtime":12345,
 | 
					            "expected-downtime":12345,
 | 
				
			||||||
            "duplicate":123,
 | 
					            "duplicate":123,
 | 
				
			||||||
            "normal":123,
 | 
					            "normal":123,
 | 
				
			||||||
            "normal-bytes":123456
 | 
					            "normal-bytes":123456,
 | 
				
			||||||
 | 
					            "dirty-sync-count":15
 | 
				
			||||||
         },
 | 
					         },
 | 
				
			||||||
         "disk":{
 | 
					         "disk":{
 | 
				
			||||||
            "total":20971520,
 | 
					            "total":20971520,
 | 
				
			||||||
@ -3075,13 +3080,15 @@ Examples:
 | 
				
			|||||||
            "expected-downtime":12345,
 | 
					            "expected-downtime":12345,
 | 
				
			||||||
            "duplicate":10,
 | 
					            "duplicate":10,
 | 
				
			||||||
            "normal":3333,
 | 
					            "normal":3333,
 | 
				
			||||||
            "normal-bytes":3412992
 | 
					            "normal-bytes":3412992,
 | 
				
			||||||
 | 
					            "dirty-sync-count":15
 | 
				
			||||||
         },
 | 
					         },
 | 
				
			||||||
         "xbzrle-cache":{
 | 
					         "xbzrle-cache":{
 | 
				
			||||||
            "cache-size":67108864,
 | 
					            "cache-size":67108864,
 | 
				
			||||||
            "bytes":20971520,
 | 
					            "bytes":20971520,
 | 
				
			||||||
            "pages":2444343,
 | 
					            "pages":2444343,
 | 
				
			||||||
            "cache-miss":2244,
 | 
					            "cache-miss":2244,
 | 
				
			||||||
 | 
					            "cache-miss-rate":0.123,
 | 
				
			||||||
            "overflow":34434
 | 
					            "overflow":34434
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -248,7 +248,7 @@ const VMStateDescription vmstate_arm_cpu = {
 | 
				
			|||||||
        /* The length-check must come before the arrays to avoid
 | 
					        /* The length-check must come before the arrays to avoid
 | 
				
			||||||
         * incoming data possibly overflowing the array.
 | 
					         * incoming data possibly overflowing the array.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU),
 | 
					        VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU),
 | 
				
			||||||
        VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
 | 
					        VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
 | 
				
			||||||
                             cpreg_vmstate_array_len,
 | 
					                             cpreg_vmstate_array_len,
 | 
				
			||||||
                             0, vmstate_info_uint64, uint64_t),
 | 
					                             0, vmstate_info_uint64, uint64_t),
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								vl.c
									
									
									
									
									
								
							@ -4322,6 +4322,7 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
    cpu_exec_init_all();
 | 
					    cpu_exec_init_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk_mig_init();
 | 
					    blk_mig_init();
 | 
				
			||||||
 | 
					    ram_mig_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* open the virtual block devices */
 | 
					    /* open the virtual block devices */
 | 
				
			||||||
    if (snapshot)
 | 
					    if (snapshot)
 | 
				
			||||||
@ -4336,8 +4337,6 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
    default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);
 | 
					    default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);
 | 
				
			||||||
    default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);
 | 
					    default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (nb_numa_nodes > 0) {
 | 
					    if (nb_numa_nodes > 0) {
 | 
				
			||||||
        int i;
 | 
					        int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										122
									
								
								vmstate.c
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								vmstate.c
									
									
									
									
									
								
							@ -10,6 +10,50 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
 | 
					static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			||||||
                                   void *opaque);
 | 
					                                   void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vmstate_n_elems(void *opaque, VMStateField *field)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int n_elems = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (field->flags & VMS_ARRAY) {
 | 
				
			||||||
 | 
					        n_elems = field->num;
 | 
				
			||||||
 | 
					    } else if (field->flags & VMS_VARRAY_INT32) {
 | 
				
			||||||
 | 
					        n_elems = *(int32_t *)(opaque+field->num_offset);
 | 
				
			||||||
 | 
					    } else if (field->flags & VMS_VARRAY_UINT32) {
 | 
				
			||||||
 | 
					        n_elems = *(uint32_t *)(opaque+field->num_offset);
 | 
				
			||||||
 | 
					    } else if (field->flags & VMS_VARRAY_UINT16) {
 | 
				
			||||||
 | 
					        n_elems = *(uint16_t *)(opaque+field->num_offset);
 | 
				
			||||||
 | 
					    } else if (field->flags & VMS_VARRAY_UINT8) {
 | 
				
			||||||
 | 
					        n_elems = *(uint8_t *)(opaque+field->num_offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return n_elems;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vmstate_size(void *opaque, VMStateField *field)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int size = field->size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (field->flags & VMS_VBUFFER) {
 | 
				
			||||||
 | 
					        size = *(int32_t *)(opaque+field->size_offset);
 | 
				
			||||||
 | 
					        if (field->flags & VMS_MULTIPLY) {
 | 
				
			||||||
 | 
					            size *= field->size;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *vmstate_base_addr(void *opaque, VMStateField *field)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void *base_addr = opaque + field->offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (field->flags & VMS_POINTER) {
 | 
				
			||||||
 | 
					        base_addr = *(void **)base_addr + field->start;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return base_addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
					int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			||||||
                       void *opaque, int version_id)
 | 
					                       void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -19,11 +63,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
    if (version_id > vmsd->version_id) {
 | 
					    if (version_id > vmsd->version_id) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (version_id < vmsd->minimum_version_id_old) {
 | 
					 | 
				
			||||||
        return -EINVAL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if  (version_id < vmsd->minimum_version_id) {
 | 
					    if  (version_id < vmsd->minimum_version_id) {
 | 
				
			||||||
        return vmsd->load_state_old(f, opaque, version_id);
 | 
					        if (vmsd->load_state_old &&
 | 
				
			||||||
 | 
					            version_id >= vmsd->minimum_version_id_old) {
 | 
				
			||||||
 | 
					            return vmsd->load_state_old(f, opaque, version_id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (vmsd->pre_load) {
 | 
					    if (vmsd->pre_load) {
 | 
				
			||||||
        int ret = vmsd->pre_load(opaque);
 | 
					        int ret = vmsd->pre_load(opaque);
 | 
				
			||||||
@ -36,30 +81,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
             field->field_exists(opaque, version_id)) ||
 | 
					             field->field_exists(opaque, version_id)) ||
 | 
				
			||||||
            (!field->field_exists &&
 | 
					            (!field->field_exists &&
 | 
				
			||||||
             field->version_id <= version_id)) {
 | 
					             field->version_id <= version_id)) {
 | 
				
			||||||
            void *base_addr = opaque + field->offset;
 | 
					            void *base_addr = vmstate_base_addr(opaque, field);
 | 
				
			||||||
            int i, n_elems = 1;
 | 
					            int i, n_elems = vmstate_n_elems(opaque, field);
 | 
				
			||||||
            int size = field->size;
 | 
					            int size = vmstate_size(opaque, field);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (field->flags & VMS_VBUFFER) {
 | 
					 | 
				
			||||||
                size = *(int32_t *)(opaque+field->size_offset);
 | 
					 | 
				
			||||||
                if (field->flags & VMS_MULTIPLY) {
 | 
					 | 
				
			||||||
                    size *= field->size;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (field->flags & VMS_ARRAY) {
 | 
					 | 
				
			||||||
                n_elems = field->num;
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_INT32) {
 | 
					 | 
				
			||||||
                n_elems = *(int32_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT32) {
 | 
					 | 
				
			||||||
                n_elems = *(uint32_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT16) {
 | 
					 | 
				
			||||||
                n_elems = *(uint16_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT8) {
 | 
					 | 
				
			||||||
                n_elems = *(uint8_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (field->flags & VMS_POINTER) {
 | 
					 | 
				
			||||||
                base_addr = *(void **)base_addr + field->start;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            for (i = 0; i < n_elems; i++) {
 | 
					            for (i = 0; i < n_elems; i++) {
 | 
				
			||||||
                void *addr = base_addr + size * i;
 | 
					                void *addr = base_addr + size * i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -78,6 +103,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
                    return ret;
 | 
					                    return ret;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (field->flags & VMS_MUST_EXIST) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Input validation failed: %s/%s\n",
 | 
				
			||||||
 | 
					                    vmsd->name, field->name);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        field++;
 | 
					        field++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -102,30 +131,10 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
    while (field->name) {
 | 
					    while (field->name) {
 | 
				
			||||||
        if (!field->field_exists ||
 | 
					        if (!field->field_exists ||
 | 
				
			||||||
            field->field_exists(opaque, vmsd->version_id)) {
 | 
					            field->field_exists(opaque, vmsd->version_id)) {
 | 
				
			||||||
            void *base_addr = opaque + field->offset;
 | 
					            void *base_addr = vmstate_base_addr(opaque, field);
 | 
				
			||||||
            int i, n_elems = 1;
 | 
					            int i, n_elems = vmstate_n_elems(opaque, field);
 | 
				
			||||||
            int size = field->size;
 | 
					            int size = vmstate_size(opaque, field);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (field->flags & VMS_VBUFFER) {
 | 
					 | 
				
			||||||
                size = *(int32_t *)(opaque+field->size_offset);
 | 
					 | 
				
			||||||
                if (field->flags & VMS_MULTIPLY) {
 | 
					 | 
				
			||||||
                    size *= field->size;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (field->flags & VMS_ARRAY) {
 | 
					 | 
				
			||||||
                n_elems = field->num;
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_INT32) {
 | 
					 | 
				
			||||||
                n_elems = *(int32_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT32) {
 | 
					 | 
				
			||||||
                n_elems = *(uint32_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT16) {
 | 
					 | 
				
			||||||
                n_elems = *(uint16_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            } else if (field->flags & VMS_VARRAY_UINT8) {
 | 
					 | 
				
			||||||
                n_elems = *(uint8_t *)(opaque+field->num_offset);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (field->flags & VMS_POINTER) {
 | 
					 | 
				
			||||||
                base_addr = *(void **)base_addr + field->start;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            for (i = 0; i < n_elems; i++) {
 | 
					            for (i = 0; i < n_elems; i++) {
 | 
				
			||||||
                void *addr = base_addr + size * i;
 | 
					                void *addr = base_addr + size * i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -138,6 +147,12 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
 | 
				
			|||||||
                    field->info->put(f, addr, size);
 | 
					                    field->info->put(f, addr, size);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (field->flags & VMS_MUST_EXIST) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Output state validation failed: %s/%s\n",
 | 
				
			||||||
 | 
					                        vmsd->name, field->name);
 | 
				
			||||||
 | 
					                assert(!(field->flags & VMS_MUST_EXIST));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        field++;
 | 
					        field++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -323,8 +338,9 @@ const VMStateInfo vmstate_info_int32_equal = {
 | 
				
			|||||||
    .put  = put_int32,
 | 
					    .put  = put_int32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 32 bit int. Check that the received value is less than or equal to
 | 
					/* 32 bit int. Check that the received value is non-negative
 | 
				
			||||||
   the one in the field */
 | 
					 * and less than or equal to the one in the field.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_int32_le(QEMUFile *f, void *pv, size_t size)
 | 
					static int get_int32_le(QEMUFile *f, void *pv, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -332,7 +348,7 @@ static int get_int32_le(QEMUFile *f, void *pv, size_t size)
 | 
				
			|||||||
    int32_t loaded;
 | 
					    int32_t loaded;
 | 
				
			||||||
    qemu_get_sbe32s(f, &loaded);
 | 
					    qemu_get_sbe32s(f, &loaded);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (loaded <= *cur) {
 | 
					    if (loaded >= 0 && loaded <= *cur) {
 | 
				
			||||||
        *cur = loaded;
 | 
					        *cur = loaded;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user