df pokazuje pełny dysk a du wolne miejsce
Rozwiązanie problemu rozbieżności między df a du na Linux. Dowiedz się jak znaleźć usunięte pliki trzymane przez procesy komendą lsof oraz jak sprawdzić wyczerpanie tablicy inode.
Dlaczego df wskazuje pełny dysk, a du pokazuje co innego
df zgłasza, że dysk jest pełny, podczas gdy du nie znajduje zajętego miejsca, ponieważ proces nadal utrzymuje otwarty plik, który został usunięty. Usunięcie pliku usuwa jego nazwę z katalogu. Bloki danych są zwalniane dopiero w momencie zamknięcia ostatniego deskryptora pliku wskazującego na dany inode. du przeszukuje nazwy, więc nie zlicza usuniętych plików. df pyta system plików o liczbę przydzielonych bloków, dlatego nadal uwzględnia plik, który nie posiada już nazwy.
Niniejszy przewodnik odtwarza tę sytuację na standardowym VPS z Ubuntu przy użyciu zainstalowanych narzędzi, lokalizuje proces blokujący zasób za pomocą /proc i zwalnia miejsce bez konieczności restartu. Pozostałe przyczyny tego samego objawu to: wyczerpana tablica inode, pliki ukryte pod punktem montowania oraz bloki zarezerwowane dla użytkownika root.
Należy wykonać każde polecenie i przeanalizować jego wynik. Wartości zależą od konfiguracji dysku, dlatego należy porównać stan przed i po na własnej maszynie, zamiast odnosić się do liczb podanych w przewodniku.
Co zliczają df oraz du
df (disk free) odpytuje każdy zamontowany system plików o jego własne statystyki: ile bloków istnieje, ile jest przydzielonych, a ile wolnych. Narzędzie to nigdy nie otwiera katalogów. Wynik obejmuje każdy przydzielony blok, w tym bloki należące do plików, do których nie prowadzi żaden wpis w katalogu.
du (disk usage) działa odwrotnie. Rozpoczyna pracę od podanej ścieżki, odczytuje katalogi, sprawdza statystyki każdego znalezionego wpisu i sumuje bloki. Plik bez nazwy jest dla niego niewidoczny. Podobnie każdy katalog, do którego użytkownik nie ma uprawnień odczytu, dlatego zwykły użytkownik otrzymuje mniejszy wynik niż root. Przed wyciągnięciem wniosków z porównania należy uruchomić du z uprawnieniami sudo.
Przy porównywaniu tych dwóch narzędzi zawsze istotne są dwie opcje.
-xograniczadudo jednego systemu plików. Bez tej opcjidu /wchodzi w każdy system plików zamontowany poniżej/i generuje sumę, którejdf /nigdy nie mierzył.-swyświetla jedną linię podsumowania dla każdego argumentu zamiast jednej linii dla każdego katalogu.
Daje to parę poleceń, które można uruchomić obok siebie dla wybranego systemu plików.
df -h /
sudo du -xhs / 2>/dev/nulldf odpowiada natychmiast. du na dużym systemie plików zajmuje minuty, ponieważ sprawdza statystyki każdego pliku po drodze. Gdy wyniki znacznie się różnią, a du zostało uruchomione jako root z flagą -x, brakujące miejsce jest przydzielone do obiektu, który nie posiada nazwy.
Celowe wywołanie niespójności
Wykonaj te czynności na testowym serwerze VPS. Wszystkie poniższe polecenia korzystają z bash oraz coreutils, więc nie ma potrzeby instalowania dodatkowego oprogramowania.
Zarejestruj stan początkowy systemu plików, na którym znajduje się /var/tmp.
cd /var/tmp
df -h .
df --output=used -B1 .Drugie polecenie wyświetla liczbę użytych bajtów bez zaokrągleń, co pozwala na precyzyjną weryfikację na końcu.
Teraz utwórz plik. Jego rozmiar wynika z wolnego miejsca zgłaszanego przez system, dzięki czemu demonstracja zadziała na dowolnym dysku.
free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .$(...) to podstawienie polecenia: powłoka wykonuje polecenie wewnątrz, a wynik staje się wartością free. Jeśli ta składnia jest nowa, podstawianie poleceń w bash zawiera szczegółowe wyjaśnienie. fallocate rezerwuje rzeczywiste bloki bez ich zapisywania, dlatego kończy działanie natychmiast. Na systemie plików, który tego nie obsługuje, polecenie zakończy się błędem, a head -c $((free / 10)) /dev/zero > ghost.bin wykona to samo zadanie, zapisując bajty na dysk.
Porównaj ten df -h . z wcześniej zarejestrowanym. Kolumna użytego miejsca wzrosła, a kolumna dostępnego miejsca zmalała.
Teraz przytrzymaj plik otwarty przez inny proces, a następnie usuń go.
sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/nullPrzekierowanie jest kluczem do całego mechanizmu. sleep infinity < ghost.bin & uruchamia proces w tle, którego standardowym wejściem jest ten plik, więc powłoka otwiera plik i przekazuje deskryptor do sleep, który utrzymuje go w stanie otwartym. $! przechowuje identyfikator procesu (PID) tego zadania w tle. rm następnie usuwa nazwę pliku, podczas gdy deskryptor pozostaje otwarty.
Odczytaj wynik. ls nie może znaleźć pliku, ponieważ nazwa została usunięta. du wskazuje wartości zbliżone do początkowych, ponieważ operuje na nazwach plików. df nie zmieniło się, ponieważ bloki są nadal zaalokowane. System plików i drzewo katalogów są teraz niespójne, a różnica między nimi to właśnie usunięty plik.
Znajdowanie procesu blokującego usunięty plik
Każdy otwarty deskryptor pliku widnieje w /proc/<pid>/fd/ jako dowiązanie symboliczne do pliku, do którego się odnosi. Gdy plik zostanie odlinkowany, jądro oznacza cel tego dowiązania jako usunięty. Zatem znalezienie procesu blokującego sprowadza się do znalezienia dowiązania, którego cel posiada to oznaczenie.
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null-lname dopasowuje cel dowiązania symbolicznego zamiast jego nazwy, %p wypisuje ścieżkę deskryptora, a %l wypisuje obiekt, na który wskazuje. Identyfikator procesu (PID) jest drugim elementem wypisanej ścieżki. Polecenie należy uruchomić z sudo, w przeciwnym razie odczytasz tylko /proc/<pid>/fd dla własnych procesów. Przekierowanie stderr odrzuca komunikaty o błędach procesów, które zakończyły działanie w trakcie skanowania przez find.
Obciążony serwer w każdej chwili przetrzymuje kilka usuniętych plików, z których większość jest niewielka i nieszkodliwa. Należy posortować je według rozmiaru, aby na górze listy znalazły się tylko istotne przypadki.
sudo bash -c 'for fd in /proc/[0-9]*/fd/*; do
target=$(readlink "$fd" 2>/dev/null) || continue
case "$target" in
*"(deleted)") echo "$(stat -Lc %s "$fd" 2>/dev/null) $fd $target" ;;
esac
done' | sort -rn | headstat -L podąża za dowiązaniem do samego inoda, dzięki czemu %s raportuje rozmiar pliku, który nie posiada już nazwy. Sortowanie według tej wartości umieszcza największy plik na początku.
Następnie należy zidentyfikować proces powiązany z wybranym deskryptorem. Ścieżka na górze listy zawiera oba potrzebne numery, więc należy przypisać je do zmiennych, zastępując PID oraz N wartościami uzyskanymi z własnego zestawienia.
pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"ps podaje nazwę programu i pokazuje czas jego działania. stat -L wypisuje rozmiar oraz liczbę przydzielonych bloków usuniętego inoda. Razem odpowiadają na kluczowe pytanie: która usługa utrzymuje ten plik w pamięci.
Jeśli maszyna posiada już lsof, sudo lsof +L1 wyświetla otwarte pliki, których licznik dowiązań spadł do zera, prezentując ich rozmiary w jednej tabeli. Narzędzie to nie jest obecne w minimalnym obrazie Ubuntu, a instalacja pakietu na systemie plików bez wolnego miejsca może zakończyć się niepowodzeniem, dlatego wersja oparta na /proc jest metodą, która działa zawsze.
Zwalnianie miejsca bez restartu
Restart rozwiązuje problem, ale jest niewłaściwym pierwszym krokiem: powoduje przestój usługi i niszczy dowody. Istnieją cztery łagodniejsze metody, które należy stosować w podanej kolejności.
Najpierw skopiuj dane, jeśli są jeszcze potrzebne. Odczytanie ścieżki deskryptora pozwala uzyskać dostęp do aktywnego i-węzła (inode).
sudo cp /proc/<pid>/fd/<n> /root/recovered.logJest to jedyny przypadek, w którym usunięty plik można łatwo odzyskać, dlatego odzyskiwanie plików usuniętych za pomocą rm -rf zaczyna się od sprawdzenia, czy jakikolwiek proces nadal trzyma otwarty plik. Gdy ostatni deskryptor zostanie zamknięty, ta ścieżka znika.
Po drugie, opróżnij plik za pomocą deskryptora. Ścieżka /proc prowadzi do tego samego i-węzła, więc jego wyczyszczenie (truncate) zwalnia bloki, podczas gdy proces nadal działa.
sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /Działa to poprawnie, gdy proces zapisujący otworzył plik w trybie dopisywania (append), ponieważ każdy zapis trafia na bieżący koniec pliku. W przeciwnym razie proces zachowuje stary offset zapisu, więc kolejny zapis trafi daleko w głąb pliku, odtwarzając go z luką na początku. Luka nie jest alokowana, więc bloki pozostają wolne, a df zachowuje odzyskane miejsce. To, co powraca, to jedynie rozmiar: uruchom ponownie sudo stat -L "/proc/$pid/fd/$n" po zapisie przez proces, a wyświetli on stary rozmiar obok liczby bloków, która już się z nim nie zgadza. Zrestartuj proces, jeśli chcesz, aby rozmiar również zaczął się od zera.
Po trzecie, poproś usługę o ponowne otwarcie logów. Demon, którego plik dziennika został usunięty w trakcie działania, to najczęstsza rzeczywista przyczyna tego problemu. Wiele demonów otwiera ponownie pliki logów po otrzymaniu sygnału: nginx używa SIGUSR1, a rsyslog używa SIGHUP. Sprawdź dokumentację danego demona zamiast zgadywać, ponieważ wysłanie niewłaściwego sygnału do niewłaściwego demona może go zatrzymać.
sudo systemctl kill -s USR1 nginxPolecenie to wysyła sygnał do procesu, który systemd rejestruje jako główny proces jednostki, więc jednostka z błędnie zadeklarowanym Type= dla sposobu uruchamiania demona może dostarczyć sygnał do procesu, który nigdy nie trzymał usuniętego pliku, przez co miejsce nie zostanie zwolnione.
Po czwarte, zrestartuj jednostkę. sudo systemctl restart <unit> zamyka wszystkie deskryptory trzymane przez stary proces, więc bloki wracają z pewnością. W powyższej demonstracji procesem trzymającym plik jest sleep, który został uruchomiony samodzielnie, więc jego zakończenie jest wystarczające.
kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/nullPorównaj liczbę użytych bajtów z wartością zapisaną przed utworzeniem pliku. Wartości powinny się zgadzać, a find nie raportuje już używanego deskryptora. Weryfikacja za pomocą tego samego polecenia, które wykryło problem, jest nawykiem wartym utrzymania.
Obserwowanie zmian tej wartości jest łatwiejsze niż ręczne uruchamianie df wielokrotnie. watch powtarza polecenie w określonym odstępie czasu i odświeża wynik w tym samym miejscu, więc watch df -h / pokazuje zmianę w kolumnie użycia w miarę odzyskiwania miejsca.
Gdy sumy się zgadzają, a dysk nadal jest pełny
Jeśli df oraz root du -x wskazują na to samo, nie ma to związku z usuniętymi plikami. Pozostałe przyczyny mają inny charakter i każda z nich wymaga odrębnej weryfikacji.
Brak wolnych i-węzłów (inodes) przy dostępnym miejscu na dysku
I-węzeł (inode) przechowuje metadane pojedynczego pliku. System plików ext4 tworzy stałą liczbę i-węzłów podczas formatowania, dlatego system plików może wyczerpać pulę i-węzłów, mimo że nadal posiada wolne bloki danych. W takiej sytuacji tworzenie nowych plików kończy się błędem, nawet jeśli df -h wskazuje na dostępną przestrzeń.
df -h /
df -i /Pierwsze polecenie zlicza bloki, a drugie i-węzły. Należy porównać kolumnę użycia (use) dla każdego z nich. Niskie zużycie bloków przy maksymalnym wykorzystaniu i-węzłów oznacza, że problemem jest bardzo duża liczba bardzo małych plików.
df odrzuca -i oraz --output w tym samym wywołaniu, więc aby uzyskać surowe wartości do odczytu lub przekazania do innego polecenia, należy wybrać pola i-węzłów po nazwie i pominąć -i.
df --output=itotal,iused,iavail,ipcent /Kolumny te zawierają te same dane rozliczeniowe, które wyświetla df -i, w formie umożliwiającej dalsze przetwarzanie.
Lokalizację plików można ustalić, zliczając wpisy zamiast bajtów.
sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | headNależy powtarzać to samo polecenie na kolejnych poziomach katalogów, aż do znalezienia drzewa katalogów, w którym generowane są pliki. Jeśli używana wersja du nie obsługuje --inodes, polecenie sudo find /var -xdev -type f | wc -l zliczy poddrzewo w wolniejszy sposób.
Rozwiązaniem jest usunięcie lub przeniesienie tych plików. Nie można zwiększyć liczby i-węzłów w istniejącym systemie plików ext4, ponieważ ich liczba jest ustalana w momencie mkfs, więc zwiększenie tego limitu wymaga odtworzenia systemu plików i przywrócenia danych z kopii zapasowej. System XFS przydziela i-węzły dynamicznie w miarę potrzeb, więc nie napotyka takiego samego sztywnego ograniczenia. Maszyna obsługująca kontenery osiąga oba limity szybciej niż inne, ponieważ warstwy obrazów zawierają wiele małych plików. W takim przypadku czyszczenie użycia dysku przez Docker na VPS jest właściwym rozwiązaniem, które odzyskuje znacznie więcej miejsca niż ogólne porządkowanie systemu plików.
Miejsce ukryte pod punktem montowania
Katalog może zawierać pliki przed zamontowaniem w nim czegokolwiek. Po zamontowaniu systemu plików w tym katalogu, znajdujące się pod nim pliki pozostają w tym samym miejscu: nadal zajmują miejsce, są uwzględniane przez df, ale nie można uzyskać do nich dostępu za pomocą nazwy. du nie widzi ich, ponieważ punkt montowania je przesłania.
Można to wykazać przy użyciu tmpfs, który nie wymaga wolnego miejsca na dysku. Ta część wymaga maszyny z uprawnieniami do montowania, więc zadziała na VPS typu KVM.
sudo mkdir -p /srv/covered
sudo cp /etc/services /srv/covered/
ls /srv/covered
sudo mount -t tmpfs tmpfs /srv/covered
ls /srv/covered
sudo umount /srv/covered
ls /srv/coveredŚrodkowe ls pokazuje pusty katalog. Kopia nigdzie nie zniknęła: nadal znajduje się w głównym systemie plików i powraca w momencie odmontowania. Należy wyobrazić sobie usługę, która zapisywała logi w tej ścieżce przez miesiąc, zanim ktoś zamontował na niej wolumen.
Aby znaleźć rzeczywiste dane na działającym serwerze, należy zamontować główny system plików po raz drugi w innym miejscu. Montowanie typu bind pokazuje system plików bez zamontowanych wewnątrz niego innych systemów plików.
sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheckWszystko, co pojawia się w tym wykazie, a nie jest widoczne w standardowej ścieżce, znajduje się pod punktem montowania. Po zakończeniu pracy należy odmontować montowanie typu bind, w przeciwnym razie późniejsze du bez flagi -x policzy te same pliki dwukrotnie.
Bloki zarezerwowane dla użytkownika root
System plików ext4 rezerwuje część bloków dla użytkownika root, aby zapełnienie dysku nie uniemożliwiło zalogowania się i naprawy systemu. Proces uruchomiony przez zwykłego użytkownika napotka błąd braku miejsca jako pierwszy, podczas gdy df nadal będzie wskazywać na niewielki zapas. Należy sprawdzić ustawienia dla własnego systemu plików zamiast zakładać wartości domyślne.
dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'Polecenie to wyświetla całkowitą liczbę bloków oraz liczbę bloków zarezerwowanych w tych samych jednostkach, dzięki czemu stosunek między nimi jest bezpośredni. df raportuje kolumnę dostępnego miejsca jako przestrzeń, którą może jeszcze wykorzystać zwykły użytkownik, dlatego suma użytego i dostępnego miejsca jest mniejsza niż całkowity rozmiar. Różnica to rezerwa.
Wartość tę można zmienić za pomocą sudo tune2fs -m <percent> "$dev". Zmiana jest stosowana natychmiastowo i nie wymaga ponownego montowania systemu plików. Zmniejszenie rezerwy na oddzielnym systemie plików z danymi jest uzasadnione. W przypadku głównego systemu plików (root) należy pozostawić wystarczającą ilość miejsca, aby użytkownik root mógł zapisywać dane, ponieważ całkowicie zapełniony system plików jest znacznie trudniejszy w naprawie. Rezerwa chroni również przed utratą dostępu: klucz dopisywany do authorized_keys na systemie plików bez wolnego miejsca może zostać zapisany niekompletnie lub wcale, a kolejna próba logowania zakończy się błędem Permission denied (publickey) z przyczyn niezwiązanych z samym kluczem. tune2fs działa w systemach ext2, ext3 oraz ext4. System XFS nie posiada odpowiednika tego ustawienia.
Kiedy polecenie du wprowadza w błąd
Cztery zachowania du powodują, że sumaryczne wartości wydają się nieprawidłowe.
- Dowiązania twarde (hard links):
duzlicza i-węzeł (inode) tylko raz, nawet jeśli wskazuje na niego kilka nazw, więc drzewo pełne dowiązań twardych raportuje mniejszy rozmiar niż suma rozmiarów poszczególnych plików. - Pliki rzadkie (sparse files):
duraportuje liczbę faktycznie przydzielonych bloków, podczas gdyls -lraportuje rozmiar pozorny. Należy dodać flagę--apparent-size, aby wyświetlić drugą z tych wartości. - Uprawnienia: uruchomione przez zwykłego użytkownika,
dupomija pliki, których nie może odczytać, co prowadzi do zaniżonych wyników. Wyświetlane przy tym błędy są często przekierowywane do/dev/nulli ignorowane przez użytkowników. - Granice systemu plików: bez flagi
-x,du /zlicza każdy system plików zamontowany poniżej/, dlatego wynik końcowy może przekraczać wartość raportowaną przezdf /.
Polecenie df również posiada cechę, o której warto wiedzieć. Raportuje ono każdy system plików oddzielnie, dlatego należy je uruchomić dla konkretnej ścieżki, w której występuje błąd zapisu. Oddzielna partycja /boot zapełnia się w swoim własnym tempie wraz z gromadzeniem się pakietów jądra, a usuwanie starych jąder w systemie Ubuntu jest zadaniem odrębnym od zwalniania miejsca na /.
Procedura postępowania w przypadku rzeczywistego incydentu
- Uruchom
df -h <path>orazdf -i <path>na systemie plików, którego dotyczył nieudany zapis, a nie odruchowo na/. - Uruchom
sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -h, a następnie przejdź do największego katalogu. - Jeśli
dunie wykazuje użycia zgłaszanego przezdf, przeszukaj/procpod kątem usuniętych plików, które są nadal otwarte. - Jeśli wartości są zgodne, wykonaj bind mount systemu plików w innej lokalizacji i sprawdź, czy pod punktem montowania nie znajdują się ukryte pliki.
- Jeśli wyczerpany został limit inode, licz pliki, a nie bajty.
Każdy z tych kroków to polecenie, którego wynik można odczytać. Na tym polega różnica między naprawą a zgadywaniem.
FAQ
Dlaczego df pokazuje, że dysk jest pełny, podczas gdy du wykazuje znacznie mniejsze zajęcie?
Typową przyczyną jest plik, który został usunięty, podczas gdy proces nadal go utrzymuje jako otwarty. Usunięcie pliku usuwa jego wpis w katalogu, więc du nie ma nazwy do śledzenia i przestaje go uwzględniać w obliczeniach. Inode oraz powiązane z nim bloki pozostają przydzielone do momentu zamknięcia ostatniego deskryptora, a df zlicza wszystkie przydzielone bloki. Przeszukaj /proc/<pid>/fd pod kątem dowiązań symbolicznych, których cel jest oznaczony jako usunięty – w ten sposób zidentyfikujesz zarówno plik, jak i proces, który go blokuje. Przed uznaniem porównania za wiarygodne upewnij się, że uruchomiłeś du jako root z flagą -x, ponieważ zwykły użytkownik pomija bez ostrzeżenia katalogi, do których nie ma uprawnień odczytu.
Jak znaleźć usunięty plik, który jest nadal otwarty, bez użycia lsof?
Skorzystaj z wbudowanego w jądro rejestru otwartych deskryptorów. sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null wyświetla każdy deskryptor wskazujący na plik bez nazwy, a identyfikator procesu (PID) znajduje się w ścieżce, którą narzędzie wypisuje. sudo stat -Lc %s na jednej z tych ścieżek deskryptorów raportuje rozmiar pliku, co pozwala na ich posortowanie i wybranie istotnego zasobu. Metoda ta nie wymaga instalacji żadnego pakietu, co jest kluczowe w sytuacjach, gdy instalacja oprogramowania na systemie plików bez wolnego miejsca kończy się niepowodzeniem.
Czy można zwolnić miejsce bez przerywania procesu?
Czasami. sudo truncate -s 0 /proc/<pid>/fd/<n> uzyskuje dostęp do tego samego inode poprzez deskryptor i zwalnia jego bloki, podczas gdy proces nadal działa. Jest to najbezpieczniejsze rozwiązanie, gdy proces otworzył plik w trybie dopisywania (append mode), ponieważ zapisy zawsze trafiają na koniec pliku. Jeśli tak nie jest, przesunięcie zapisu (write offset) pozostaje w poprzednim miejscu, a kolejny zapis odtwarza plik z luką na początku. W rezultacie zgłaszany rozmiar wraca do poprzedniej wartości, podczas gdy bloki pod luką pozostają wolne. Restart jednostki lub wysłanie sygnału wymuszającego ponowne otwarcie logów (zgodnie z dokumentacją aplikacji) jest rozwiązaniem, które nie pozostawia rzadkich plików (sparse files).
df pokazuje wolne miejsce, ale zapisy nadal kończą się błędem. Co może być przyczyną?
Sprawdź liczbę inode za pomocą df -i dla danej ścieżki, ponieważ system plików z wolnymi blokami, ale bez wolnych inode, odrzuca tworzenie nowych plików. Sprawdź, czy zapis jest wykonywany przez użytkownika innego niż root na systemie plików ext4, gdzie pozostały tylko zarezerwowane bloki – informację o tym wyświetli sudo tune2fs -l dla danego urządzenia. Upewnij się, że sprawdzasz system plików, do którego faktycznie kierowany jest zapis, ponieważ oddzielne /boot lub /var zapełniają się niezależnie od /.
Dlaczego du raportuje większą sumę niż df?
du bez flagi -x przechodzi przez wszystkie systemy plików zamontowane pod wskazaną ścieżką, sumując zajętość wielu systemów plików, podczas gdy df opisuje tylko jeden. Montowania typu bind pogarszają ten efekt, ponieważ te same pliki są zliczane wielokrotnie w każdej ścieżce, w której się pojawiają. Dodaj -x, aby ograniczyć du do jednego systemu plików, i wskaż df tę samą ścieżkę, aby oba polecenia opisywały ten sam zakres danych.