Primeiro, você não está sozinho em intrigas sobre esse tipo de problema.
Isso não se limita apenas a, tmpfs
mas tem sido uma preocupação citada com o
NFSv4 .
Se um aplicativo lê 'buracos' em um arquivo esparso, o sistema de arquivos converte blocos vazios em blocos "reais" preenchidos com zeros e os retorna ao aplicativo.
Quando md5sum
está tentando digitalizar um arquivo, ele decide explicitamente fazer isso em
ordem seqüencial , o que faz muito sentido com base no que o md5sum está tentando fazer.
Como existem fundamentalmente "brechas" no arquivo, essa leitura seqüencial (em algumas situações) causa uma operação de cópia em gravação para preencher o arquivo. Isso então entra em uma questão mais profunda sobre a fallocate()
implementação ou não do suporte ao sistema de arquivos FALLOC_FL_PUNCH_HOLE
.
Felizmente, não apenas tmpfs
suporta isso, mas também existe um mecanismo para "cavar" os buracos.
Usando o utilitário CLI fallocate
, podemos detectar e refazer esses furos com êxito.
Conforme man 1 fallocate
:
-d, --dig-holes
Detect and dig holes. This makes the file sparse in-place, without
using extra disk space. The minimum size of the hole depends on
filesystem I/O block size (usually 4096 bytes). Also, when using
this option, --keep-size is implied. If no range is specified by
--offset and --length, then the entire file is analyzed for holes.
You can think of this option as doing a "cp --sparse" and then
renaming the destination file to the original, without the need for
extra disk space.
See --punch-hole for a list of supported filesystems.
fallocate
opera no nível do arquivo e, quando você está executando md5sum
em um dispositivo de bloco (solicitando leituras seqüenciais), está observando o espaço exato entre como o fallocate()
syscall deve operar. Podemos ver isso em ação:
Em ação, usando o seu exemplo, vemos o seguinte:
$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ONTGAS8L06
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ONTGAS8L06/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ sudo md5sum /dev/loop0
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 102400 /tmp/tmp.ONTGAS8L06/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ONTGAS8L06/sparse100M
Agora ... isso responde à sua pergunta básica. Meu lema geral é "ficar estranho", então eu cavei mais ...
$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ZcAxvW32GY
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 516 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 512 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
Você vê que apenas o ato de executar as losetup
alterações altera o tamanho do arquivo esparso. Portanto, isso se torna uma combinação interessante de onde tmpfs
, o mecanismo HOLE_PUNCH fallocate
e os dispositivos de bloco se cruzam.