在libvirt 使用save命令对虚拟机进行存储后,将libvirt的信息,虚拟机的内存,cpu以及其他设备的信息都存储了起来。
先把文件格式大致的画出来。
libvirt 存储文件信息
+-------------+-----+-----+-----+-----+
|Libvirt-Magic|版本 | xml |运行 |是否 |
| | |长度 |状态 |压缩 |
|8字节 |4字节|4字节|4字节|4字节|
+-------------+-----+-----+-----+-----+
| 保留字段(60字节) |
+-------------------------------------+
| xml 详细信息(占用xml长度个字节) |
+-------------------------------------+
qemu文件开头存储信息。
+-----+-----+--------+
|QEMV |版本 |设备信息|
| | | |
|4字节|4字节| |
+-----+-----+--------+
qemu中savevm_handlers中的设备信息,可能有多个设备。
设备循环,一个设备信息如下。
+-------+-------+------+------+------+------+--------+------+
|section|section|设备名|设备名|实例id|版本id|子设备信|循环 |
|start | id | 长度 | | | | 息 |设备 |
|1字节 | 4字节 |1字节 |n字节 |4字节 |4字节 | | |
+-------+-------+------+------+------+------+--------+------+
子设备信息存储 这里以ram设备 为例
+--------------------------------------+
|共占用内存字节数 8字节 |
+------+------+------+--------+--------+
|设备名|设备名|设备内|循环前面|ram存储 |
| 长度 | |存长度|信息 |结束标记|
|1字节 |n字节 |8字节 | |8字节 |
+------+------+------+--------+--------+
开始存储设备详细信息
+-------+-------+------+------+
|section|section|设备详|循环 |
|part | id |细信息|设备 |
|1字节 |4字节 |n字节 | |
+-------+-------+------+------+
处理存储结束
+-------+-------+------+------+
|section|section|设备结|循环 |
|end | id |束信息|设备 |
|1字节 |4字节 |n字节 | |
+-------+-------+------+------+
存储设备状态
+-------+-------+------+------+
|section|section|设备状|循环 |
|full | id |态信息|设备 |
|1字节 |4字节 |n字节 | |
+-------+-------+------+------+
+-----+
|结束 |
|标记 |
|1字节|
+-----+
这里就对这一文件进行分析。
首先将存储文件的2进制信息发出来。
00000000 4c 69 62 76 69 72 74 51 65 6d 75 64 53 61 76 65 |LibvirtQemudSave|
00000010 02 00 00 00 07 12 00 00 01 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 3c 64 6f 6d |............<dom|
这是存储文件中的一部分信息,结合代码来看一下这个文件究竟是什么
#define QEMU_SAVE_MAGIC "LibvirtQemudSave"
typedef enum {
QEMU_SAVE_FORMAT_RAW = 0,
QEMU_SAVE_FORMAT_GZIP = 1,
QEMU_SAVE_FORMAT_BZIP2 = 2,
/*
* Deprecated by xz and never used as part of a release
* QEMU_SAVE_FORMAT_LZMA
*/
QEMU_SAVE_FORMAT_XZ = 3,
QEMU_SAVE_FORMAT_LZOP = 4,
/* Note: add new members only at the end.
These values are used in the on-disk format.
Do not change or re-use numbers. */
QEMU_SAVE_FORMAT_LAST
} virQEMUSaveFormat;
struct _virQEMUSaveHeader {
char magic[sizeof(QEMU_SAVE_MAGIC)-1]; //libvirt 存储内存文件的魔数LibvirtQemudSave 16个字节
uint32_t version; //版本信息 上述例子是02
uint32_t xml_len; //存储的xml配置信息长度0x1207
uint32_t was_running;//01 表示恢复时运行,00表示恢复时处于暂停状态
uint32_t compressed;//表示压缩方式,0表示raw,其他格式根据virQEMUSaveFormat定义。
uint32_t unused[15];
};
首先,文件最开始存储了_virQEMUSaveHeader 文件的头信息。
头信息总共占用了0x5b个字节。
忽略libvirt存储配置的一部分,然后直接到达qemu开始存储文件的位置。
根据上面头文件信息,可以得知,qemu存储文件的起始位置为0x1207+0x5b=0x1262
00001250 63 6c 61 62 65 6c 3e 0a 3c 2f 64 6f 6d 61 69 6e |clabel>.</domain|
00001260 3e 0a 00 51 45 56 4d 00 00 00 03 01 00 00 00 02 |>..QEVM.........|
00001270 03 72 61 6d 00 00 00 00 00 00 00 04 00 00 00 00 |.ram............|
00001280 80 8d 10 04 06 70 63 2e 72 61 6d 00 00 00 00 80 |.....pc.ram.....|
00001290 00 00 00 08 76 67 61 2e 76 72 61 6d 00 00 00 00 |....vga.vram....|
000012a0 00 80 00 00 07 70 63 2e 62 69 6f 73 00 00 00 00 |...