“Não é possível alocar memória” ao ler da fita SCSI

5

Estou experimentando algumas unidades de fita SCSI antigas e gravei com êxito alguns dados em uma fita, mas estou tentando lê-la novamente.

# tar tvf /dev/st0
tar: /dev/st0: Cannot read: Cannot allocate memory
tar: At beginning of tape, quitting now
tar: Error is not recoverable: exiting now

# dd if=/dev/st0 of=test
dd: error reading '/dev/st0': Cannot allocate memory
0+0 records in
0+0 records out
0 bytes copied, 3.20155 s, 0.0 kB/s

Após esses comandos, dmesg diz:

st 10:0:3:0: [st0] Block limits 1 - 16777215 bytes.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 512 byte transfer.
st 10:0:3:0: [st0] Failed to read 131072 byte block with 65536 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 10240 byte transfer.
st 10:0:3:0: [st0] Failed to read 94208 byte block with 69632 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 10240 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 512 byte transfer.

A maioria deles foi porque eu estava testando diferentes tamanhos de bloco com a opção tar -b , mas nenhum deles teve qualquer efeito.

Ocasionalmente eu sou capaz de ler alguns kB de dados do primeiro bloco da fita (que o tar pode extrair até que os dados sejam cortados), mas geralmente ele falha sem nenhum dado lido.

Eu (aparentemente) gravei dados com sucesso em fita, movi a fita para a outra unidade, procurei o final dos dados e depois escrevi mais, então parece não haver dificuldade em gravar dados na unidade, apenas em lendo de novo.

Estou usando duas unidades LTO-3. Um é um HP Ultrium 920 com metade da altura e o outro HP Ultrium 960 com altura total. Ambos apresentam este problema. Eu tentei com duas placas SCSI diferentes (uma placa LSI Logic Ultra320 e uma placa Adaptec Ultra2 / SE 40MB / seg), ambas produzindo os mesmos erros.

Eu tentei um cabo com um terminador conectado (me deu 40MB / s até mesmo na placa Ultra320), então um cabo de dois conectores que significava que eu poderia conectar apenas uma unidade para ativar o jumper "termo power" na drive, que me levou ao Ultra160 (mesmo que o drive e o controlador sejam ambos Ultra320), mas nada disso mudou nada e ao longo de tudo eu ainda tenho os mesmos erros ao tentar ler a partir da unidade.

Eu fiz downgrade do kernel Linux 4.10.13 para 4.4.3 (a versão anterior desta máquina) e a mensagem de erro muda de "Não é possível alocar memória" para "Erro de entrada / saída", mas o problema continua o mesmo.

Alguma idéia do que poderia causar esse erro?

EDIT: O problema de 40MB / seg foi causado porque eu estava usando um terminador ativo SE. Depois que substituímos isso por um terminador LVD, as velocidades aumentaram para o Ultra160. Eu acho que preciso de novos cabos para acertar o Ultra320, mas isso agora é o dobro da largura de banda da fita (máx. 80MB / s), então está tudo bem para mim por enquanto. Não fez diferença com as mensagens de erro.

    
por Malvineous 19.05.2017 / 11:51

1 resposta

8

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.

    
por 20.05.2017 / 12:21

Tags