Arquivo especial que causa erro de E / S

11

Eu quero testar automaticamente se um software reage como esperado se um arquivo DB SQLite essencial não for lido (causando um erro de E / S). Exatamente isso aconteceu alguns dias atrás em um cliente. Nós consertamos isso manualmente, mas agora eu quero criar um código automático para consertá-lo e precisar acessar um arquivo quebrado para testar isso.

Como tudo no Unix é um arquivo, suspeitei que poderia haver um arquivo especial que sempre causa erros de E / S quando alguém tenta lê-lo (por exemplo, em / dev).

Alguns arquivos semelhantes (imo) seriam:

  • /dev/full , que sempre diz "Não há espaço no dispositivo", se você tentar escrevê-lo
  • /dev/null e /dev/zero

então presumi que só tem que haver um arquivo como esse (mas ainda não achei um).

Alguém conhece tal arquivo ou qualquer outro método para eu obter o resultado desejado (uma imagem de partição intencionalmente defeituosa, um wrapper em torno de open () usando LD_PRELOAD, ...)

Qual a melhor maneira de ir aqui?

    
por mreithub 29.05.2013 / 13:57

5 respostas

8

Você pode usar dmsetup para criar um dispositivo de mapeamento de dispositivo usando as metas error ou flakey para simular falhas.

dmsetup create test --table '0 123 flakey 1 0 /dev/loop0'

Onde 123 é o comprimento do dispositivo, em setores e / dev / loop0 é o dispositivo original no qual você deseja simular erros. Por erro, você não precisa dos argumentos subsequentes, pois sempre retorna um erro.

    
por 29.05.2013 / 15:22
11

Há um grande conjunto de respostas para isso no Stack Overflow e no Server Fault, mas faltam algumas técnicas. Para facilitar a vida, aqui está uma lista (não muito) curta sobre os mecanismos de injeção de falha de E / S do disco e do sistema de arquivos do Linux:

Fato bônus: O SQLite tem um driver VFS para simular erros para obter uma boa cobertura de teste.

Relacionados:

por 12.07.2014 / 19:16
5

Você deseja um mecanismo injeção de falhas para E / S.

No Linux, aqui está um método que não requer nenhuma configuração prévia e gera um erro incomum (não EIO “Erro de entrada / saída”, mas ESRCH “Nenhum tal processo”):

cat /proc/1234/mem

em que 1234 é o PID de um processo em execução como o mesmo usuário que o processo que você está testando, mas não esse processo em si. Créditos para rubasov para pensando de /proc/$pid/mem .

Se você usar o PID do processo em si, obterá EIO, mas somente se estiver lendo de uma área que não esteja mapeada na memória do processo. A primeira página nunca é mapeada, então está tudo bem se você ler o arquivo sequencialmente, mas não é adequado para um processo de banco de dados que busca diretamente no meio do arquivo.

Com mais algumas configurações como root, você pode alavancar o mapeador de dispositivos para criar arquivos com setores válidos e setores defeituosos.

Outra abordagem seria implementar um pequeno sistema de arquivos FUSE . O EIO é o código de erro padrão quando o driver do sistema de arquivos do espaço do usuário faz algo errado, por isso é fácil de conseguir. Tanto o Perl quanto As ligações do Python vêm com exemplos para começar, você pode escrever rapidamente um sistema de arquivos que espelha os arquivos existentes, mas que injeta uma EIO em locais cuidadosamente escolhidos. Existe um sistema de arquivos existente: petardfs ( article ), eu não sei o quão bem funciona fora da caixa.

No entanto, outro método é o LD_PRELOAD wrapper. Um já existente é o Libfiu (injeção de falhas no espaço do usuário). Ele funciona pré-carregando uma biblioteca que sobrecarrega as chamadas da API POSIX. Você pode escrever diretivas simples ou código C arbitrário para substituir o comportamento normal.

    
por 29.05.2013 / 23:28
1

A solução é muito mais fácil se não houver problema em usar um arquivo de dispositivo como "arquivo com erros de E / S". Minha proposta é para os casos em que um arquivo regular deve ter tais erros.

> dd if=/dev/zero of=/path/to/ext2.img bs=10M count=10
> losetup /dev/loop0 /path/to/ext2.img
> blockdev --getsz /dev/loop0
204800
> echo "0 204800 linear /dev/loop0 0" | dmsetup create sane_dev
> mke2fs /dev/mapper/sane_dev # ext2 reicht
> mount -t ext2 /dev/mapper/sane_dev /some/where
> dd if=/dev/zero of=/some/where/unreadable_file bs=512 count=4
> hdparm --fibmap /some/where/unreadable_file
/mnt/tmp/unreadable_file:
 filesystem blocksize 1024, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0       2050       2053          4
> umount /dev/mapper/sane_dev
> dmsetup remove sane_dev
> start_sector=$((204800-2053-1))
> echo $'0 2053 linear /dev/loop0 0\n2053 1 error\n2054 '"${start_sector} linear /dev/loop0 2054" | 
>   dmsetup create error_dev
> mount -t ext2 /dev/mapper/error_dev /some/where
> cat /some/where/unreadable_file # 3rd sector of file is unreadable
cat: /some/where/unreadable_file: Input/output error

Devo admitir que estou um pouco confuso porque não consegui ler setores individuais desse arquivo sem um erro (com dd .. seek=... ). Talvez seja um problema de leitura antecipada.

    
por 29.05.2013 / 15:27
1

Você poderia usar o CharybdeFS que foi feito exatamente para esse tipo de propósito.

É um sistema de arquivos de fusíveis de passagem como o PetardFS, mas muito mais configurável.

Veja o livro de receitas do CharybdeFS aqui: link

É avançado o suficiente para testar um banco de dados.

    
por 02.05.2016 / 19:17