QCOW镜像格式为big-endian。
第一个cluster包含qcow2镜像的头。
字节偏移 | 字段 | 描述 |
---|---|---|
0 - 3 | magic | 字符串(“QFI\xfb”) |
4 - 7 | version | 版本号,2或3 |
8 - 15 | backing_file_offset | 后端文件名在镜像中的偏移,0表示没有后端文件 |
16 - 19 | backing_file_size | 后端文件名的长度字节数,最大1023字节 |
20 - 23 | cluster_bits | 1 « cluster_bits是cluster大小,必须大于9-21之间 |
24 - 31 | size | 虚拟磁盘大小,单位字节 |
32 - 35 | crypt_method | 0,不加密;1,AES加密 |
36 - 39 | l1_size | 活跃L1表入口项(entries)数量 |
40 - 47 | l1_table_offset | 活跃L1表起始在镜像内的偏移,必须cluster对齐 |
48 - 55 | refcount_table_offset | refcount表起始在镜像内的偏移,必须cluster对齐 |
56 - 59 | refcount_table_clusters | refcount表占用的cluster数量 |
60 - 63 | nb_snapshots | 镜像中包含的快照数量 |
64 - 71 | snapshots_offset | 快照表起始在镜像内的偏移,必须cluster对齐 |
[root@test-11 ~]# hexdump -n 8 -s 24 test.qcow2
0000018 0000 0600 0040 0000
版本3之后增加的字段
字节偏移 | 字段 | 描述 |
---|---|---|
72 - 79 | incompatible_features | 不兼容特性掩码,如果未知位被设置,镜像打开失败。 Bit 0: Dirty bit. 如果被设置,refcounts可能不一致,在使用镜像前需要扫描L1/L2表进行修复 Bit 1: Corrupt bit.如果被设置,数据结构体可能被破坏,镜像不能写入 Bits 2-63: 保留,设置为0 |
80 - 87 | compatible_features | 兼容特性掩码,未知位被设置,可以直接忽略。 Bit 0: Lazy refcounts bit. 如果被设置,可以使用lazy refcount更新,标记镜像dirty,延迟refcount元数据更新。 Bits 1-63: 保留,设置为0 |
88 - 95 | autoclear_features | Bitmask of auto-clear features. An implementation may only write to an image with unknown auto-clear features if it clears the respective bits from this field first. Bit 0: Bitmaps extension bit,显示位图扩展数据的一致性,如果有位图扩展,但该位未被设置,则位图扩展数据不一致 Bits 1-63: 保留,设置为0 |
96 - 99 | refcount_order | 引用数块入口宽度(reference count block entry),不能超过6,V2镜像值为4 |
100 - 103 | header_length | 头结构体长度,V2镜像长度为72字节 |
紧接着镜像头之后,是一个可选的头扩展区,结构如下:
字节偏移 | 字段 | 描述 |
---|---|---|
0 - 3 | Header extension type | 头扩展类型 0x00000000 - End of the header extension area 0xE2792ACA - Backing file format name 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension other - Unknown header extension, can be safely ignored |
4 - 7 | length | 头扩展数据长度 |
8 - n | data | 头扩展数据 |
n - m | pad | 补齐,8字节对齐 |
除非特殊声明,每个镜像中最多只有一个头扩展类型。
如果镜像有后端文件,则后端文件名应该保存在头扩展区的尾部与第一个cluster尾部之间。而且这部分空间不允许存放其它数据,工具可以安全的修改和增加扩展,而不会影响兼容的特性。
特性名称表是一个可选的头部扩展,包含镜像使用特性的名称。特征名表项数量由头扩展数据的长度决定,每项格式如下:
偏移 | 字段 | 描述 |
---|---|---|
0 | feature type | 特性类型 0: 不兼容特性 1: 兼容特性 2: 自动清除特性 |
1 | bitmap | Bit number within the selected feature bitmap (valid values: 0-63) |
2 - 47 | feature name | 特征名,用0补齐。 |
位图(bitmaps)扩展是可选的头扩展,提供与虚拟磁盘相关的保存位图能力。目前只有一种位图类型:dirty tracking bitmap,追踪虚拟磁盘从某个时间点的变化。
位偏移 | 字段 | 描述 |
---|---|---|
0 - 3 | nb_bitmaps | 镜像中包含的位图数量,Qemu目前最大支持65535 |
4 - 7 | Reserved | 保留位必须为0 |
8 - 15 | bitmap_directory_size | 位图目录大小,是所有位图头的总和 |
16 - 23 | bitmap_directory_offset | 位图目录起始在镜像内的偏移 |
qcow2通过维护每个主机cluster的引用计数管理主机clusters的分配。refcount为0表示空闲,1表示使用,>=2表示被使用且任何写访问必须执行COW操作。
refcounts用两级表管理,第一级是refcount table,大小可变(保存在头结构体),第二级可以包括多个clusters,但必须在镜像文件内部连续。包含指向第二级结构体的指针称作refcount blocks,大小为一个cluster。
refcount_block_entries = (cluster_size * 8 / refcount_bits)
refcount_block_index = (offset / cluster_size) % refcount_block_entries
refcount_table_index = (offset / cluster_size) / refcount_block_entries
refcount_block = load_cluster(refcount_table[refcount_table_index]);
return refcount_block[refcount_block_index];
位偏移 | 字段 | 描述 |
---|---|---|
0 - 8 | Reserved | 保留,设置为0 |
9 - 63 | refcount_offset | refcount block起始在镜像内的偏移 |
Refcount block项(x = refcount_bits - 1): 0 - x: cluster的reference count
与refcounts一样,qcow2使用两级结构体映射guest cluster到host cluster。它们称作L1和L2表。
L1表大小可变(保存在头结构体),可以使用多个clusters,但在镜像文件内必须连续。L2表大小固定为一个cluster。
给定一个虚拟磁盘内的偏移(offset),计算镜像文件的偏移:
l2_entries = (cluster_size / sizeof(uint64_t))
l2_index = (offset / cluster_size) % l2_entries
l1_index = (offset / cluster_size) / l2_entries
l2_table = load_cluster(l1_table[l1_index]);
cluster_offset = l2_table[l2_index];
return cluster_offset + (offset % cluster_size)
位偏移 | 字段 | 描述 |
---|---|---|
0-8 | Reserved | 保留,设置为0 |
9 - 55 | l2_offset | L2表起始在镜像内的偏移,如果为0,L2表和它描述的clusters都没有分配 |
56 - 62 | Reserved | 保留,设置为0 |
63 | l2_refcount | 0表示L2表没有使用或需要COW, 1表示refcount为1 |
[root@master qemu-2.6.0]# qemu-img info ~/test.qcow2 --output json
{
"virtual-size": 26843545600,
"filename": "/root/test.qcow2",
"cluster-size": 65536,
"format": "qcow2",
"actual-size": 287100928,
"format-specific": {
"type": "qcow2",
"data": {
"compat": "1.1",
"lazy-refcounts": false
}
},
"dirty-flag": false
}
[root@master qemu-2.6.0]# hexdump -n 4 -s 36 ~/test.qcow2
0000024 0000 3200
l1_size = 0x32 == 50 l1_size = virtual-size/cluster-size/l2-size virtual-size = 26843545600 cluster-size = 65536 l2-size = 65536/8 = 8192
[root@master qemu-2.6.0]# hexdump -n 8 -s 40 ~/t1.qcow2
0000028 0000 0000 0300 0000
l1_offset 0x30000
[root@master qemu-2.6.0]# hexdump -n 8 -s 0x30000 ~/test.qcow2
0030000 0080 0000 0400 0000
l2_offset 0x40000
** l2_entry **
[root@master qemu-2.6.0]# hexdump -n 8 -s 0x40000 ~/test.qcow2
0040000 c040 0000 0500 0000
cluster_offset 0x40c0000000050000
位偏移 | 字段 | 描述 |
---|---|---|
0 - 61 | cluster_desc | cluster描述符 |
62 | cluster_type | 0表示标准clusters,1表示压缩clusters |
63 | cluster_refcount | 0表示cluster没有使用或需要COW,1表示refcount为1 |
位偏移 | 字段 | 描述 |
---|---|---|
0 | cluster_zero | 设置为1,cluster读全0。host cluster偏移用于描述预分配,但不用于从这个cluster读数据。V2总是0 |
1 - 8 | Reserved | 保留,设置0 |
9 - 55 | cluster_offset | host cluster偏移,0表示cluster未分配 |
56 - 61 | Reserved | 保留,设置0 |
如果cluster未分配,读请求从后端文件读数据。如果没有后端文件,或后端文件比镜像小,读到的就是全零。
qcow2支持内部快照,操作的基本原则是切换活跃L1表,这样guest就看到不同的host clusters。 创建快照时,需要拷贝L1表和指向的L2表,从该L1表访问的clusters计数增加,这样写操作就会触发COW,而且对其它快照不可见。 加载快照时,新的活跃L1表所有项的bit63和它的L2表需要重建。 所有快照的目录存在快照表中,是镜像内一段连续的区域。快照表项大小可变,由ID长度、名称和额外数据决定。
偏移 | 字段 | 描述 |
---|---|---|
0 - 7 | l1_offset | 快照的L1表起始在镜像内偏移,cluster对齐 |
8 - 11 | l1_size | 快照的L1表项数量 |
12 - 13 | id_size | 快照唯一ID字符串长度 |
14 - 15 | name_size | 快照名字长度 |
16 - 19 | seconds | 快照创建时间,据epoch的秒数 |
20 - 23 | nanoseconds | 快照创建时间的纳米部分 |
24 - 31 | Time that the guest was running until the snapshot was taken in nanoseconds | |
32 - 35 | vm_size | 虚拟机状态大小 |
36 - 39 | extra_size | 额外数据在表项中的大小,用于格式未来扩展 |
variable | extra_data | Extra data for future extensions. Unknown fields must be ignored. Currently defined are (offset relative to napshot table entry): Byte 40 - 47: Size of the VM state in bytes. 0 if no VM state is saved. If this field is present, the 32-bit value in bytes 32-35 is ignored. Byte 48 - 55: Virtual disk size of the snapshot in bytes Version 3 images must include extra data at least up to byte 55. |
variable | ID | 快照ID |
variable | name | 快照名称 |
variable | pad | 8字节补齐 |
[root@31 ~]# qemu-img info --output json /opt/glance/images/19c4f335-f837-484e-b599-fc7cedce48e5
{
"virtual-size" | 21474836480,
"filename" | "/opt/glance/images/19c4f335-f837-484e-b599-fc7cedce48e5",
"cluster-size" | 65536,
"format" | "qcow2",
"actual-size" | 8378843136,
"format-specific" | {
"type" | "qcow2",
"data" | {
"compat" | "1.1",
"lazy-refcounts" | false,
"refcount-bits" | 16,
"corrupt" | false
}
},
"dirty-flag" | false
}
[root@31 ~]# qemu-img convert -O qcow2 /opt/glance/images/19c4f335-f837-484e-b599-fc7cedce48e5 t1
[root@31 ~]# qemu-img info --output json t1
{
"virtual-size" | 21474836480,
"filename" | "t1",
"cluster-size" | 65536,
"format" | "qcow2",
"actual-size" | 8590069760,
"format-specific" | {
"type" | "qcow2",
"data" | {
"compat" | "1.1",
"lazy-refcounts" | false,
"refcount-bits" | 16,
"corrupt" | false
}
},
"dirty-flag" | false
}