qcow文件格式描述
官网说明文档:
https://github.com/zchee/go-qcow2/blob/master/docs/specification.md
https://github.com/Xilinx/qemu/blob/master/docs/specs/qcow2.txt
vim [某虚拟机的qcow2文件]
%!xxd
- 0 - 3 : magic QCOW magic string ("QFI\xfb") 4个字节固定的标识符
- 4 - 7 : version Version number (valid values are 2 and 3) 版本号,2或者3
- 8 - 15 : backing_file_offset 文件路径字符串相对于文件起始位置的偏移地址,这个字符串不是以0结束的。该值为0时,表示该镜像没有 backing file
0000 0000 0000 0118 -> 0000 0001 0001 1000 256+24=280 看左边的地址定位
- 16 - 19 : backing_file_size 文件路径字符串长度,单位是字节数。必须小于1023字节。镜像没有backing file时,该值无意义
0000 0079
400 280
0x00000190-0x00000118 =ox78 + 1 = 121
- 20 - 23 : cluster_bits cluster 位数,代表了 cluster 大小(1 << cluster_bits 就是 cluster 的大小)。不能小于9,也就是每个 cluster 大小不能小于 512个字节。 Note:新版本的qemu启用了最大 2MB 的 cluster 大小。
0000 0010
- 24 - 31 : size 虚拟磁盘的大小,单位字节,这个是呈现给用户的大小(virt-df查看),不是文件实际大小
0000 0002 8000 0000
- 32 - 35 : crypt_method 0 - 未加密;1 - AES加密
0000 0000
- 36 - 39 : l1_size L1 table项数
0000 0014 = 20
- 40 - 47 : l1_table_offset L1 table 相对于镜像文件起始位置的偏移, 必须与 cluster 对齐
0000 0000 0004 0000 = 4 * 2^12 看左边的地址即可
- 48 - 55 : refcount_table_offset refcount table 相对于镜像文件起始位置的偏移。必须与 cluster 对齐
0000 0000 0001 0000
- 56 - 59 : refcount_table_clusters refcount table 占用了多少个 cluster
0000 0001
- 60 - 63 : nb_snapshots 镜像文件中包含了多少个快照。
0000 0000
- 64 - 71 : snapshots_offset 快照table相对于镜像文件起始位置的偏移,必须与cluster对齐
0000 0000 0000 0000
版本号如果为3,头部还会有以下附加的信息,在版本2中,这些值都是0,除非特别说明:
- 72 - 79 : incompatible_features 未实现的特征的位掩码,在解析文件的时候,如果发现某个未知的位被设置为1,就是需要报错的时候了。
0000 0000 0000 0000
Bit 0 脏位。如果该位为1,refcounts可能和实际情况是不一致的,在解析的时候需要扫描一遍 L1/L2 table 来修复 refcounts。
Bit 1 损坏位。如果该位为1,任何数据结构可能损坏,且镜像不应该被写。
Bits 2-63 Reserved (set to 0) 保留,应该为0。
Bitmask of incompatible features. An implementation must
fail to open an image if an unknown bit is set.
Bit 0: Dirty bit. If this bit is set then refcounts
may be inconsistent, make sure to scan L1/L2
tables to repair refcounts before accessing the
image.
Bit 1: Corrupt bit. If this bit is set then any data
structure may be corrupt and the image must not
be written to (unless for regaining
consistency).
Bits 2-63: Reserved (set to 0)
- 80 - 87 : compatible_features 兼容特征的位掩码。解析的时候完全可以忽略这些位。
0000 0000 0000 0000
Bit 0: 该位为1,则 lazy refcount 更新可以被使用。 意味着 dirty bit 为1,并且推迟refcount 元数据的更新。
Bits 1-63: Reserved (set to 0)
- 88 - 95 : autoclear_features 我的理解是…… 对于这些autoclear feature,在处理镜像时,如果某一位含义未知,则应该先将其设置为0,再进行写镜像操作。
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.
0000 0000 0000 0000
Bit 0:这一位表示 bitmap extension 数据一致性。 如果这一位为1,但不存在 bitmaps extension,则应该报错;如果存在 bitmap extension 但这一位为0,则应认为 bitmap extension data 不一致(存在问题?)。
Bits 1-63: Reserved (set to 0)
- 96 - 99 : refcount_order refcount block项的宽度(bit宽度),版本2时,固定为4,也就是说 refcount_bits = 16.该值不超过6,也就是 refcount_bits 不超过 64。refcount_bits = 1 << refcount_order
0000 0004
- 100 - 103: header_length 文件头结构体的长度,版本2时,长度固定为72字节。
0000 0068 104字节 也就是刚好到该位置
关于header extensions,头部扩展性选项
紧接着镜像的文件头,存储的是可选的多个 header extensions,header extensions定义
typedef struct Qcow2UnknownHeaderExtension {
uint32_t magic;
uint32_t len;
QLIST_ENTRY(Qcow2UnknownHeaderExtension) next;
uint8_t data[];
} Qcow2UnknownHeaderExtension;
字段说明
Byte 0 - 3: Header extension 的类型:
0x00000000 - End of the header extension area 我理解该值应该是表示没有header extension选项
0xE2792ACA - Backing file format name e279 2aca 示例中刚好是这个值
0x6803f857 - Feature name table
0x23852875 - Bitmaps extension
other - Unknown header extension, can be safely
ignored
4 - 7: header extension 的数据长度0000 0005 5byte
8 - n: Header extension数据部分 7163 6f77 32
n - m: 为对齐到 8字节的填充部分 00 0000
后面接着
6803 f857 00000090 和后面紧接着的Feature name table有关 长度为00000090 144byte
除非特别说明,每个extension类型在一个镜像里应该只会出现一次。如果有Backing file ,则在 the backing file name should be stored in the remaining space between the end of the header extension area and the end of the first cluster. It is not allowed to store other data here, so that an implementation can safely modify the header and add extensions without harming data of compatible features that it doesn't support. Compatible features that need space for additional data can use a header extension.
关于 Feature name table 和 Bitmaps extension 两种 extension 类型结构的说明
Feature name table
eature name table 是可选项:记录镜像的某种特性。应用程序使用该字段记录某种未知的特性错误信息(稍后才知道的特性),eature name table的条目数取决于header extension data的长度,每一项的结构如下:
00000080: 0000 6469 7274 7920 6269 7400 0000 0000
00000090: 0000 0000 0000 0000 0000 0000 0000 0000
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000
000000b0: 0001 636f 7272 7570 7420 6269 7400 0000
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000
000000e0: 0100 6c61 7a79 2072 6566 636f 756e 7473
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000
00000100: 0000 0000 0000 0000 0000 0000 0000 0000
三种future name table刚好144byte
Byte 0: 特性的类型 (select feature bitmap)
0: Incompatible feature 参看前面 应该是dirty bit 和 corrupt bit
1: Compatible feature
2: Autoclear feature
1: Bit number within the selected feature bitmap (valid
values: 0-63)
2 - 47: Feature name (padded with zeros, but not necessarily null
terminated if it has full length)
Bitmaps extension
bitmaps extension为可选项.可用于存储虚拟disk相关的bitmap . 当前只有一种 dirty tracking bitmap,跟踪 虚disk从某个时间点的变化。在auto-clear feature设置的情况下,需要考虑extension的数据。
Byte 0 - 3: nb_bitmaps image中bitmap的数量,大于等于1
The number of bitmaps contained in the image. Must be
greater than or equal to 1.
注意: 当前Qemu 一个image支持65535个bitmaps
4 - 7: 保留为0.
8 - 15: bitmap_directory_size
Size of the bitmap directory in bytes. It is the cumulative
size of all (nb_bitmaps) bitmap headers.
16 - 23: bitmap_directory_offset
Offset into the image file at which the bitmap directory
starts. Must be aligned to a cluster boundary.
Host cluster management
有 host cluster 和 guest cluster 的区别.这里解释了前面一直提到的refcount。对于每一个host cluster,qcow2维护了一个refcount表,应该是引用计数的概念,当refcount为0时,表示该cluster是未分配的,1表示是在使用的,>=2时表示在被使用,并且所有的写操作都要进行COW(copy on write)操作。
采用了两层表来维护管理 refcounts,第一层叫 refcount table,是可变大小的(refcount table 的 size 存储在header里),refcount table 的每一项覆盖多个 cluster,当然,在镜像文件中refcount table是连续存储的。refcount table 包含了多个指针,指向了第二层结构体,第二层结构被称为 refcount block,一个refcount block在大小上就是一个cluster。(意思就是,block也是存在一个个cluster里的),以下是根据镜像偏移量 offset,获得某个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];
注:各种变量前文有述,这里回顾一下
cluster_size = 1 << cluster_bits //最小 512 bytes
refcount_bits = 16 //in version 2
以版本2为例:
cluster_size是一个cluster的字节数,对于一个qcow2文件来说,每个cluster都是固定大小的,比如512字节。
refcount_bits固定是16,也就是2bytes,因为refcount block也要按照cluster的大小来存储,所以每个cluster能够存储的block个数: refcount_block_entries = cluster_size / 2 = 256 。
refcount_table 的一个单元对应 256 个 refcount_block,存在一个cluster里。
每个block里有2个字节(16位),记录了某个cluster的引用计数。
所以计算某个 offset 所在的 cluster 引用计数的办法,先 offset / cluster_size 得到这个offset对应的是第几个cluster,然后在refcount table里找,存在table的第几个单元里,最后在这个单元里找是第几个block存着引用计数。
下面是 refcount table 和 refcount block 的结构体定义,理解了上面这段的话,这里挺简单的了。
Refcount table entry:
Bit 0 - 8: Reserved (set to 0)
9 - 63: Bits 9-63 of the offset into the image file at which the
refcount block starts. Must be aligned to a cluster
boundary.
If this is 0, the corresponding refcount block has not yet
been allocated. All refcounts managed by this refcount block
are 0.
Refcount block entry (x = refcount_bits - 1): 这里为16-1=15
Bit 0 - x: Reference count of the cluster. If refcount_bits implies a
sub-byte width, note that bit 0 means the least significant
bit in this context.
00000000: 5146 49fb 0000 0003 0000 0000 0000 0118
00000010:0000 00790000 0010 0000 0002 8000 0000
00000020: 0000 0000 0000 0014 0000 0000 0004 0000
00000030: 0000 0000 0001 0000 0000 0001 0000 0000
00000040: 0000 0000 0000 0000 0000 0000 0000 0000
00000050: 0000 0000 0000 0000 0000 0000 0000 0000
00000060: 0000 0004 0000 0068 e279 2aca 0000 0005
00000070: 7163 6f77 3200 0000 6803 f857 00000090
00000080: 0000 6469 7274 7920 6269 7400 0000 0000
00000090: 0000 0000 0000 0000 0000 0000 0000 0000
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000
000000b0: 0001 636f 7272 7570 7420 6269 7400 0000
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000
000000e0: 0100 6c61 7a79 2072 6566 636f 756e 7473
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000
00000100: 0000 0000 0000 0000 0000 0000 0000 0000
00000110: 0000 0000 0000 0000 2f64
00000120: 7374 6163 6b2d 7072 696d 6172 792d 7374 stack-primary-st
00000130: 6f72 6167 652f 696d 6167 6563 6163 6865 orage/imagecache
00000140: 2f74 656d 706c 6174 652f 3365 3839 6131 /template/3e89a1
00000150: 3965 6566 3231 3433 3738 6166 3437 3262 9eef214378af472b
00000160: 3136 3162 3165 6662 3562 2f33 6538 3961 161b1efb5b/3e89a
00000170: 3139 6565 6632 3134 3337 3861 6634 3732 19eef214378af472
00000180: 6231 3631 6231 6566 6235 622e 7163 6f77 b161b1efb5b.qcow
00000190: 3200 0000 0000 0000 0000 0000 0000 0000 2...............
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000210: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000220: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000230: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000240: 0000 0000 0000 0000 0000 0000 0000 0000 ................
「Talk is cheap. Show me the code」