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 | ... | ... |