Jak znaleźć duże pliki, które zostały usunięte, ale nadal są otwarte w aplikacji? Jak usunąć taki plik, nawet jeśli proces go otworzył?
Sytuacja polega na tym, że uruchamiamy proces, który wypełnia plik dziennika w niesamowitym tempie. Znam przyczynę i mogę to naprawić. Do tego czasu chciałbym rm lub opróżnić plik dziennika bez zamykania procesu.
Po prostu rm output.log
usuwa tylko odniesienia do pliku, ale nadal zajmuje miejsce na dysku, dopóki proces się nie zakończy. Gorzej: po rm
ing nie mogę teraz znaleźć, gdzie jest plik ani jak duży jest! Czy jest jakiś sposób, aby znaleźć plik i ewentualnie go opróżnić, nawet jeśli nadal jest otwarty w innym procesie?
Mam na myśli szczególnie systemy operacyjne oparte na Linuksie, takie jak Debian lub RHEL.
źródło
lsof -p <pid>
aby wyświetlić listę jego otwartych plików i ich rozmiarów. Usunięty plik będzie miał(deleted)
obok niego. Usunięte pliki zostaną prawdopodobnie połączone/proc/<pid>/fd/1
. Nie wiem, jak sprawić, aby proces przestał zapisywać do swojego deskryptora pliku, nie przerywając go. Myślę, że to zależy od procesu.rm
plików ed, które są nadal otwarte?lsof | grep "(deleted)"
. Gdy nie będzie już żadnych procesów, w których usunięty plik jest otwarty, jądro zwolni bloki i-węzła i dysku. Procesy nie mają „programów obsługi”, za pomocą których można ich powiadomić, że otwarty, zasadniczo zablokowany plik, został usunięty z dysku.lsof | grep '(deleted)'
działa również w systemie Linux. W systemie Linux możesz zostać powiadomiony o usunięciu pliku (nawet pliki, które nie mają już żadnego wpisu w katalogu innym niż / proc / some-pid / fd) za pomocą mechanizmu inotify (zdarzenie IN_DELETE_SELF)somefile
i otworzyłem go w VIM, a następnierm
edytowałem w innym procesie bash. Następnie uruchamiamlsof | grep somefile
i nie ma go tam, mimo że plik jest otwarty w VIM.Odpowiedzi:
Jeśli nie możesz zabić aplikacji, możesz skrócić zamiast usuwać plik dziennika, aby odzyskać miejsce. Jeśli plik nie był otwarty w trybie dołączania (z
O_APPEND
), plik będzie wyglądał na tak duży, jak przed następnym razem, gdy aplikacja do niego napisze (choć z wiodącą częścią rzadką i wyglądającą, jakby zawierała NUL bajtów), ale spacja zostanie odzyskany (nie dotyczy to systemów plików HFS + w systemie Apple OS / X, które nie obsługują plików rzadkich).Aby go skrócić:
Jeśli został już usunięty, w systemie Linux nadal można go obciąć, wykonując:
Gdzie
$pid
jest identyfikator procesu, w którym plik jest otwarty, i$fd
jeden deskryptor pliku, pod którym jest otwarty (pod którym można to sprawdzić)lsof -p "$pid"
.Jeśli nie znasz pid i szukasz usuniętych plików, możesz:
lsof -nP +L1
, jak wspomniano w @ user75021, jest jeszcze lepszą (bardziej niezawodną i przenośną) opcją (lista plików, które mają mniej niż 1 link).Lub (w systemie Linux):
Lub znaleźć duże z
zsh
:Alternatywą, jeśli aplikacja jest dynamicznie połączona, jest dołączenie do niej debuggera i wywołanie
close(fd)
nowego, a następnie wywołanie nowegoopen("the-file", ....)
.źródło
truncate
polecenie, które robi to samo wyraźniej.lsof
prawdopodobnie będzie najbliżej przenośnego rozwiązania, które można uzyskać, aby wyświetlić listę otwartych plików. podejście debugera do zamykania fd pod nóżkami aplikacji powinno być również dość przenośne.df -k | awk 'NR>1 { print $NF }' | xargs fuser -Vud
(a następnie łatwe wysyłanie sygnałów do przestępców w celu zmuszenia ich do wydania fd)lsof +L1
. Na stronie podręcznika lsof: „Specyfikacja formularza+L1
wybierze otwarte pliki, które zostały odłączone. Specyfikacja formularza+aL1 <file_system>
wybierze otwarte pliki w określonym systemie plików.”. To powinno być nieco bardziej niezawodne niż grepowanie.Sprawdź szybki start tutaj:
lsof
Szybki startDziwi mnie, że nikt nie wspomniał o pliku szybkiego startu lsof (dołączonym do lsof). Sekcja „3.a” pokazuje, jak znaleźć otwarte, niepowiązane pliki:
Na przykład:
W systemach Red Hat, aby znaleźć lokalną kopię pliku szybkiego uruchamiania, zwykle robię to:
... albo to:
źródło
To od sterownika systemu plików zależy, czy rzeczywiście zwolni przydzielone miejsce, i zwykle dzieje się to dopiero po zwolnieniu wszystkich deskryptorów plików odnoszących się do tego pliku. Tak więc nie można odzyskać miejsca, chyba że aplikacja zamknie plik. Co oznacza albo jego zakończenie, albo zabawę „trochę” w debuggerze (np. Zamknięcie pliku i upewnienie się, że nie zostanie ponownie otwarty / zapisany, lub otwarcie
/dev/null
zamiast niego). Możesz też zhakować jądro, ale odradzałbym to.Obcinanie pliku, jak sugeruje Stephane, może pomóc, ale rzeczywisty wynik zależy również od systemu plików (na przykład wstępnie przydzielone bloki zostaną prawdopodobnie zwolnione dopiero po zamknięciu pliku).
Uzasadnieniem tego zachowania jest to, że jądro nie wiedziałoby, co zrobić z żądaniami danych (zarówno do odczytu, jak i do zapisu, ale w rzeczywistości czytanie jest bardziej krytyczne) ukierunkowane na taki plik.
źródło
fallocate
w systemie Linux 4.9. Czy możesz wyjaśnić, w jakim systemie plików i warunkach obcinanie pliku nie zajmuje miejsca?