Specjalny plik powodujący błąd we / wy


13

Chcę automatycznie przetestować, czy oprogramowanie reaguje zgodnie z oczekiwaniami, jeśli niezbędny plik SQLite DB nie zostanie odczytany (powodując błąd we / wy). Dokładnie tak się stało kilka dni temu u klienta. Naprawiliśmy go ręcznie, ale teraz chcę utworzyć automatyczny kod, aby go naprawić i potrzebuję dostępu do uszkodzonego pliku, aby go przetestować.

Ponieważ wszystko w Uniksie jest plikiem, podejrzewałem, że może istnieć specjalny plik, który zawsze powoduje błędy We / Wy, gdy ktoś próbuje go odczytać (np. W / dev).

Niektóre podobne pliki (imo) to:

  • /dev/full która zawsze mówi „Brak miejsca na urządzeniu”, jeśli spróbujesz to napisać
  • /dev/null i /dev/zero

więc założyłem, że musi to być taki plik (ale jeszcze go nie znalazłem).

Czy ktoś zna taki plik lub inną metodę uzyskania pożądanego rezultatu (celowo wadliwy obraz partycji, opakowanie wokół open () przy użyciu LD_PRELOAD, ...)?
Jaka jest najlepsza droga tutaj?


O ile mi wiadomo, w systemie Linux nie ma specjalnego pliku, który daje SIGIO, gdy z niego czytasz. Ostatni raz dostałem SIGIO z powodu pamięci USB, która zadeklarowała pojemność znacznie większą niż rzeczywista, fizyczna. Może to może być możliwość?
lgeorget

hmmm, mógłbym spróbować tego z małym obrazem partycji, który
przycinę

SIGIO nie oznacza, że ​​wystąpił błąd, jest to sposób, w jaki program może poprosić o powiadomienie, że możliwe jest teraz nieblokowanie IO, zamiast wywoływania select () lub poll ().
psusi

Ups, tak, oczywiście masz rację. Napisałem SIGIO, ale myślałem o kodzie błędu EIO. Ale może też OP? Dlaczego brak odczytu dałby SIGIO?
lgeorget

och, popełniłem ten sam błąd w pytaniu ...
Edytowałem

Odpowiedzi:


8

Można użyć dmsetupdo utworzenia urządzenia do mapowania urządzeń przy użyciu celu errorlub flakeydo symulowania awarii.

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

Gdzie 123 to długość urządzenia, w sektorach, a / dev / loop0 to oryginalne urządzenie, na którym chcesz symulować błędy. W przypadku błędu nie potrzebujesz kolejnych argumentów, ponieważ zawsze zwraca błąd.


1
W tym poleceniu znajduję co najmniej dwa błędy: brakująca nazwa urządzenia, literówka i co to znaczy „1 0 / dev / null”?
Hauke ​​Laging

@HaukeLaging, ach, tak, pominąłem nazwę i jakoś trafiłem na zły cytat. 1 0 / dev / null oznacza 1 cel, zaczynając od przesunięcia 0, wspierany przez urządzenie / dev / null. Jest potrzebny do płatków, ale najwyraźniej jest opcjonalny dla błędu.
psusi

Wydaje mi się, że nie jest to „opcjonalne”, ale po prostu ignorowane. Możesz to sprawdzić za pomocą dmsetup table test. Możesz nawet pisać foo barza error; to po prostu nie obchodzi (i dlatego powinno zostać usunięte).
Hauke ​​Laging

@HaukeLaging, edytowane.
psusi

Dzięki za odpowiedź, myślę, że tak właśnie pójdę. Jedyny drobny problem, jaki mam z tym, to to, że wymaga dostępu do roota, ale myślę, że i tak będziesz potrzebować tego typu rzeczy na niskim poziomie ... (Będę zagłębiał się w pomysł LD_PRELOAD, kiedy będę miał czas).
mreithub

14

Istnieje już duży zestaw odpowiedzi na temat przepełnienia stosu i błędu serwera, ale brakowało niektórych technik. Aby ułatwić życie, oto lista mechanizmów blokowania VM / Linux / systemu plików Linux / biblioteki przestrzeni użytkownika Linux biblioteki mechanizmów wstrzykiwania błędów we / wy:

Dodatkowy fakt: SQLite ma sterownik VFS do symulacji błędów, dzięki czemu może uzyskać dobry zasięg testu.

Związane z:


5

Potrzebujesz mechanizmu iniekcji błędów dla I / O.

W systemie Linux jest to metoda, która nie wymaga wcześniejszej konfiguracji i generuje nietypowy błąd (nie EIO „Błąd wejścia / wyjścia”, ale ESRCH „Brak takiego procesu”):

cat /proc/1234/mem

gdzie 1234 jest PID procesu uruchomionego jako ten sam użytkownik co testowany proces, ale nie sam proces. Kredyty na rubasov do myślenia o /proc/$pid/mem.

Jeśli użyjesz PID samego procesu, otrzymasz EIO, ale tylko jeśli czytasz z obszaru, który nie jest zmapowany w pamięci procesu. Pierwsza strona nigdy nie jest mapowana, więc jest ok, jeśli czytasz plik sekwencyjnie, ale nie nadaje się do procesu bazy danych, który szuka bezpośrednio do środka pliku.

Mając trochę więcej ustawień jako root, możesz wykorzystać mapowanie urządzeń do tworzenia plików z prawidłowymi i uszkodzonymi sektorami.

Innym podejściem byłoby wdrożenie małego systemu plików FUSE . EIO jest domyślnym kodem błędu, gdy sterownik systemu plików przestrzeni użytkownika robi coś złego, więc łatwo go osiągnąć. Zarówno wiązania Perla, jak i Pythona zawierają przykłady na początek. Możesz szybko napisać system plików, który głównie odzwierciedla istniejące pliki, ale wstrzykuje EIO w starannie wybrane miejsca. Istnieje taki system plików: petardfs ( artykuł ), nie wiem, jak dobrze działa po wyjęciu z pudełka.

Jeszcze inną metodą jest LD_PRELOADopakowanie. Istniejącym jest Libfiu (wstrzykiwanie błędów w przestrzeni użytkownika). Działa poprzez wstępne załadowanie biblioteki, która przeciąża wywołania API POSIX. Możesz napisać proste dyrektywy lub dowolny kod C, aby zastąpić normalne zachowanie.


Libfiu wygląda naprawdę obiecująco (i znajduje się w repozytoriach Debiana). Świetna odpowiedź, dziękuję, +1
mreithub

1

Rozwiązanie jest o wiele łatwiejsze, jeśli można użyć pliku urządzenia jako „pliku z błędami we / wy”. Moja propozycja dotyczy przypadków, w których zwykły plik zawiera takie błędy.

> 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

Muszę przyznać, że jestem trochę zdezorientowany, ponieważ nie udało mi się odczytać pojedynczych sektorów z tego pliku bez błędu (z dd .. seek=...). Być może jest to problem z wyprzedzeniem.


Bloki systemu plików mają rozmiar co najmniej 4096 bajtów, więc będą obejmować wiele sektorów, nawet jeśli plik jest mały.
Anon

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.