Gravando imagens com a ferramenta bmaptool
- por Sergio Prado
Bmaptool é uma ferramenta genérica para gravar imagens em dispositivos de armazenamento, e pode ser uma alternativa mais confiável e rápida que o bom e velho comando dd.
Ela foi criada para o projeto Tizen IVI e possui diversas vantagens quando comparada ao comando dd, incluindo:
- Muito mais rápida (dependendo de alguns fatores como velocidade de escrita em disco e tamanho da imagem, pode ser de 5 a 7 vezes mais rápida).
- Mais confiável pois verifica a integridade dos dados durante a gravação.
- Mais segura pois evita a gravação de imagens em partições montadas.
- Capaz de ler imagens diretamente de servidores remotos, sem a necessidade de fazer o download antes da gravação.
- Capaz de ler imagens comprimidas para gravação, sem a necessidade de descomprimir antes de gravar.
Para entender melhor como a ferramenta bmaptool consegue ser mais rápida que o comando dd, é necessário conhecer um tipo de arquivo especial no Linux chamado “sparse file”.
SPARSE FILES
Todo arquivo no Linux tem um tamanho aparente (lógico) e um tamanho real (físico) ocupado em disco.
Um arquivo vazio tem o tamanho aparente de 0 bytes e um tamanho real ocupado em disco também de 0 bytes (sem considerar o espaço ocupado pelos metadados do arquivo no sistema de arquivos).
Veja por exemplo a listagem de um arquivo vazio no comando abaixo. O tamanho real é primeiro “0”, e o tamanho aparente é o “0” logo após o nome do usuário/grupo.
$ ls -slh teste.txt 0 -rw-rw-r-- 1 sprado sprado 0 Nov 22 06:51 teste.txt |
Se escrevermos 1 byte neste arquivo, o tamanho aparente mudará para 1, porém o tamanho real ocupado em disco será de 4k, já que o sistema de arquivos precisou alocar um novo bloco para armazenar este byte:
$ echo -n "a" >> teste.txt $ ls -slh teste.txt 4,0K -rw-rw-r-- 1 sprado sprado 1 Nov 22 06:53 teste.txt |
E se escrevermos um novo byte neste arquivo, o tamanho aparente aumenta para 2, porém o tamanho real ocupado em disco continua o mesmo, já que o bloco alocado anteriormente será utilizado para armazenar este segundo byte (um novo bloco será alocado apenas quando utilizarmos todo o primeiro bloco).
$ echo -n "b" >> teste.txt $ ls -slh teste.txt 4,0K -rw-rw-r-- 1 sprado sprado 2 Nov 22 06:55 teste.txt |
O que acontece se eu abrir este arquivo, fazer um seek para a posição 1048576 (1MB) e escrever 1 byte nesta posição?
Podemos fazer isso com o comando dd:
$ echo "c" | dd of=teste.txt bs=1 count=1 seek=1048576 1+0 records in 1+0 records out 1 byte copied, 0,000177506 s, 5,6 kB/s |
Sim, o sistema de arquivos permitiu fazer um seek para uma posição inexistente do arquivo e escrever 1 byte nesta posição! E como ficaram os tamanhos real e aparente do arquivo?
$ ls -slh teste.txt 8,0K -rw-rw-r-- 1 sprado sprado 1,1M Nov 22 06:59 teste.txt |
Wow! Um arquivo com tamanho aparente de 1,1M que ocupa apenas 8k (2 blocos de 4K) em disco!
O que aconteceu aqui? O arquivo ficou com um buraco (hole) de 1M entre o segundo byte (“b”) e o terceiro byte (“c”) escrito pelo comando dd. Este buraco não ocupa espaço em disco e se você tentar lê-lo, receberá um monte de zeros:
$ hexdump -C teste.txt 00000000 61 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |ab..............| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00100000 63 |c| 00100001 |
Um arquivo com buracos é chamado de sparse file. É um recurso do sistema de arquivos para pré-alocar espaço em um arquivo de forma otimizada, sem a necessidade de ocupar fisicamente espaço em disco.
A imagem abaixo, tirada da Wikipedia, exemplifica bem um sparse file:
A maioria dos sistemas de arquivo modernos suporta sparse files, incluindo ext4, btrfs e ntfs.
Um sparse file pode ser criado facilmente com a ferramenta truncate. Por exemplo, o comando abaixo irá criar um arquivo de 1G que não ocupa nada em disco:
$ truncate -s1G image.raw $ ls -slh image.raw 0 -rw-rw-r-- 1 sprado sprado 1,0G Nov 22 07:13 image.raw |
Sparse files são utilizados por muitas ferramentas e aplicações no Linux. Por exemplo, as ferramentas de virtualização (VMWare, VirtualBox, etc) criam imagens de máquina virtual com tamanho pré-definido utilizando sparse files.
Vamos agora voltar para a ferramenta bmaptool.
BMAPTOOL
A ferramenta bmaptool é capaz de identificar sparse files e evitar a leitura e gravação dos buracos existentes nos arquivos, diminuindo consideravelmente o tempo de gravação das imagens.
Como exemplo, vamos pegar a imagem do Debian da Beaglebone Black:
$ ls -slh bone-debian-9.5-iot-armhf-2018-08-30-4gb.img 2,0G -rw-rw-r-- 1 sprado sprado 3,4G Set 26 13:15 bone-debian-9.5-iot-armhf-2018-08-30-4gb.img |
Esta imagem tem um tamanho aparente de 3.4GB, porém um espaço físico ocupado em disco de 2GB. Ou seja, ela tem um buraco de aproximadamente 1.4GB que não precisa ser lido/gravado no disco.
Como o comando dd não sabe lidar com sparse files, ele irá ler e gravar toda a imagem, incluindo os buracos. No teste que fiz, levou quase 11 minutos para gravar esta imagem em um cartão SD.
$ time sudo dd if=bone-debian-9.5-iot-armhf-2018-08-30-4gb.img of=/dev/sdb bs=4M conv=fsync 850+0 records in 850+0 records out 3565158400 bytes (3,6 GB, 3,3 GiB) copied, 644,936 s, 5,5 MB/s real 10m44.963s user 0m0.040s sys 0m8.952s |
Já a ferramenta bmaptool será muito mais rápida ao gravar esta imagem.
Para utilizá-la, o primeiro passo é gerar um arquivo com o mapa de blocos da imagem utilizando o parâmetro create da ferramenta. Este comando leva alguns segundos para executar.
$ bmaptool create bone-debian-9.5-iot-armhf-2018-08-30-4gb.img > bmap.cfg |
E então, para gravar a imagem, basta rodar a ferramenta com o parâmetro copy, passando o arquivo com o mapa de blocos da imagem:
$ time sudo bmaptool copy bone-debian-9.5-iot-armhf-2018-08-30-4gb.img /dev/sdb --bmap bmap.cfg bmaptool: info: block map format version 2.0 bmaptool: info: 870400 blocks of size 4096 (3.3 GiB), mapped 506443 blocks (1.9 GiB or 58.2%) bmaptool: info: copying image 'bone-debian-9.5-iot-armhf-2018-08-30-4gb.img' to block device '/dev/sdb' using bmap file 'bmap.cfg' bmaptool: info: 100% copied bmaptool: info: synchronizing '/dev/sdb' bmaptool: info: copying time: 6m 17.5s, copying speed 5.2 MiB/sec real 6m17.941s user 0m9.500s sys 0m4.512s |
A gravação levou em torno de 6 minutos, quase a metade do tempo do comando dd! :-)
A ferramenta é escrita em Python e seu código-fonte, incluindo instruções de instalação e uso, estão disponíveis no site do projeto no GitHub.
Um abraço,
Sergio Prado