Dlaczego wyłączenie zasilania mojego komputera po złym zapisaniu „rm” zapisało moje pliki?

31

Sytuacja klasyczna: źle się sprawdziłem rmi zaraz potem zorientowałem się, że usunąłem niewłaściwe pliki. (Nic krytycznego, a ostatnio miałem kopie zapasowe, ale wciąż denerwujące).

Wiedząc, że dalszą aktywnością dysku był mój wróg, gdybym chciał odzyskać pliki za pomocą extundeletetakich narzędzi, natychmiast natychmiast wyłączyłem maszynę fizycznie (tj. Za pomocą przycisku zasilania, a nie haltżadnego polecenia). Był to laptop bez uruchomionych ważnych zadań lub otwartych, więc operacja była do przyjęcia. (Nawiasem mówiąc, od tamtej pory dowiedziałem się, że pierwszą rzeczą do zrobienia w takiej sytuacji byłoby oszacowanie, czy brakujące pliki mogą być nadal otwierane przez proces https://unix.stackexchange.com/a/101247 - jeśli są, powinieneś je odzyskać w ten sposób, zamiast wyłączać maszynę.)

Mimo to, kiedy maszyna została wyłączona, pomyślałem przez chwilę i zdecydowałem, że pliki nie są warte zainwestowania czasu w uruchomienie systemu na żywo w celu przeprowadzenia właściwej analizy sądowej. Więc ponownie uruchomiłem maszynę. A potem odkryłem, że moje pliki nadal znajdowały się na dysku: rmnie zostały propagowane na dysk przed wyłączeniem. Zatańczyłem trochę i podziękowałem bogowi sysadminów za Jego nieoczekiwane przebaczenie.

Moje pytanie polega teraz na zrozumieniu, w jaki sposób było to możliwe i jakie jest typowe opóźnienie, zanim plik rmzostanie faktycznie propagowany na dysk. Wiem, że IO dysku nie jest natychmiast opróżniane, ale przez pewien czas pozostaje w pamięci, ale pomyślałem, że dziennik dysku szybko upewni się, że oczekujące operacje nie zostaną całkowicie utracone. https://unix.stackexchange.com/a/78766 wydaje się wskazywać na osobny mechanizm opróżniania brudnych stron i opróżniania operacji dziennika, ale nie podaje wystarczających szczegółów na temat tego, w jaki sposób dziennik byłby zaangażowany w to rm, oraz spodziewanego opóźnienia przed operacje są opróżniane.

Kilka dodatkowych szczegółów: dane znajdowały się na partycji ext4 w woluminie LUKS, a po ponownym uruchomieniu komputera zobaczyłem syslog:

Sep 24 10:24:58 gamma kernel: [   11.457007] EXT4-fs (dm-0): 1 orphan inode deleted
Sep 24 10:24:58 gamma kernel: [   11.458393] EXT4-fs (dm-0): recovery complete
Sep 24 10:24:58 gamma kernel: [   11.482475] EXT4-fs (dm-0): mounted filesystem with ordered data mode. Opts: (null)

ale nie jestem pewien, czy jest to związane z rm.

Innym pytaniem byłoby, czy istnieje sposób, aby powiedzieć jądrze, aby nie wykonywało żadnej z oczekujących operacji dyskowych (ale powiedzmy, że gdzieś je zrzuciło), zamiast wyłączać maszynę. (Oczywiście nie wydaje się niebezpieczne, aby nie wykonywać oczekujących operacji, ale tak by się stało po wyłączeniu urządzenia, a to może w niektórych przypadkach cię uratować.) To byłoby oczywiście „czystsze”, a także interesujące na przykład na zdalne serwery, na których fizyczne wyłączenie nie jest łatwą opcją.

a3nm
źródło

Odpowiedzi:

22

Wygląda na to, że dobrze rozumiesz, co się stało.

Tak, ponieważ system został wyłączony z zasilania przed zatwierdzeniem zmian na dysku, były one dostępne podczas rozruchu.

System buforuje wszystkie zapisy przed wypłukaniem ich na dysk. Istnieje kilka opcji kontrolujących to zachowanie, wszystkie znajdujące się w /proc/sys/vm/dirty_* [ kernel doc ] . O ile flush nie jest jawnie wykonywany przez aplikację za pomocą fsync() [ man 2 fsync ] , dane są zatwierdzane, gdy są wystarczająco duże lub pamięć podręczna zapisu jest zapełniona.
Stosowana powyżej definicja „danych” obejmuje modyfikację wpisu katalogu w celu usunięcia pliku.

Jeśli chodzi o dziennik, jest to jedno z powszechnych nieporozumień dotyczących tego, do czego służy dziennik. Celem dziennika nie jest zapewnienie, że zmiany zostaną odtworzone lub że dane nie zostaną utracone. Celem dziennika jest zapobieganie uszkodzeniu samego systemu plików, a nie zawartych w nim plików. Czasopismo zawiera po prostu informacje o wprowadzanych zmianach, a nie (zwykle) pełne dane samej zmiany. Dokładne szczegóły zależą od systemu plików i trybu kroniki. Dla ext3 / 4, patrz dataopcja montowania w man 8 mount.


Aby odpowiedzieć na dodatkowe pytanie, czy istnieje sposób, aby zapobiec oczekującym zapisom bez ponownego uruchamiania:

Po szybkim przeczytaniu kodu źródłowego jądra wygląda na to, że możesz użyć magicznej ukomendy sysrq ([ wikipedia ], [ kernel doc ]), aby wykonać awaryjną operację tylko do odczytu. Wygląda na to, że natychmiast ponownie zamontuje wszystkie woluminy tylko do odczytu bez operacji synchronizacji.

Aby tego użyć, po prostu naciśnij Alt+ SysRq+ u.

Patrick
źródło
1
Dzięki za tę odpowiedź! Nadal jestem trochę zdezorientowany co do czasopisma: czy powinienem myśleć o tym jako o czymś, co angażuje się tylko wtedy, gdy zmiany zostaną zapisane na dysk, aby buforowanie zapisu było jedynym istotnym mechanizmem do oszacowania czasu karencji przed rmnapisaniem? Innymi słowy, rzeczy są zapisywane w czasopiśmie tylko wtedy, gdy zapis ma się właśnie odbyć? A może obraz jest bardziej złożony? Jeśli chodzi o alt-sysrq-u, jest to całkiem fajny pomysł. Czy masz odniesienie do roszczenia „wydaje się”? (Wydaje się, że nie wynika to z podanych przez ciebie linków.) Dzięki! :)
a3nm
Ponadto system magiczny sysrq ma również to, że nadal nie można tego zrobić na zdalnym komputerze.
a3nm
3
@ a3nm Możesz użyć sysrq na zdalnym komputerze. echo u > /proc/sysrq-trigger(być może trzeba go najpierw aktywować).
Paulo Almeida
Dziennik nie zajmuje się zawartością pliku (domyślnie można go zmienić w całości w dzienniku), tylko metadane systemu plików, ale w tym przypadku mógł usunąć plik , ponieważ mamy do czynienia z usunięciem pozycji katalogu. Dlatego dziennik musi upewnić się, że albo plik istnieje (z jego poprzednią zawartością, zakładając, że nie wprowadzono żadnych innych zmian), albo nie.
Ángel
@ a3nm W odniesieniu do komentarza do dziennika. Pamięć podręczna zapisu znajduje się między dziennikiem a dyskiem. Podczas pisania do systemu plików dziennik jest aktualizowany, a następnie system plików, ale żadne z nich nie jest jeszcze przypisane do dysku.
Patrick
2

Od: https://www.kernel.org/doc/Documentation/filesystems/ext4.txt

commit = nrsec (*) Ext4 może zostać poproszony o synchronizację wszystkich swoich danych i metadanych co sekundę „nrsec”. Wartość domyślna to 5 sekund. Oznacza to, że jeśli stracisz moc, stracisz tyle, co ostatnie 5 sekund pracy (jednak system plików nie zostanie uszkodzony, dzięki kronikowaniu). Ta wartość domyślna (lub dowolna niska wartość) zaszkodzi wydajności, ale jest dobra dla bezpieczeństwa danych. Ustawienie na 0 będzie miało taki sam efekt, jak pozostawienie wartości domyślnej (5 sekund). Ustawienie bardzo dużych wartości poprawi wydajność.

Zobacz także, jak je opróżnić: Jak opróżnić bufory i pamięć podręczną w systemie Linux?

Cytat z powyższego linku:

UWAGA: wyczyść pamięć niepotrzebnych rzeczy (Kernerl 2.6.16 lub nowszy). Zawsze najpierw uruchom synchronizację, aby wypłukać przydatne rzeczy na dysk !!!

To free pagecache:

$ echo 1 > /proc/sys/vm/drop_caches

To free dentries and inodes:

$ echo 2 > /proc/sys/vm/drop_caches

To free pagecache, dentries and inodes:

$ echo 3 > /proc/sys/vm/drop_caches
David
źródło
Dzięki za tę odpowiedź! Nie rozumiem tego jednak: jeśli chodzi o wspomnianą „synchronizację”, czy commit=nrsecjest to coś, co miałoby miejsce po tym, jak jądro zdecyduje się opróżnić zmiany z pamięci na dysk? Czy też ustawienie commit=1gwarantuje, że wszystkie zmiany zostaną usunięte po 1 sekundzie niezależnie od ustawień dirty_expire_centisecsi dirty_writeback_centisecs?
a3nm
Jądro opróżnia (synchronizuje) każdą pamięć podręczną / bufory na dysk co 1 sekundę commit=1. O ile rozumiem, synczmusza wszystko do działania niezależnie od ustawień pamięci wirtualnej, chociaż może się to zdarzyć wcześniej.
David
Również ze względu na wydajność, ustawienie (i długowieczność pamięci) zatwierdzenia na niższą niż domyślną nie jest zalecane.
David