You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何高效地将稀疏分区镜像写入磁盘镜像?

如何高效地将稀疏分区镜像写入磁盘镜像?

我来帮你解决这个恼人的问题!你用dd遇到的核心痛点就是它会傻乎乎地遍历整个镜像文件的大小——哪怕大部分都是稀疏空洞,也会把这些“假”的全零块一股脑写入,自然慢得离谱。而且conv=sparse的隐患你也说到了,要是目标磁盘镜像的对应区域之前有数据,直接用这个参数会残留旧数据,确实不靠谱。

下面给你几个实用的解决方案,从ext4专属的最优解到通用方法都有:

一、Ext4专属最优解:用e2image提取实际数据再写入

既然你的分区是ext4格式,直接利用ext4的元数据工具e2image就能精准提取出分区里真正有数据的部分,完全跳过空洞:

  1. 先把稀疏分区镜像转换成只包含已使用块的紧凑镜像:
    e2image -rap small.img small.raw
    e2image -rap rootfs.img rootfs.raw
    
    这里-r表示只读模式(避免破坏原镜像),-a会复制所有已分配的块,-p还能显示进度条,方便你追踪进度。生成的.raw文件大小就是分区实际占用的空间(比如你说的67MB、120MB),而不是原来的300MB、20GB。
  2. 再用dd把紧凑镜像写入磁盘镜像的对应位置:
    dd if=small.raw of=disk.img seek=1 bs=1M conv=notrunc
    dd if=rootfs.raw of=disk.img seek=301 bs=1M conv=notrunc
    
    这次dd只需要复制几十MB的数据,速度会快到飞起,而且完全不用担心空洞的问题。

二、通用方法:用ddiflag=sparse参数跳过空洞

如果你需要兼容其他文件系统的稀疏镜像,或者不想额外处理镜像文件,可以直接给dd加上iflag=sparse参数,让它自动识别输入文件里的空洞并跳过写入:

dd if=small.img of=disk.img seek=1 bs=1M conv=notrunc iflag=sparse
dd if=rootfs.img of=disk.img seek=301 bs=1M conv=notrunc iflag=sparse

这个参数会让dd读取输入时,遇到稀疏空洞就直接跳过,只写入真正有数据的块。现代Linux发行版的dd基本都支持这个参数,操作简单,不用额外转换镜像。

小提醒

如果你的disk.img不是全新创建的(比如之前有写入过数据),那目标分区对应的区域可能残留旧数据,这时候最好先把目标区域清零:

# 清零small分区对应的300MB区域(从1MiB开始)
dd if=/dev/zero of=disk.img seek=1 bs=1M count=300 conv=notrunc
# 清零root分区对应的剩余区域(从301MiB开始)
dd if=/dev/zero of=disk.img seek=301 bs=1M conv=notrunc

清零后再用带iflag=sparsedd写入,就不会有旧数据残留的问题了。

为什么原来的dd这么慢?

简单说就是dd默认不识别稀疏文件的空洞,它会把输入文件里的空洞当成全零块来读取和写入——哪怕是20GB的空洞,也会老老实实写20GB的零,速度当然慢。而上面的两种方法,要么直接提取有效数据,要么自动跳过空洞,自然能大幅提升速度。

备注:内容来源于stack exchange,提问作者Fadeway

火山引擎 最新活动