Ok, acho que já resolvi isso.
TL; DR
Use dd
com um tamanho de bloco grande para ler a fita:
dd if=/dev/nst0 bs=1M | tar tvf -
Antecedentes
Quando você escreve em fitas, os dados são gravados em unidades chamadas blocos. Estes são como setores em um disco rígido. Onde os blocos de disco rígido foram fixados em 512 bytes por muitos anos e só recentemente foram movidos para blocos de 4096 bytes, os blocos de fita podem ser configurados para qualquer tamanho que você desejar.
O tamanho do bloco que você deseja usar é definido com o subcomando setblk
em mt-st
:
mt-st -f /dev/nst0 setblk 512 # Use 512-byte blocks
mt-st -f /dev/nst0 setblk 64k # Use 65536-byte blocks
Quando você emite uma operação de leitura para a unidade, ela retornará dados em blocos do tamanho de blocos. Você não pode ler metade de um bloco - a menor quantidade de dados que você pode ler de uma fita é um bloco, que obviamente pode ser qualquer número de bytes reais, dependendo do tamanho do bloco.
Isto significa que se o programa que você está usando fornecer um buffer de memória de 16kB, você poderá ler até 32 blocos de uma vez da fita com blocos de 512 bytes, pois eles se encaixam exatamente no buffer de 16kB. No entanto, você não será capaz de ler qualquer coisa da fita com blocos de 64kB, porque você não pode colocar um deles no buffer de 16kB, e lembre-se que você não pode ler nada menos que um inteiro bloco de cada vez.
Se você tentar fazer isso usando um buffer muito pequeno para um bloco, o driver (nesse caso, o driver de fita st
SCSI) retornará um código de erro de alocação de memória para avisá-lo de que seu buffer de leitura está muito pequeno para manter um único bloco.
Para complicar ainda mais, algumas unidades de fita (aparentemente as LTOs que estou usando) também suportam blocos de tamanho variável. Isso significa que o tamanho do bloco é determinado pelo tamanho de cada operação de gravação e cada bloco pode ter um tamanho diferente do último.
Este modo é definido com um tamanho de bloco igual a zero:
mt-st -f /dev/nst0 setblk 0 # Use variable-sized blocks
Esta é também a opção padrão como - presumivelmente, eu estou supondo aqui - que desperdiça menos espaço com um programa configurado incorretamente. Se, por exemplo, você definiu blocos de 4k, mas seu programa só gravou dados em unidades de 512 bytes por vez, há um risco de que cada bloco de dados de 512 bytes ocupe 4k na fita.
Causa
Se você agora juntar tudo, perceberá que uma fita pode hipoteticamente ter um bloco de 512 bytes seguido por um bloco de 64kB. Se o programa estiver lendo a fita com um buffer de 16kB, ele lerá com sucesso o primeiro bloco, mas quando tentar ler mais, ele não conseguirá encaixar o seguinte bloco de 64kB em seu buffer para que o driver retorne um erro.
Isso explica por que eu estava recebendo Cannot allocate memory
erros na maior parte do tempo e, ocasionalmente, consegui pegar tar para extrair os primeiros arquivos, mas depois recebi o erro novamente. Eu não defini o tamanho do bloco com mt-st
, por isso defini blocos de tamanho variável quando a fita foi gravada, e agora tar
estava usando um buffer muito pequeno para ler em alguns desses blocos.
tar
tem um algumas opções para definir seu próprio código interno tamanhos de bloco, ou seja, --blocking-factor
, --read-full-records
e --record-size
, no entanto, eles só funcionam se tar
for usado para ler e gravar diretamente na fita.
Porque eu escrevi para a fita por meio do mbuffer
programa para reduzir o brilho da sapata da fita, o tamanho do bloco no arquivo tar
não correspondia mais ao tamanho do bloco na fita. Isso significa que --blocking-factor
teve pouco efeito - permitiria que o primeiro bloco da fita fosse lido, o que inclui um cabeçalho dizendo tar
qual é o suposto fator de bloqueio, no qual ele muda para isso e ignora o valor dado na linha de comando. Isso significa que o segundo bloco e os subsequentes não podem mais ser lidos!
Solução
A solução é usar outro programa para ler da fita - um que pode ter o tamanho do buffer de leitura configurado para um valor grande o suficiente para conter o maior bloco que provavelmente veremos.
dd
funciona para isso e, em um piscar de olhos, isso funciona:
dd if=/dev/nst0 bs=256k | tar tvf -
Você pode precisar aumentar 256k
se sua fita tiver blocos maiores, mas isso funcionou para mim. 1M
também funciona bem, então não parece importar se o valor é muito grande, dentro da razão.