1. 流程:
1)测试设备是否支持snapshot保存
2)停止虚拟机
3)保存虚拟机状态
4)创建快照
5)恢复虚拟机
2. 函数调用:
1) 入口函数
do_savevm()
2) 函数调用:
1) bdrv_snapshots()
2) vm_stop()
3) qemu_savevm_state()
4) bdrv_snapshot_create()
5) vm_start()
3. 保存状态关键函数qemu_savevm_state()调用
1) qemu_savevm_state_begin()
2) qemu_savevm_state_iterate()
3) qemu_savevm_state_complete()
4. 关键结构体
1)savevm_handlers 设备状态保存函数链表头
通过QTAILQ_FOREACH(se, &savevm_handlers, entry){}遍历保存所有设备状态;
2)QEMUFile
struct QEMUFile {
QEMUFilePutBufferFunc *put_buffer;
QEMUFileGetBufferFunc *get_buffer;
QEMUFileCloseFunc *close;
QEMUFileRateLimit *rate_limit;
QEMUFileSetRateLimit *set_rate_limit;
QEMUFileGetRateLimit *get_rate_limit;
void *opaque;
int is_write;
int64_t buf_offset; /* start of buffer when writing, end of buffer
when reading */
int buf_index;
int buf_size; /* 0 when writing */
int buf_max_size;
uint8_t *buf;
int has_error;
};
其中put_buffer/get_buffer为关键函数,用来保存/获取设备状态
通过qemu_fopen_ops()函数注册该结构体
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
QEMUFileGetBufferFunc *get_buffer,
QEMUFileCloseFunc *close,
QEMUFileRateLimit *rate_limit,
QEMUFileSetRateLimit *set_rate_limit,
QEMUFileGetRateLimit *get_rate_limit)
{
QEMUFile *f;
f = qemu_mallocz(sizeof(QEMUFile));
f->opaque = opaque;
f->put_buffer = put_buffer;
f->get_buffer = get_buffer;
f->close = close;
f->rate_limit = rate_limit;
f->set_rate_limit = set_rate_limit;
f->get_rate_limit = get_rate_limit;
f->is_write = 0;
f->buf_max_size = IO_BUF_SIZE;
f->buf = qemu_malloc(sizeof(uint8_t) * f->buf_max_size);
return f;
}
3)SaveStateEntry
typedef struct SaveStateEntry {
QTAILQ_ENTRY(SaveStateEntry) entry;
char idstr[256];
int instance_id;
int alias_id;
int version_id;
int section_id;
SaveSetParamsHandler *set_params;
SaveLiveStateHandler *save_live_state;
SaveStateHandler *save_state;
LoadStateHandler *load_state;
const VMStateDescription *vmsd;
void *opaque;
CompatEntry *compat;
int no_migrate;
} SaveStateEntry;
4) register_savevm_live()
注册保存设备状态函数,填充了结构体SaveStateEntry,并把函数加入到队列中:
QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
如果该设备支持动态迁移和状态保存,必须注册调用改函数注册信息。