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,6 +29,7 @@ | ||
29 | #include <time.h> | 29 | #include <time.h> |
30 | #include <errno.h> | 30 | #include <errno.h> |
31 | #include <sys/time.h> | 31 | #include <sys/time.h> |
32 | +#include <zlib.h> | ||
32 | 33 | ||
33 | #ifndef _WIN32 | 34 | #ifndef _WIN32 |
34 | #include <sys/times.h> | 35 | #include <sys/times.h> |
@@ -822,17 +823,21 @@ static void timer_save(QEMUFile *f, void *opaque) | @@ -822,17 +823,21 @@ static void timer_save(QEMUFile *f, void *opaque) | ||
822 | } | 823 | } |
823 | qemu_put_be64s(f, &cpu_ticks_offset); | 824 | qemu_put_be64s(f, &cpu_ticks_offset); |
824 | qemu_put_be64s(f, &ticks_per_sec); | 825 | qemu_put_be64s(f, &ticks_per_sec); |
826 | + qemu_put_be64s(f, &cpu_clock_offset); | ||
825 | } | 827 | } |
826 | 828 | ||
827 | static int timer_load(QEMUFile *f, void *opaque, int version_id) | 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 | return -EINVAL; | 832 | return -EINVAL; |
831 | if (cpu_ticks_enabled) { | 833 | if (cpu_ticks_enabled) { |
832 | return -EINVAL; | 834 | return -EINVAL; |
833 | } | 835 | } |
834 | qemu_get_be64s(f, &cpu_ticks_offset); | 836 | qemu_get_be64s(f, &cpu_ticks_offset); |
835 | qemu_get_be64s(f, &ticks_per_sec); | 837 | qemu_get_be64s(f, &ticks_per_sec); |
838 | + if (version_id == 2) { | ||
839 | + qemu_get_be64s(f, &cpu_clock_offset); | ||
840 | + } | ||
836 | return 0; | 841 | return 0; |
837 | } | 842 | } |
838 | 843 | ||
@@ -5114,24 +5119,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | @@ -5114,24 +5119,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | ||
5114 | /***********************************************************/ | 5119 | /***********************************************************/ |
5115 | /* ram save/restore */ | 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 | static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) | 5122 | static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) |
5136 | { | 5123 | { |
5137 | int v; | 5124 | int v; |
@@ -5152,28 +5139,238 @@ static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) | @@ -5152,28 +5139,238 @@ static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) | ||
5152 | return 0; | 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 | static void ram_save(QEMUFile *f, void *opaque) | 5278 | static void ram_save(QEMUFile *f, void *opaque) |
5156 | { | 5279 | { |
5157 | int i; | 5280 | int i; |
5281 | + RamCompressState s1, *s = &s1; | ||
5282 | + uint8_t buf[10]; | ||
5283 | + | ||
5158 | qemu_put_be32(f, phys_ram_size); | 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 | static int ram_load(QEMUFile *f, void *opaque, int version_id) | 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 | return -EINVAL; | 5331 | return -EINVAL; |
5170 | if (qemu_get_be32(f) != phys_ram_size) | 5332 | if (qemu_get_be32(f) != phys_ram_size) |
5171 | return -EINVAL; | 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 | return 0; | 5374 | return 0; |
5178 | } | 5375 | } |
5179 | 5376 | ||
@@ -6612,8 +6809,8 @@ int main(int argc, char **argv) | @@ -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 | init_ioports(); | 6815 | init_ioports(); |
6619 | 6816 |