Postado por Chris Siebenmann , administrador de sistemas Unix da Universidade de TorontoDe tempos em tempos, algo estranho acontece no meu trabalho que me faz pensar. Mesmo que não seja imediatamente claro quais conclusões se seguem. Mencionei recentemente que encontramos um bug no GNU Tar, e a história de como isso aconteceu é um desses casos.
Para servidores de arquivos de backup, usamos Amanda e GNU Tar. Com o tempo, ocasionalmente tivemos um problema bastante raro, em que o tar ficou louco ao fazer backup do sistema de arquivos com o diretório
/var/mail
, produzindo uma quantidade enorme de saída. Geralmente esse processo chegava ao infinito e tinha que matar o lixão; em outros casos, ainda terminava emitindo terabytes de dados que pareciam perfeitamente compactados. Quando mais uma vez me deparei com um arquivo tar tão gigantesco, verifiquei - e descobri que ele consiste parcialmente em zero bytes, algo que a equipe de teste do
tar -t
realmente não gosta, depois do qual tudo volta ao normal.
(Por causa disso, eu queria saber se os bytes nulos aparecem naturalmente nas pessoas nas caixas de correio. Aconteceu que
encontrar bytes nulos nos arquivos de texto não
é tão simples e sim, eles estão lá).
Recentemente, mudamos o sistema de arquivos de
/var/mail
para os novos servidores de arquivos Linux no Ubuntu 18.04 e, portanto, passamos para uma versão mais recente e mais padrão do GNU Tar do que nas máquinas OmniOS. Esperávamos que isso resolvesse nossos problemas, mas o mesmo incidente aconteceu quase imediatamente. Desta vez, o GNU Tar trabalhou em uma máquina Ubuntu, onde estou muito familiarizado com todas as ferramentas de depuração disponíveis, então verifiquei o processo
tar
execução. O teste mostrou que o
tar
produz um fluxo interminável de
read()
retornando 0 bytes:
read(6, "", 512) = 0 read(6, "", 512) = 0 [...] read(6, "", 512) = 0 write(1, "\0\0\0\0\0"..., 10240) = 10240 read(6, "", 512) = 0 [...]
lsof
referido descritor de arquivo 6 é a caixa de correio de outra pessoa.
Usando o
apt-get source tar
baixei o código-fonte e comecei a procurar por chamadas de sistema
read()
que não verificassem a conclusão do arquivo. Depois de examinar vários níveis de endereçamento indireto, encontrei um local óbvio onde parece que essa verificação foi omitida, principalmente na função
sparse_dump_region do arquivo
sparse.cs . E então me lembrei de algo.
Alguns meses atrás,
encontramos um problema do NFS no Alpine . Enquanto trabalhava nesse bug, rastreei o processo Alpine e notei, entre outras coisas, que ele usa
ftruncate()
para redimensionar caixas de correio; algumas vezes as expande, criando temporariamente uma seção esparsa do arquivo até preenchê-lo e, às vezes, compactando-o. Isso pareceu coincidir com a situação atual: áreas esparsas estão conectadas e a redução do tamanho do arquivo usando
ftruncate()
cria uma situação em que o tar encontra inesperadamente uma conclusão do arquivo.
(Isso até explica por que o tar às vezes é restaurado; se novos e-mails chegarem repentinamente na caixa de correio posteriormente, ele retornará ao tamanho esperado e o tar não encontrará mais um encerramento inesperado de arquivos).
Eu errei um pouco no GDB com os símbolos de depuração do Ubuntu e o código-fonte do pacote tar que recebi e consegui reproduzir o erro, embora fosse um pouco diferente da minha teoria original. Acontece que
sparse_dump_region
não redefine as áreas esparsas do arquivo, mas redefine áreas não esparsas (é claro), e é usado para todos os arquivos (esparsos ou não) se você executar tar com o argumento
--sparse
. Portanto, o erro real é que,
se você executar o GNU Tar com o argumento --sparse
e o arquivo for compactado enquanto está sendo lido, o tar não poderá lidar corretamente com o final do arquivo recebido antes do esperado . Se o arquivo crescer novamente, o tar será restaurado.
(Exceto quando o arquivo é escasso apenas no final e compactado apenas neste local. Nesse caso, tudo está em ordem).
Eu pensei que, mesmo assim, eu poderia verificar muitos anos atrás em nossos servidores de arquivos OmniOS. Existem maneiras de rastrear as chamadas do sistema do programa e dos análogos, e eu poderia encontrar e olhar o código fonte da minha versão do GNU Tar e executá-lo com o depurador OmniOS (embora não pareçamos ter o GDB instalado lá), e assim por diante. Mas eu não fiz. Em vez disso, encolhemos os ombros e seguimos em frente. Levei para mover o sistema de arquivos no Ubuntu para que eu movesse meu dedo e descobrisse o problema.
(Não se trata apenas das ferramentas e do ambiente; assumimos automaticamente que o OmniOS possui uma versão antiga não suportada do GNU Tar, o que não faz sentido investigar, porque o problema foi certamente resolvido na versão mais recente).
PS: Provavelmente, como uma solução rápida, simplesmente
--sparse
Amanda de usar a
--sparse
tar
--sparse
ao fazer backup. As caixas de correio não devem ser esparsas e, se isso acontecer,
ainda compactamos os backups do sistema de arquivos , para que todos esses zero bytes sejam compactados.
PPS: Não tentei relatar o bug aos desenvolvedores do GNU Tar, porque o encontrei apenas na sexta-feira e a universidade está de férias de inverno agora. Sinta-se livre para fazer isso antes de mim.