QCOW2镜像格式

QEMU copy-on-write format with a range of special features, including the ability to take multiple snapshots, smaller images on filesystems that don’t support sparse files, optional AES encryption, and optional zlib compression

现在比较主流的一种虚拟化镜像格式,经过一代的优化,目前qcow2的性能上接近raw裸格式的性能

QCOW2镜像格式是Qemu支持的磁盘镜像格式之一。它可以使用一个文件来表示一个固定大小的块设备。与Raw镜像格式相比,QCOW2具有如下优点:

  1. 更小的文件大小,即便不支持holes(稀疏文件)的文件系统同样适用
  2. 支持写时拷贝(COW, Copy-on-write),QCOW2镜像只反映底层磁盘镜像所做的修改
  3. 支持快照,QCOW2镜像可以包含镜像历史的多重快照
  4. 支持基于zlib的数据压缩
  5. 支持AES加密

qemu-img是管理镜像文件文件最常用的命令,使用方法如下:

# 创建一个名为test.qcow2,大小为4G的qcow2镜像

$ qemu-img create -f qcow2 test.qcow2 4G

# 将QCOW2格式的test.qcow2文件转换成raw格式的test.img文件

$ qemu-img convert test.qcow2 -O raw test.img

QCOW2头

每一个QCOW2文件均以一个大端(big endian)格式的头开始,其格式如下:

typedef struct QCowHeader {

      uint32_t magic;

      uint32_t version;

      uint64_t backing_file_offset;

      uint32_t backing_file_size;

      uint32_t cluster_bits;

      uint64_t size; /* in bytes */

      uint32_t crypt_method;

      uint32_t l1_size;

      uint64_t l1_table_offset;

      uint64_t refcount_table_offset;

      uint32_t refcount_table_clusters;

      uint32_t nb_snapshots;

      uint64_t snapshots_offset;

  } QCowHeader;

  • 前四个字节magic字段包含了字符’Q’,’F’和’I’,接下来是0xfb。
  • 接下来的四个字节version字段表示文件所使用的格式版本号。当前有两种版本格式,版本1和版本2,即QCOW和QCOW2.我们将重点介绍QCOW2,结尾处我们会对QCOW和QCOW2进行比较。
  • hacking_field_offset字段给出了文件起始位置到包含文件路径字符串的距离偏移值,该字段为8字节;backing_file_size字段给出了表示文件路径的字符串(非’\0’结尾)的长度。如果该镜像文件为COW镜像,该字符串指向原始文件的绝对路径。后续我们会继续讨论。
  • cluster_bits字段,该4字节字段描述了如何将镜像偏移位置映射到本地文件中;该字段决定了在一个簇中,可作为索引的偏移地址低位比特位数。由于L2表独占了一个簇,并包含8字节的项,因此地址中cluster_bits减3之外的其余高位比特作为L2表的索引值。L2表的详细内容会在如下的2级检索中介绍。
  • 接下来的8字节,size字段,表示了该镜像所表示的块设备大小,块设备大小值以字节为单位。
  • cypt_method字段包含0和1两种值,为0时表示没有使用加密方法,1表示采用了AES加密算法。
  • l1_size字段给出了L1表的大小,l1_table_offset字段给出了L1表中偏移值。
  • refcount_table_offset给出了refcount表的偏移量,refcount_table_clusters描述了以簇为单位的refcount表的大小。
  • 每一个快照都有一个QCowSnapshotHeader,nb_snapshots给出了镜像中包含的快照数目,即QCowSnapshotHeader的数目,snapshots_offset字段给出了QCowSnapshotHeader的偏移值。

通常一个镜像文件包含以下几部分:

  • 上文中提到的头文件信息
  • L1表,以簇对齐,从下一个簇的起始点存储
  • refcount表,同样为簇对齐
  • 一个或者多个refcount块
  • 快照头,第一个头要求簇对齐,其余的头要求8字节对齐
  • L2表,每个表独占一个簇
  • 数据簇

二级检索

    对于QCOW2镜像格式,磁盘设备的内容保存在簇中。每一个簇包含多个512字节的扇区。

    为了将给定的地址定位到簇的地址,必须要遍历L1表和L2表。L1表中存储了一组到L2表的偏移值,而L2表中存储了一组到簇的偏移值。

    根据cluster_bits字段,给定的地址被划分为三个单独的偏移值。假设cluster_bits的值为12,那么地址可按如下步骤划分:

  • 地址的低12位作为4Kb的簇偏移值
  • 接下来的9比特表示L2表中512个表项数组的偏移值。由于L2表是一个包含8字节项的单独簇,因此这里需要的比特数的计算方式为l2_bits=cluster_bits – 3。
  • 剩下的43比特为L1表中的8字节文件偏移值。

    注意,L1表的最小值可以通过给定的磁盘镜像大小来计算,计算方法如下:

l1_size = round_up(disk_size / (cluster_size * l2_size), cluster_size)

    总而言之,为了将磁盘镜像地址映射到镜像文件偏移值,需要经历如下步骤:

  1. 使用l1_table_offset字段获取L1表的地址
  2. 使用地址中的高(64-l2_bits-cluster_bits)位来检索L1表中的8字节数组项
  3. 使用L1表中的偏移值获取L2表的地址
  4. 使用地址中的l2_bits字段来检索L2表中的8字节数组项
  5. 使用L2表中偏移值来获取簇的地址
  6. 使用地址中剩下的cluster_bits字段作为簇中地址偏移值

如果L1或者L2表中获取的偏移值为0,则表示磁盘镜像对应的区域尚未被分配。

    还需注意的是,L1和L2表中偏移值的高2位为“Copied”和“Compress”的预留比特位。具体细节见下文。

引用计数

    每一个簇都会被引用计数,这样做的目的是允许这些簇在不被任何快照使用的前提下能够及时的释放。

    每一个簇的引用计数为2字节,这2字节的引用计数均保存在簇大小的块中。refcount块在镜像中的偏移值可以检索refcount表得到,而引用计数表则由refcount_table_offset和refcount_table_clusters共同定位,其中refcount_table_offset指定了refcount表相对起始位置的偏移值,refcount_table_clusters指定了refcount表占用的簇数。

为了获取某个簇的引用计数,可以将簇偏移值划分为refcount表偏移值和refcount块偏移值。由于refcount块是一个两字节的存储项,簇偏移值的低cluster_size – 1位表示块偏移值,其余的位数表示表偏移值。

这里QCOW2有一个优化处理,如果任何由L1表或者L2表的指向的簇的引用计数为1,则L1或L2表项最高位被置为“copied”标记。这意味着没有快照在使用当前簇,当前簇可以直接被写入,而不需要创建引用当前簇的快照。

Copy-on-Write镜像

    QCOW2镜像可以用来存储另一个磁盘镜像的修改内容,而不影响原有磁盘的内容。这种镜像被称之为拷贝镜像,以用户的角度看起来像是一个独立的镜像文件,但是其中的大部分数据是从原始镜像中获取到的。只有原始镜像的簇发生改变的内容才会被存储到拷贝镜像中。

    这种表示方式很容易实现。可以通过在Copy-on-write镜像中包含原始磁盘镜像中的路径,头文件中记录原文件的路径字符串。

    当读取Copy-on-write镜像中的簇时,首先检查该区域是否存在Copy-on-write镜像文件内。如果不存在,则从原始磁盘镜像中读取对应的位置。

快照

    快照同COW文件概念比较相似,区别在于原文件是可写的,而快照不可写。

    近一步解释—一个COW镜像也可被称为“快照”,因为COW确实表示了原始镜像文件的状态。我们可以通过创建多个COW镜像来实现对原始镜像的“快照”,每一个镜像指向原始镜像。值得注意的是,原始镜像必须保持只读,而COW快照为可写。

    快照—“真实快照”—存在于原始镜像文件中。每个快照都是原始镜像在过去的某个时刻的只读记录。原始镜像文件一直保持可写的状态,当原始文件发生改变时,写时复制出来的簇可以被不同的快照引用。

每个快照对应如下头:

typedef struct QCowSnapshotHeader {
      /* header is 8 byte aligned */
      uint64_t l1_table_offset;
      uint32_t l1_size;
      uint16_t id_str_size;
      uint16_t name_size;
      uint32_t date_sec;
      uint32_t date_nsec;
      uint64_t vm_clock_nsec;
      uint32_t vm_state_size;
      uint32_t extra_data_size; /* for extension */
      /* extra data follows */
      /* id_str follows */
      /* name follows  */
  } QCowSnapshotHeader;

各字段解释如下:

  • 每个快照都有一个name和ID,均为字符串格式(非’\0’结尾),其位置在QCOWSnapshotHeader头之后。
  • 每个快照至少保留L1表的副本, 其值体现在l1_table_offset和l1_size上。
  • 快照创建时,通过date_sec和date_nsec获取到主机的gettimeofday()
  • vm_clock_nsec表示VM锁的当前状态
  • vm_state_size表示虚机状态的大小,而虚机状态作为快照的一部分被存储起来。虚机状态被保存在原始L1表中,紧随镜像头之后。
  • extra_data_size表示在头之后扩展数据的长度,不包括ID和name字符串。该字段为后续扩展使用。

    每创建一个快照就会增加一个头文件,复制L1表的内容,并增加所有L2表中的引用计数和被L1表引用的数据簇。之后,如果镜像中的任何L2表或者数据簇被修改了—也就是说,簇的引用计数值超过1,并且/或者当前簇的“拷贝”标志已被标记—Qemu会先拷贝这些L2表和数据簇,而后再进行写入。这样所有的快照都不会被修改。

压缩

    QCOW2镜像格式支持压缩特性,允许每一个簇可以独立通过zlib进行压缩。

    可以通过如下步骤从L2表中获取簇偏移值:

  • 如果簇偏移值的最高位为1,则表示该簇已被压缩
  • 簇偏移值接下来的cluster_bits – 1位为压缩簇的大小,其单位为512字节的扇区
  • 簇偏移值的其余位数为镜像中簇的实际地址

加密

    QCOW2镜像格式同样支持簇的加密特性。

    若QCowHeader头中的crypt_method字段值为1,则会采用16字符128比特的AES秘钥进行加密。

簇中的每一个扇区都是通过AES密码块链接模式单独进行加密,采用小端模式的扇区偏移地址(相对于设备的起始位置)来作为128位初始化向量的头64位。

QCOW2镜像与上一代镜像

QCOW2相对于QCOW有如下不同之处:

  1. QCOW2支持快照概念,QCOW1仅支持copy-on-write镜像的概念
  2. QCOW2中引用了引用计数的概念,引用计数用来支持快照的概念
  3. QCOW2中L2表总是可以占据一个单独的簇,而之前簇的大小在头l2_bits中被指定
  4. QCOW2压缩簇的大小以扇区为单位,而非字节为单位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/341290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

for循环简介及实例(输出九九乘法表)

for循环简介 简介 for循环是3大循环其中一种,相比while循环和do while循环,它更加灵活,而且完全包含了while循环的功能,用for语句可以解决编程中所有循环问题。 语法格式 for(语句1;表达式1;表达式2) 语句 //语句1一般用于设置…

Windows下使用net user命令管理账户

准备工作-以管理员身份运行命令提示符(cmd) 鼠标左键单击Windos标志或者按下键盘Windows键,下滑菜单,在Windows系统 中找到命令提示符。 2.右键,更多->以管理员身份运行 net user 命令用法 1.查看所有用户 net…

Java中带有NetSuite数据实体的对象关系映射(ORM)

对象关系映射(ORM)技术使使用关系数据源更容易,并且可以将逻辑业务模型与物理存储模型联系在一起。 遵循本教程,将与NetSuite数据的连接集成到基于Java的ORM框架Hibernate中。 您可以使用Hibernate将面向对象的域模型映射到传统的…

vmware中ubuntu虚拟机扩容

两种扩容方式: 重新创建一块虚拟硬盘 扩大原来的硬盘:如果装系统时没有进行手动分区,系统只有两个分区(根分区和交换分区),这种情况我们直接扩展根分区的大小。 我们是为了解决当前用户空间不够的问题&…

pat 乙级 1021 个位数统计(C++)

题目 给定一个 k 位整数 Nd​k−1​​10​k−1​​⋯d​1​​10​1d​0(0≤d​i≤9, i0,⋯,k−1, d​k−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N100311,则有 2 个 0,3 个 1,和 1 个 3。 输…

该虚拟机似乎正在使用

该虚拟机似乎正在使用 点击获取所有权,此时虚拟机还是不能打开。 打开Vmware虚拟机虚拟磁盘文件和配置文件存放的位置 删除后缀为.lck的文件夹 然后开启此虚拟机就可以啦

PAT 乙级(Basic Level) 题解汇总(持续更新)(C++)

前言 为了准备3月份的CCF CSP认证,以及提升自己的编程能力和数据结构与算法基础,目前我坚持每天刷pat乙级题库,然后记录在CSDN。一则,希望夯实我做过的题和学到的东西;二则,希望对和我一样的小伙伴有些许帮…

反射是最重要的Java API

前几天我在想-这是最重要的Java API。 哪种SE和EE API可以使大多数Java生态系统成为可能,而哪些API不能刚刚被重新创建为第三方库。 正如您可能已经猜到标题一样,我认为它是Reflection API 。 是的,它不可避免地是每个项目的直接或间接的一部…

Wireshark常用过滤使用方法

过滤源ip、目的ip。 在wireshark的过滤规则框Filter中输入过滤条件。如查找目的地址为192.168.101.8的包,ip.dst192.168.101.8;查找源地址为ip.src1.1.1.1 端口过滤。 如过滤80端口,在Filter中输入,tcp.port80,这条规…

pat 乙级 1003 我要通过!(C++)

题目 “答案正确"是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出"答案错误”。 得到"答案正确"的条件是: 字符串中必…

【C】printf按8进制、10进制、16进制输出以及高位补0

#include <iostream> #include <iomanip> #include "Circle.h" // Circle class declaration file int main() { int PrintVal 9;/*按整型输出&#xff0c;默认右对齐*/printf("%d\n",PrintVal);/*按整型输出&#xff0c;补齐4位的宽度&#…

pat 乙级 1005 继续(3n+1)猜想(C++)

题目 卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。 当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递推过程中遇到的每一个数。例如对 n3 进行验证的时候&#xff0c;我们需要计算 3、5、8、4、…

带有Spring Boot和Spring Cloud的Java微服务

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户&#xff1f; 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 Java是开发微服务架构时使用的一种很棒的语言。 实际上&#xff0c;我们行业中的一些知名人士…

pat 乙级 1018 锤子剪刀布(C++)

题目 两人玩锤子剪刀布&#xff0c;现给出两人的交锋记录&#xff0c;请统计双方的胜、平、负次数&#xff0c;并且给出双方分别出什么手势的胜算最大。 输入格式&#xff1a; 输入第 1 行给出正整数 N&#xff08;≤105 &#xff09;&#xff0c;即双方交锋的次数。随后 N …

Terminal中输入一行命令快速移动光标至行首行尾

Linux&#xff1a;### ①快速移动光标至行首 **Home或CtrlA ** ②快速移动光标至行尾 **End或CtrlE ** ③从光标处开始删除&#xff0c;直到行尾 **CtrlK ** ④到下一行 **CtrlN 或 方向键&#xff1a;↓ ** ⑤到上一行 **CtrlP 或 方向键&#xff1a;↑ **

nio2和nio2_列出和过滤NIO.2中的目录内容

nio2和nio2在Java 7发行之前&#xff0c;列出目录内容的领域并没有发生太多事情。但是&#xff0c;由于NIO.2引入了一种新的方法来做到这一点&#xff0c;因此覆盖这一领域可能是值得的。 NIO.2的一大优点是能够在一个方法调用中立即使用列表和过滤。 这为与文件系统相关的大多…

pat 乙级 1033 旧键盘打字(C++)

题目 旧键盘上坏了几个键&#xff0c;于是在敲一段文字的时候&#xff0c;对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键&#xff0c;打出的结果文字会是怎样&#xff1f; 输入格式&#xff1a; 输入在 2 行中分别给出坏掉的那些键、以及应该输入的文…

修改typora主题的字体

简 述&#xff1a; 在 mac 中修改 typora 主题的英文和中文的字体&#xff0c;使得码字更加舒服&#xff08;win 也有效&#xff09;。 [TOC] 本文初发于 “偕臧的小站“&#xff0c;同步转载于此。 书写环境&#xff1a; &#x1f4bb;&#xff1a; MacOS 10.14.6 &#x1…

在ADF 12.2.1.3中使用基于JSON的REST Web服务

以前&#xff0c;我曾发布过有关在ADF中使用基于ADF BC的REST Web服务的信息。 现在&#xff0c;本文讨论使用通用数据控件使用基于JSON的REST Web服务。 您也可以查看有关Web服务的先前文章&#xff0c;以获取更多信息。 在ADF 12.2.1中使用应用程序模块快速创建SOAP Web服务…