use zlib to compress ram snapshots - correctly save qemu clock
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2095 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									d15a771da1
								
							
						
					
					
						commit
						c88676f89c
					
				
							
								
								
									
										263
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										263
									
								
								vl.c
									
									
									
									
									
								
							@ -29,6 +29,7 @@
 | 
				
			|||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <sys/time.h>
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					#include <zlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
#include <sys/times.h>
 | 
					#include <sys/times.h>
 | 
				
			||||||
@ -822,17 +823,21 @@ static void timer_save(QEMUFile *f, void *opaque)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    qemu_put_be64s(f, &cpu_ticks_offset);
 | 
					    qemu_put_be64s(f, &cpu_ticks_offset);
 | 
				
			||||||
    qemu_put_be64s(f, &ticks_per_sec);
 | 
					    qemu_put_be64s(f, &ticks_per_sec);
 | 
				
			||||||
 | 
					    qemu_put_be64s(f, &cpu_clock_offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int timer_load(QEMUFile *f, void *opaque, int version_id)
 | 
					static int timer_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (version_id != 1)
 | 
					    if (version_id != 1 && version_id != 2)
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    if (cpu_ticks_enabled) {
 | 
					    if (cpu_ticks_enabled) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    qemu_get_be64s(f, &cpu_ticks_offset);
 | 
					    qemu_get_be64s(f, &cpu_ticks_offset);
 | 
				
			||||||
    qemu_get_be64s(f, &ticks_per_sec);
 | 
					    qemu_get_be64s(f, &ticks_per_sec);
 | 
				
			||||||
 | 
					    if (version_id == 2) {
 | 
				
			||||||
 | 
					        qemu_get_be64s(f, &cpu_clock_offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -5114,24 +5119,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
/***********************************************************/
 | 
					/***********************************************************/
 | 
				
			||||||
/* ram save/restore */
 | 
					/* ram save/restore */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* we just avoid storing empty pages */
 | 
					 | 
				
			||||||
static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i, v;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    v = buf[0];
 | 
					 | 
				
			||||||
    for(i = 1; i < len; i++) {
 | 
					 | 
				
			||||||
        if (buf[i] != v)
 | 
					 | 
				
			||||||
            goto normal_save;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    qemu_put_byte(f, 1);
 | 
					 | 
				
			||||||
    qemu_put_byte(f, v);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 normal_save:
 | 
					 | 
				
			||||||
    qemu_put_byte(f, 0); 
 | 
					 | 
				
			||||||
    qemu_put_buffer(f, buf, len);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
 | 
					static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int v;
 | 
					    int v;
 | 
				
			||||||
@ -5152,21 +5139,10 @@ static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ram_save(QEMUFile *f, void *opaque)
 | 
					static int ram_load_v1(QEMUFile *f, void *opaque)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
    qemu_put_be32(f, phys_ram_size);
 | 
					 | 
				
			||||||
    for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
 | 
					 | 
				
			||||||
        ram_put_page(f, phys_ram_base + i, TARGET_PAGE_SIZE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int i, ret;
 | 
					    int i, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (version_id != 1)
 | 
					 | 
				
			||||||
        return -EINVAL;
 | 
					 | 
				
			||||||
    if (qemu_get_be32(f) != phys_ram_size)
 | 
					    if (qemu_get_be32(f) != phys_ram_size)
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
 | 
					    for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
 | 
				
			||||||
@ -5177,6 +5153,227 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BDRV_HASH_BLOCK_SIZE 1024
 | 
				
			||||||
 | 
					#define IOBUF_SIZE 4096
 | 
				
			||||||
 | 
					#define RAM_CBLOCK_MAGIC 0xfabe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct RamCompressState {
 | 
				
			||||||
 | 
					    z_stream zstream;
 | 
				
			||||||
 | 
					    QEMUFile *f;
 | 
				
			||||||
 | 
					    uint8_t buf[IOBUF_SIZE];
 | 
				
			||||||
 | 
					} RamCompressState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ram_compress_open(RamCompressState *s, QEMUFile *f)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    memset(s, 0, sizeof(*s));
 | 
				
			||||||
 | 
					    s->f = f;
 | 
				
			||||||
 | 
					    ret = deflateInit2(&s->zstream, 1,
 | 
				
			||||||
 | 
					                       Z_DEFLATED, 15, 
 | 
				
			||||||
 | 
					                       9, Z_DEFAULT_STRATEGY);
 | 
				
			||||||
 | 
					    if (ret != Z_OK)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    s->zstream.avail_out = IOBUF_SIZE;
 | 
				
			||||||
 | 
					    s->zstream.next_out = s->buf;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_put_be16(s->f, RAM_CBLOCK_MAGIC);
 | 
				
			||||||
 | 
					    qemu_put_be16(s->f, len);
 | 
				
			||||||
 | 
					    qemu_put_buffer(s->f, buf, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->zstream.avail_in = len;
 | 
				
			||||||
 | 
					    s->zstream.next_in = (uint8_t *)buf;
 | 
				
			||||||
 | 
					    while (s->zstream.avail_in > 0) {
 | 
				
			||||||
 | 
					        ret = deflate(&s->zstream, Z_NO_FLUSH);
 | 
				
			||||||
 | 
					        if (ret != Z_OK)
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        if (s->zstream.avail_out == 0) {
 | 
				
			||||||
 | 
					            ram_put_cblock(s, s->buf, IOBUF_SIZE);
 | 
				
			||||||
 | 
					            s->zstream.avail_out = IOBUF_SIZE;
 | 
				
			||||||
 | 
					            s->zstream.next_out = s->buf;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ram_compress_close(RamCompressState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int len, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* compress last bytes */
 | 
				
			||||||
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        ret = deflate(&s->zstream, Z_FINISH);
 | 
				
			||||||
 | 
					        if (ret == Z_OK || ret == Z_STREAM_END) {
 | 
				
			||||||
 | 
					            len = IOBUF_SIZE - s->zstream.avail_out;
 | 
				
			||||||
 | 
					            if (len > 0) {
 | 
				
			||||||
 | 
					                ram_put_cblock(s, s->buf, len);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            s->zstream.avail_out = IOBUF_SIZE;
 | 
				
			||||||
 | 
					            s->zstream.next_out = s->buf;
 | 
				
			||||||
 | 
					            if (ret == Z_STREAM_END)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					fail:
 | 
				
			||||||
 | 
					    deflateEnd(&s->zstream);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct RamDecompressState {
 | 
				
			||||||
 | 
					    z_stream zstream;
 | 
				
			||||||
 | 
					    QEMUFile *f;
 | 
				
			||||||
 | 
					    uint8_t buf[IOBUF_SIZE];
 | 
				
			||||||
 | 
					} RamDecompressState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ram_decompress_open(RamDecompressState *s, QEMUFile *f)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    memset(s, 0, sizeof(*s));
 | 
				
			||||||
 | 
					    s->f = f;
 | 
				
			||||||
 | 
					    ret = inflateInit(&s->zstream);
 | 
				
			||||||
 | 
					    if (ret != Z_OK)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ram_decompress_buf(RamDecompressState *s, uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret, clen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->zstream.avail_out = len;
 | 
				
			||||||
 | 
					    s->zstream.next_out = buf;
 | 
				
			||||||
 | 
					    while (s->zstream.avail_out > 0) {
 | 
				
			||||||
 | 
					        if (s->zstream.avail_in == 0) {
 | 
				
			||||||
 | 
					            if (qemu_get_be16(s->f) != RAM_CBLOCK_MAGIC)
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            clen = qemu_get_be16(s->f);
 | 
				
			||||||
 | 
					            if (clen > IOBUF_SIZE)
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            qemu_get_buffer(s->f, s->buf, clen);
 | 
				
			||||||
 | 
					            s->zstream.avail_in = clen;
 | 
				
			||||||
 | 
					            s->zstream.next_in = s->buf;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
 | 
				
			||||||
 | 
					        if (ret != Z_OK && ret != Z_STREAM_END) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ram_decompress_close(RamDecompressState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    inflateEnd(&s->zstream);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ram_save(QEMUFile *f, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    RamCompressState s1, *s = &s1;
 | 
				
			||||||
 | 
					    uint8_t buf[10];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    qemu_put_be32(f, phys_ram_size);
 | 
				
			||||||
 | 
					    if (ram_compress_open(s, f) < 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					        if (tight_savevm_enabled) {
 | 
				
			||||||
 | 
					            int64_t sector_num;
 | 
				
			||||||
 | 
					            int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* find if the memory block is available on a virtual
 | 
				
			||||||
 | 
					               block device */
 | 
				
			||||||
 | 
					            sector_num = -1;
 | 
				
			||||||
 | 
					            for(j = 0; j < MAX_DISKS; j++) {
 | 
				
			||||||
 | 
					                if (bs_table[j]) {
 | 
				
			||||||
 | 
					                    sector_num = bdrv_hash_find(bs_table[j], 
 | 
				
			||||||
 | 
					                                                phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
 | 
				
			||||||
 | 
					                    if (sector_num >= 0)
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (j == MAX_DISKS)
 | 
				
			||||||
 | 
					                goto normal_compress;
 | 
				
			||||||
 | 
					            buf[0] = 1;
 | 
				
			||||||
 | 
					            buf[1] = j;
 | 
				
			||||||
 | 
					            cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);
 | 
				
			||||||
 | 
					            ram_compress_buf(s, buf, 10);
 | 
				
			||||||
 | 
					        } else 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //        normal_compress:
 | 
				
			||||||
 | 
					            buf[0] = 0;
 | 
				
			||||||
 | 
					            ram_compress_buf(s, buf, 1);
 | 
				
			||||||
 | 
					            ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ram_compress_close(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    RamDecompressState s1, *s = &s1;
 | 
				
			||||||
 | 
					    uint8_t buf[10];
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (version_id == 1)
 | 
				
			||||||
 | 
					        return ram_load_v1(f, opaque);
 | 
				
			||||||
 | 
					    if (version_id != 2)
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    if (qemu_get_be32(f) != phys_ram_size)
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    if (ram_decompress_open(s, f) < 0)
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					    for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {
 | 
				
			||||||
 | 
					        if (ram_decompress_buf(s, buf, 1) < 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Error while reading ram block header\n");
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (buf[0] == 0) {
 | 
				
			||||||
 | 
					            if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Error while reading ram block address=0x%08x", i);
 | 
				
			||||||
 | 
					                goto error;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else 
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					        if (buf[0] == 1) {
 | 
				
			||||||
 | 
					            int bs_index;
 | 
				
			||||||
 | 
					            int64_t sector_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ram_decompress_buf(s, buf + 1, 9);
 | 
				
			||||||
 | 
					            bs_index = buf[1];
 | 
				
			||||||
 | 
					            sector_num = be64_to_cpupu((const uint64_t *)(buf + 2));
 | 
				
			||||||
 | 
					            if (bs_index >= MAX_DISKS || bs_table[bs_index] == NULL) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Invalid block device index %d\n", bs_index);
 | 
				
			||||||
 | 
					                goto error;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, 
 | 
				
			||||||
 | 
					                          BDRV_HASH_BLOCK_SIZE / 512) < 0) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", 
 | 
				
			||||||
 | 
					                        bs_index, sector_num);
 | 
				
			||||||
 | 
					                goto error;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        error:
 | 
				
			||||||
 | 
					            printf("Error block header\n");
 | 
				
			||||||
 | 
					            return -EINVAL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ram_decompress_close(s);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***********************************************************/
 | 
					/***********************************************************/
 | 
				
			||||||
/* bottom halves (can be seen as timers which expire ASAP) */
 | 
					/* bottom halves (can be seen as timers which expire ASAP) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -6612,8 +6809,8 @@ int main(int argc, char **argv)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    register_savevm("timer", 0, 1, timer_save, timer_load, NULL);
 | 
					    register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
 | 
				
			||||||
    register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
 | 
					    register_savevm("ram", 0, 2, ram_save, ram_load, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init_ioports();
 | 
					    init_ioports();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user