Commit c88676f89c3e2b4eefdfe2ef647e1ea07fe052ae
1 parent
d15a771d
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
Showing
1 changed file
with
226 additions
and
29 deletions
vl.c
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | #include <time.h> |
| 30 | 30 | #include <errno.h> |
| 31 | 31 | #include <sys/time.h> |
| 32 | +#include <zlib.h> | |
| 32 | 33 | |
| 33 | 34 | #ifndef _WIN32 |
| 34 | 35 | #include <sys/times.h> |
| ... | ... | @@ -822,17 +823,21 @@ static void timer_save(QEMUFile *f, void *opaque) |
| 822 | 823 | } |
| 823 | 824 | qemu_put_be64s(f, &cpu_ticks_offset); |
| 824 | 825 | qemu_put_be64s(f, &ticks_per_sec); |
| 826 | + qemu_put_be64s(f, &cpu_clock_offset); | |
| 825 | 827 | } |
| 826 | 828 | |
| 827 | 829 | static int timer_load(QEMUFile *f, void *opaque, int version_id) |
| 828 | 830 | { |
| 829 | - if (version_id != 1) | |
| 831 | + if (version_id != 1 && version_id != 2) | |
| 830 | 832 | return -EINVAL; |
| 831 | 833 | if (cpu_ticks_enabled) { |
| 832 | 834 | return -EINVAL; |
| 833 | 835 | } |
| 834 | 836 | qemu_get_be64s(f, &cpu_ticks_offset); |
| 835 | 837 | qemu_get_be64s(f, &ticks_per_sec); |
| 838 | + if (version_id == 2) { | |
| 839 | + qemu_get_be64s(f, &cpu_clock_offset); | |
| 840 | + } | |
| 836 | 841 | return 0; |
| 837 | 842 | } |
| 838 | 843 | |
| ... | ... | @@ -5114,24 +5119,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) |
| 5114 | 5119 | /***********************************************************/ |
| 5115 | 5120 | /* ram save/restore */ |
| 5116 | 5121 | |
| 5117 | -/* we just avoid storing empty pages */ | |
| 5118 | -static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len) | |
| 5119 | -{ | |
| 5120 | - int i, v; | |
| 5121 | - | |
| 5122 | - v = buf[0]; | |
| 5123 | - for(i = 1; i < len; i++) { | |
| 5124 | - if (buf[i] != v) | |
| 5125 | - goto normal_save; | |
| 5126 | - } | |
| 5127 | - qemu_put_byte(f, 1); | |
| 5128 | - qemu_put_byte(f, v); | |
| 5129 | - return; | |
| 5130 | - normal_save: | |
| 5131 | - qemu_put_byte(f, 0); | |
| 5132 | - qemu_put_buffer(f, buf, len); | |
| 5133 | -} | |
| 5134 | - | |
| 5135 | 5122 | static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) |
| 5136 | 5123 | { |
| 5137 | 5124 | int v; |
| ... | ... | @@ -5152,28 +5139,238 @@ static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) |
| 5152 | 5139 | return 0; |
| 5153 | 5140 | } |
| 5154 | 5141 | |
| 5142 | +static int ram_load_v1(QEMUFile *f, void *opaque) | |
| 5143 | +{ | |
| 5144 | + int i, ret; | |
| 5145 | + | |
| 5146 | + if (qemu_get_be32(f) != phys_ram_size) | |
| 5147 | + return -EINVAL; | |
| 5148 | + for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { | |
| 5149 | + ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); | |
| 5150 | + if (ret) | |
| 5151 | + return ret; | |
| 5152 | + } | |
| 5153 | + return 0; | |
| 5154 | +} | |
| 5155 | + | |
| 5156 | +#define BDRV_HASH_BLOCK_SIZE 1024 | |
| 5157 | +#define IOBUF_SIZE 4096 | |
| 5158 | +#define RAM_CBLOCK_MAGIC 0xfabe | |
| 5159 | + | |
| 5160 | +typedef struct RamCompressState { | |
| 5161 | + z_stream zstream; | |
| 5162 | + QEMUFile *f; | |
| 5163 | + uint8_t buf[IOBUF_SIZE]; | |
| 5164 | +} RamCompressState; | |
| 5165 | + | |
| 5166 | +static int ram_compress_open(RamCompressState *s, QEMUFile *f) | |
| 5167 | +{ | |
| 5168 | + int ret; | |
| 5169 | + memset(s, 0, sizeof(*s)); | |
| 5170 | + s->f = f; | |
| 5171 | + ret = deflateInit2(&s->zstream, 1, | |
| 5172 | + Z_DEFLATED, 15, | |
| 5173 | + 9, Z_DEFAULT_STRATEGY); | |
| 5174 | + if (ret != Z_OK) | |
| 5175 | + return -1; | |
| 5176 | + s->zstream.avail_out = IOBUF_SIZE; | |
| 5177 | + s->zstream.next_out = s->buf; | |
| 5178 | + return 0; | |
| 5179 | +} | |
| 5180 | + | |
| 5181 | +static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len) | |
| 5182 | +{ | |
| 5183 | + qemu_put_be16(s->f, RAM_CBLOCK_MAGIC); | |
| 5184 | + qemu_put_be16(s->f, len); | |
| 5185 | + qemu_put_buffer(s->f, buf, len); | |
| 5186 | +} | |
| 5187 | + | |
| 5188 | +static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len) | |
| 5189 | +{ | |
| 5190 | + int ret; | |
| 5191 | + | |
| 5192 | + s->zstream.avail_in = len; | |
| 5193 | + s->zstream.next_in = (uint8_t *)buf; | |
| 5194 | + while (s->zstream.avail_in > 0) { | |
| 5195 | + ret = deflate(&s->zstream, Z_NO_FLUSH); | |
| 5196 | + if (ret != Z_OK) | |
| 5197 | + return -1; | |
| 5198 | + if (s->zstream.avail_out == 0) { | |
| 5199 | + ram_put_cblock(s, s->buf, IOBUF_SIZE); | |
| 5200 | + s->zstream.avail_out = IOBUF_SIZE; | |
| 5201 | + s->zstream.next_out = s->buf; | |
| 5202 | + } | |
| 5203 | + } | |
| 5204 | + return 0; | |
| 5205 | +} | |
| 5206 | + | |
| 5207 | +static void ram_compress_close(RamCompressState *s) | |
| 5208 | +{ | |
| 5209 | + int len, ret; | |
| 5210 | + | |
| 5211 | + /* compress last bytes */ | |
| 5212 | + for(;;) { | |
| 5213 | + ret = deflate(&s->zstream, Z_FINISH); | |
| 5214 | + if (ret == Z_OK || ret == Z_STREAM_END) { | |
| 5215 | + len = IOBUF_SIZE - s->zstream.avail_out; | |
| 5216 | + if (len > 0) { | |
| 5217 | + ram_put_cblock(s, s->buf, len); | |
| 5218 | + } | |
| 5219 | + s->zstream.avail_out = IOBUF_SIZE; | |
| 5220 | + s->zstream.next_out = s->buf; | |
| 5221 | + if (ret == Z_STREAM_END) | |
| 5222 | + break; | |
| 5223 | + } else { | |
| 5224 | + goto fail; | |
| 5225 | + } | |
| 5226 | + } | |
| 5227 | +fail: | |
| 5228 | + deflateEnd(&s->zstream); | |
| 5229 | +} | |
| 5230 | + | |
| 5231 | +typedef struct RamDecompressState { | |
| 5232 | + z_stream zstream; | |
| 5233 | + QEMUFile *f; | |
| 5234 | + uint8_t buf[IOBUF_SIZE]; | |
| 5235 | +} RamDecompressState; | |
| 5236 | + | |
| 5237 | +static int ram_decompress_open(RamDecompressState *s, QEMUFile *f) | |
| 5238 | +{ | |
| 5239 | + int ret; | |
| 5240 | + memset(s, 0, sizeof(*s)); | |
| 5241 | + s->f = f; | |
| 5242 | + ret = inflateInit(&s->zstream); | |
| 5243 | + if (ret != Z_OK) | |
| 5244 | + return -1; | |
| 5245 | + return 0; | |
| 5246 | +} | |
| 5247 | + | |
| 5248 | +static int ram_decompress_buf(RamDecompressState *s, uint8_t *buf, int len) | |
| 5249 | +{ | |
| 5250 | + int ret, clen; | |
| 5251 | + | |
| 5252 | + s->zstream.avail_out = len; | |
| 5253 | + s->zstream.next_out = buf; | |
| 5254 | + while (s->zstream.avail_out > 0) { | |
| 5255 | + if (s->zstream.avail_in == 0) { | |
| 5256 | + if (qemu_get_be16(s->f) != RAM_CBLOCK_MAGIC) | |
| 5257 | + return -1; | |
| 5258 | + clen = qemu_get_be16(s->f); | |
| 5259 | + if (clen > IOBUF_SIZE) | |
| 5260 | + return -1; | |
| 5261 | + qemu_get_buffer(s->f, s->buf, clen); | |
| 5262 | + s->zstream.avail_in = clen; | |
| 5263 | + s->zstream.next_in = s->buf; | |
| 5264 | + } | |
| 5265 | + ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); | |
| 5266 | + if (ret != Z_OK && ret != Z_STREAM_END) { | |
| 5267 | + return -1; | |
| 5268 | + } | |
| 5269 | + } | |
| 5270 | + return 0; | |
| 5271 | +} | |
| 5272 | + | |
| 5273 | +static void ram_decompress_close(RamDecompressState *s) | |
| 5274 | +{ | |
| 5275 | + inflateEnd(&s->zstream); | |
| 5276 | +} | |
| 5277 | + | |
| 5155 | 5278 | static void ram_save(QEMUFile *f, void *opaque) |
| 5156 | 5279 | { |
| 5157 | 5280 | int i; |
| 5281 | + RamCompressState s1, *s = &s1; | |
| 5282 | + uint8_t buf[10]; | |
| 5283 | + | |
| 5158 | 5284 | qemu_put_be32(f, phys_ram_size); |
| 5159 | - for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { | |
| 5160 | - ram_put_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); | |
| 5285 | + if (ram_compress_open(s, f) < 0) | |
| 5286 | + return; | |
| 5287 | + for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { | |
| 5288 | +#if 0 | |
| 5289 | + if (tight_savevm_enabled) { | |
| 5290 | + int64_t sector_num; | |
| 5291 | + int j; | |
| 5292 | + | |
| 5293 | + /* find if the memory block is available on a virtual | |
| 5294 | + block device */ | |
| 5295 | + sector_num = -1; | |
| 5296 | + for(j = 0; j < MAX_DISKS; j++) { | |
| 5297 | + if (bs_table[j]) { | |
| 5298 | + sector_num = bdrv_hash_find(bs_table[j], | |
| 5299 | + phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); | |
| 5300 | + if (sector_num >= 0) | |
| 5301 | + break; | |
| 5302 | + } | |
| 5303 | + } | |
| 5304 | + if (j == MAX_DISKS) | |
| 5305 | + goto normal_compress; | |
| 5306 | + buf[0] = 1; | |
| 5307 | + buf[1] = j; | |
| 5308 | + cpu_to_be64wu((uint64_t *)(buf + 2), sector_num); | |
| 5309 | + ram_compress_buf(s, buf, 10); | |
| 5310 | + } else | |
| 5311 | +#endif | |
| 5312 | + { | |
| 5313 | + // normal_compress: | |
| 5314 | + buf[0] = 0; | |
| 5315 | + ram_compress_buf(s, buf, 1); | |
| 5316 | + ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); | |
| 5317 | + } | |
| 5161 | 5318 | } |
| 5319 | + ram_compress_close(s); | |
| 5162 | 5320 | } |
| 5163 | 5321 | |
| 5164 | 5322 | static int ram_load(QEMUFile *f, void *opaque, int version_id) |
| 5165 | 5323 | { |
| 5166 | - int i, ret; | |
| 5324 | + RamDecompressState s1, *s = &s1; | |
| 5325 | + uint8_t buf[10]; | |
| 5326 | + int i; | |
| 5167 | 5327 | |
| 5168 | - if (version_id != 1) | |
| 5328 | + if (version_id == 1) | |
| 5329 | + return ram_load_v1(f, opaque); | |
| 5330 | + if (version_id != 2) | |
| 5169 | 5331 | return -EINVAL; |
| 5170 | 5332 | if (qemu_get_be32(f) != phys_ram_size) |
| 5171 | 5333 | return -EINVAL; |
| 5172 | - for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { | |
| 5173 | - ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); | |
| 5174 | - if (ret) | |
| 5175 | - return ret; | |
| 5334 | + if (ram_decompress_open(s, f) < 0) | |
| 5335 | + return -EINVAL; | |
| 5336 | + for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { | |
| 5337 | + if (ram_decompress_buf(s, buf, 1) < 0) { | |
| 5338 | + fprintf(stderr, "Error while reading ram block header\n"); | |
| 5339 | + goto error; | |
| 5340 | + } | |
| 5341 | + if (buf[0] == 0) { | |
| 5342 | + if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) { | |
| 5343 | + fprintf(stderr, "Error while reading ram block address=0x%08x", i); | |
| 5344 | + goto error; | |
| 5345 | + } | |
| 5346 | + } else | |
| 5347 | +#if 0 | |
| 5348 | + if (buf[0] == 1) { | |
| 5349 | + int bs_index; | |
| 5350 | + int64_t sector_num; | |
| 5351 | + | |
| 5352 | + ram_decompress_buf(s, buf + 1, 9); | |
| 5353 | + bs_index = buf[1]; | |
| 5354 | + sector_num = be64_to_cpupu((const uint64_t *)(buf + 2)); | |
| 5355 | + if (bs_index >= MAX_DISKS || bs_table[bs_index] == NULL) { | |
| 5356 | + fprintf(stderr, "Invalid block device index %d\n", bs_index); | |
| 5357 | + goto error; | |
| 5358 | + } | |
| 5359 | + if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, | |
| 5360 | + BDRV_HASH_BLOCK_SIZE / 512) < 0) { | |
| 5361 | + fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", | |
| 5362 | + bs_index, sector_num); | |
| 5363 | + goto error; | |
| 5364 | + } | |
| 5365 | + } else | |
| 5366 | +#endif | |
| 5367 | + { | |
| 5368 | + error: | |
| 5369 | + printf("Error block header\n"); | |
| 5370 | + return -EINVAL; | |
| 5371 | + } | |
| 5176 | 5372 | } |
| 5373 | + ram_decompress_close(s); | |
| 5177 | 5374 | return 0; |
| 5178 | 5375 | } |
| 5179 | 5376 | |
| ... | ... | @@ -6612,8 +6809,8 @@ int main(int argc, char **argv) |
| 6612 | 6809 | } |
| 6613 | 6810 | } |
| 6614 | 6811 | |
| 6615 | - register_savevm("timer", 0, 1, timer_save, timer_load, NULL); | |
| 6616 | - register_savevm("ram", 0, 1, ram_save, ram_load, NULL); | |
| 6812 | + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); | |
| 6813 | + register_savevm("ram", 0, 2, ram_save, ram_load, NULL); | |
| 6617 | 6814 | |
| 6618 | 6815 | init_ioports(); |
| 6619 | 6816 | ... | ... |