Convertendo arquivo esparso para não esparso no lugar

8

No Linux, dado um arquivo esparso, como torná-lo não esparso, no lugar?
Pode ser copiado com cp --sparse=never ... , mas se o arquivo for 10G e o furo for 2G (isto é, o espaço alocado é 8G), como fazer com que o sistema de arquivos aloque os 2G restantes sem copiar o 8G original para um novo arquivo?

    
por Ivan 24.11.2014 / 11:39

1 resposta

10

Em face disso, é um simples dd :

dd if=sparsefile of=sparsefile conv=notrunc bs=1M

Isso lê o arquivo inteiro e grava todo o conteúdo nele.

Para escrever apenas o furo, você primeiro precisa determinar onde estão esses buracos. Você pode fazer isso usando filefrag ou hdparm :

filefrag:

# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1048575:  187357696.. 188406271: 1048576:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188406272: last,eof
sparsefile: 2 extents found

hdparm:

# hdparm --fibmap sparsefile

sparsefile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0 1498861568 1507250175    8388608
  6442450944 1605633024 1614021631    8388608

Este arquivo de exemplo é, como você diz, 10G em tamanho com um 2G hole. Ele tem duas extensões, a primeira cobrindo 0-1048575 , a segunda 1572864-2621439 , o que significa que o furo é 1048576-1572864 (em blocos de tamanho 4k, como mostrado por filefrag ). As informações mostradas por hdparm são as mesmas, apenas exibidas de forma diferente (a primeira extensão abrange 8388608 setores de 512 bytes começando por 0, então é 0-4294967295 bytes, portanto, o furo é 4294967296-6442450944 em bytes.

Note que você pode ser mostrado consideravelmente mais extensões de qualquer maneira, se houver alguma fragmentação. Infelizmente, nenhum dos comandos mostra os buracos diretamente, e eu não conheço um que faça isso, então você deve deduzi-lo das compensações lógicas mostradas.

Agora, preencher esse 1048576-1572864 com dd , como mostrado acima, pode ser feito adicionando valores% (%)seek / skip (%) e count apropriados (idênticos). Observe que o bs= foi adaptado para usar os 4k setores usados por filefrag acima. (Para bs=1M , você teria que adaptar os valores de seek / skip / count para refletir os blocos 1M sized).

dd if=sparsefile of=sparsefile conv=notrunc \
   bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))

Embora você possa preencher furos com /dev/zero em vez de ler o furo do arquivo em si (que também renderá zeros), é mais seguro ler o sparsefile de qualquer maneira, para que você não corrompa seus dados caso você tenha um deslocamento errado.

Nas versões mais recentes de GNU dd , você pode manter um tamanho maior de blocos e especificar todos os valores em bytes:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
   iflag=skip_bytes,count_bytes oflag=seek_bytes \
   seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))

filefrag depois de executar isso:

# sync
# filefrag -e sparsefile 
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1572863:  187357696.. 188930559: 1572864:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188930560: last,eof
sparsefile: 2 extents found

Devido à fragmentação, ainda são duas extensões. No entanto, as compensações lógicas mostram que, desta vez, não há nenhum furo, portanto, o arquivo não é mais esparso.

Naturalmente, essa solução dd é a abordagem muito manual das coisas. Se você precisar disso regularmente, seria fácil escrever um pequeno programa que preenche essas lacunas. Se já existe como uma ferramenta padrão, ainda não ouvi falar disso.

Existe uma ferramenta, afinal, fallocate parece funcionar, de certa forma:

fallocate -l $(stat --format="%s" sparsefile) sparsefile

No entanto, por fim, no caso do XFS, enquanto ele aloca área física para esse arquivo, ele não é zerado. filefrag mostra extensões como alocadas, mas não escritas.

   2:        3..      15:    7628851..   7628863:     13:    7629020: unwritten

Isso não é suficiente se a intenção for ler os dados corretos diretamente do dispositivo de bloco. Apenas reserva o espaço de armazenamento necessário para gravações futuras.

    
por 24.11.2014 / 12:18