SSD Nodes Learn 🎉 VPS $5.50/aydan başlayan
Rehberler Matt ConnorYazan Matt Connor

df dolu du boş gösteriyor sorunu nasıl çözülür

df komutu dolu, du komutu boş alan gösterdiğinde silinen ancak süreçler tarafından tutulan dosyaları lsof ile bulun. Inode tükenmesi ve mount noktası hatalarını giderin.

df komutu neden dolu, du komutu neden boş gösteriyor

df, disk alanını dolu olarak raporlarken du, silinmiş ancak bir süreç tarafından hala tutulan bir dosya nedeniyle bu alanı bulamaz. Bir dosyayı silmek, dosya ismini dizinden kaldırır. Veri blokları, yalnızca o inode'u işaret eden son açık dosya tanımlayıcısı kapatıldığında serbest bırakılır. du, dosya isimlerini takip ettiği için bu alanı saymaz. df ise dosya sistemine kaç bloğun tahsis edildiğini sorduğu için ismi artık olmayan dosyayı hala saymaya devam eder.

Bu kılavuz, durumu halihazırda yüklü araçlarla standart bir Ubuntu VPS üzerinde yeniden oluşturur, /proc aracılığıyla dosyayı tutan süreci bulur ve sistemi yeniden başlatmadan alanı boşaltır. Aynı belirtinin diğer nedenleri şunlardır: boş girişi kalmamış bir inode tablosu, bir mount noktası altında gizli kalan dosyalar ve root kullanıcısı için ayrılmış bloklar.

Her komutu çalıştırın ve kendi çıktınızı okuyun. Değerler diskinize bağlıdır; bu nedenle kılavuzda yazan rakamlarla karşılaştırmak yerine, kendi makinenizdeki işlem öncesi ve sonrası değerleri karşılaştırın.

df ve du neyi sayar

df (disk free), her bir bağlı dosya sistemine kendi muhasebesini sorar: kaç blok var, kaçı tahsis edilmiş, kaçı boş. Hiçbir dizini açmaz. Yanıt, hiçbir dizin girdisinin işaret etmediği dosyalara ait bloklar da dahil olmak üzere, tahsis edilmiş her bloğu kapsar.

du (disk usage) tam tersini yapar. Verdiğiniz bir yoldan başlar, dizinleri okur, bulduğu her girdinin istatistiklerini alır ve blokları toplar. İsmi olmayan bir dosya onun için görünmezdir. Okumasına izin verilmeyen dizinler de öyledir; bu yüzden normal bir kullanıcı, root kullanıcısından daha küçük bir toplam elde eder. Karşılaştırmadan bir sonuca varmadan önce du komutunu sudo altında çalıştırın.

İkisini karşılaştırırken her seferinde iki seçenek önem taşır.

  • -x, du işlemini tek bir dosya sistemi üzerinde tutar. Bu seçenek olmadan du /, / altında bağlı olan her dosya sistemine girer ve df / aracının asla ölçmediği bir toplam üretir.
  • -s, her dizin için bir satır yerine her argüman için tek bir özet satırı yazdırır.

Bu, ilgilendiğiniz dosya sistemi üzerinde yan yana çalıştırmanız gereken ikiliyi sağlar.

df -h /
sudo du -xhs / 2>/dev/null

df anında yanıt verir. du, büyük bir dosya sisteminde her dosyanın istatistiğini aldığı için dakikalar sürer. İki toplam birbirinden çok uzaksa ve du, -x ile root olarak çalıştırılmışsa, eksik alan ismi olmayan bir şeye tahsis edilmiştir.

Uyumsuzluğu kasten oluşturma

Bunu bir test VPS üzerinde gerçekleştirin. Aşağıdaki işlemlerin tamamı bash ve coreutils ile yapıldığından, herhangi bir kurulum gerektirmez.

/var/tmp dizinini barındıran dosya sisteminin başlangıç durumunu kaydedin.

cd /var/tmp
df -h .
df --output=used -B1 .

İkinci komut, kullanılan bayt miktarını yuvarlama yapmadan yazdırır; bu sayede sondaki kontrol tam sonuç verir.

Şimdi bir dosya oluşturun. Dosya boyutu, makinenin kendi raporladığı boş alan üzerinden belirlenir; böylece gösterim, sahip olduğunuz disk kapasitesine uyum sağlar.

free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .

$(...) komut ikamesidir (command substitution): kabuk, içindeki komutu çalıştırır ve çıktısını free değerine atar. Bu sözdizimi sizin için yeniyse, bash'te komut ikamesi konusu bunu kapsamlı şekilde açıklar. fallocate, verileri yazmadan gerçek blokları rezerve eder; bu yüzden işlem anında tamamlanır. Bunu desteklemeyen bir dosya sisteminde komut başarısız olur; bu durumda head -c $((free / 10)) /dev/zero > ghost.bin aynı işi baytları tek tek yazarak gerçekleştirir.

Bu df -h . çıktısını kaydettiğiniz değerle karşılaştırın. Kullanılan alan sütununun arttığını, kullanılabilir alan sütununun ise azaldığını göreceksiniz.

Şimdi dosyayı başka bir süreç üzerinden açık tutun ve ardından silin.

sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/null

Yönlendirme işlemin püf noktasıdır. sleep infinity < ghost.bin &, standart girdisi ilgili dosya olan bir arka plan süreci başlatır; böylece kabuk dosyayı açar ve dosya tanımlayıcısını (descriptor), dosyayı açık tutan sleep sürecine iletir. $!, bu arka plan işinin süreç kimliğini (PID) tutar. rm ise dosya tanımlayıcısı hala açıkken dosya ismini siler.

Çıktıyı okuyun. ls dosya ismini bulamaz, çünkü isim silinmiştir. du, dosya isimlerini taradığı için başlangıç değerine yakın bir noktaya dönmüştür. df ise bloklar hala tahsis edilmiş durumda olduğu için değişmemiştir. Dosya sistemi ile dizin ağacı artık birbirini tutmamaktadır; aradaki fark, az önce sildiğiniz dosyadır.

Silinmiş dosyayı tutan süreci bulma

Her açık dosya tanımlayıcısı (file descriptor), referans verdiği dosyaya giden sembolik bir bağlantı olarak /proc/<pid>/fd/ altında görünür. Dosya bağlantısı kesildiğinde (unlink), çekirdek bu bağlantının hedefini silinmiş olarak işaretler. Dolayısıyla, dosyayı tutan süreci bulmak, hedefi bu işareti taşıyan bir bağlantıyı bulmak anlamına gelir.

sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

find /proc//fd -lname '(deleted)*' 2>/dev/null

-lname, sembolik bağlantının isminden ziyade hedefini eşleştirir, %p tanımlayıcı yolunu yazdırır ve %l ise bağlantının nereyi işaret ettiğini gösterir. Süreç kimliği (PID), yazdırdığı yolun ikinci öğesidir. Komutu sudo ile çalıştırın; aksi takdirde yalnızca kendi süreçleriniz için /proc/<pid>/fd dizinini okuyabilirsiniz. Standart hata yönlendirmesi (stderr redirect), find tarama yaparken sonlanan süreçlerden gelen gürültüyü engeller.

Yoğun bir sunucuda her an silinmiş durumda olan birçok dosya bulunur ve bunların çoğu küçük ve zararsızdır. Bunları boyuta göre sıralayarak yalnızca önemli olanların en üstte kalmasını sağlayın.

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 | head

find /proc//fd -lname '(deleted)*' -printf '%p %s\n' 2>/dev/null | sort -nk2

stat -L, bağlantıyı doğrudan inode'un kendisine kadar takip eder, bu sayede %s artık bir ismi olmayan dosyanın boyutunu raporlar. Bu sayıya göre sıralama yapmak, en büyük dosyayı en başa getirir.

Ardından, kazanan tanımlayıcının arkasındaki süreci tanımlayın. Listenin en üstündeki yol, ihtiyacınız olan her iki sayıyı da içerir; bu yüzden PID ve N değerlerini kendi listenizde çıkanlarla değiştirerek değişkenlere atayın.

pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"

ps -p PID -o comm=; ls -l /proc/PID/fd/N

ps programın adını belirtir ve ne kadar süredir çalıştığını gösterir. stat -L, silinmiş inode'un boyutunu ve ayrılmış blok sayısını yazdırır. Birlikte, önemli olan soruyu yanıtlarlar: Hangi servis bu dosyayı canlı tutuyor?

Eğer makinede halihazırda lsof yüklüyse, sudo lsof +L1 bağlantı sayısı sıfıra düşmüş açık dosyaları listeler ve boyutlarını tek bir tabloda gösterir. Bu araç minimal bir Ubuntu imajında bulunmaz ve boş alanı kalmamış bir dosya sistemine paket kurmak başarısız olabilir; bu nedenle /proc ile yapılan tarama her zaman çalışan yöntemdir.

Yeniden başlatma yapmadan alanı boşaltma

Yeniden başlatma işlemi sorunu çözer ancak bu yanlış bir ilk adımdır: servisi devre dışı bırakır ve kanıtları yok eder. Denenmesi gereken sırayla dört daha güvenli seçenek mevcuttur.

İlk olarak, verileri hala istiyorsanız dışarı kopyalayın. Tanımlayıcı yolunu okumak, canlı inode verisini okur.

sudo cp /proc/<pid>/fd/<n> /root/recovered.log

Bu, silinen bir dosyanın geri getirilmesinin kolay olduğu tek durumdur; bu nedenle rm -rf ile silinen dosyaları kurtarma konusu, bir sürecin dosyayı hala açık tutup tutmadığını sorarak başlar. Son tanımlayıcı kapandığında, bu yol artık kullanılamaz hale gelir.

İkinci olarak, dosyayı tanımlayıcı üzerinden boşaltın. /proc yolu aynı inode verisine çıkar, bu nedenle dosyayı kırpmak (truncate), süreç çalışmaya devam ederken blokları serbest bırakır.

sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /

Yazıcı süreç dosyayı ekleme (append) modunda açtıysa bu yöntem temiz bir şekilde çalışır, çünkü her yazma işlemi dosyanın güncel sonuna gider. Eğer böyle değilse, süreç eski yazma ofsetini korur; bu durumda bir sonraki yazma işlemi dosyanın çok ilerisine düşer ve ön tarafta bir boşluk (hole) oluşturarak dosyayı yeniden yaratır. Boşluklar tahsis edilmediğinden bloklar boş kalır ve df az önce geri kazandığı alanı korur. Geri gelen şey sadece dosya boyutudur: süreç yazma yaptıktan sonra sudo stat -L "/proc/$pid/fd/$n" komutunu tekrar çalıştırırsanız, dosya boyutu ile artık eşleşmeyen bir blok sayısı rapor eder. Boyutun da sıfırdan başlamasını istiyorsanız süreci yeniden başlatın.

Üçüncü olarak, servisten günlük dosyalarını yeniden açmasını isteyin. Günlük dosyası altından silinmiş bir daemon, bu sorunun gerçek hayattaki yaygın bir örneğidir. Birçok daemon, bir sinyal aldığında günlük dosyalarını yeniden açar: nginx SIGUSR1 kullanırken, rsyslog SIGHUP kullanır. Tahmin etmek yerine elinizdeki daemon'ın dokümantasyonunu kontrol edin, çünkü yanlış daemona gönderilen yanlış bir sinyal onu durdurabilir.

sudo systemctl kill -s USR1 nginx

Dördüncü olarak, birimi yeniden başlatın. sudo systemctl restart <unit>, eski sürecin tuttuğu tüm tanımlayıcıları kapatır, böylece bloklar kesin olarak geri kazanılır. Yukarıdaki gösterim için tutucu, bizzat başlattığınız bir sleep sürecidir, bu yüzden onu sonlandırmak yeterlidir.

kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

Kullanılan bayt miktarını, dosyayı oluşturmadan önce kaydettiğiniz değerle karşılaştırın. Değerler tekrar eşleşecektir ve find artık tanımlayıcınızı rapor etmeyecektir. Sorunu bulan aynı komutla doğrulama yapmak, edinilmesi gereken bir alışkanlıktır.

Bu değerin değişimini izlemek, df komutunu sürekli elle çalıştırmaktan daha kolaydır. watch bir komutu sabit aralıklarla tekrarlar ve çıktıyı yerinde günceller; bu sayede watch df -h /, alan geri kazanıldıkça kullanılan sütununun değişimini gösterir.

Toplamlar uyuştuğunda ve disk hala doluysa

Eğer df ve root du -x birbiriyle uyuşuyorsa, silinmiş bir dosya söz konusu değildir. Geriye kalan nedenler yapısal olarak farklıdır ve her birinin kendine özgü bir kontrol yöntemi bulunur.

Bloklar değil, inode'lar tükenmiş

Bir inode, tek bir dosyanın meta verilerini tutar. ext4, dosya sistemi oluşturulduğunda sabit sayıda inode yaratır; bu nedenle bir dosya sistemi, boş blokları olmasına rağmen inode'ları tüketebilir. df -h komutu yer olduğunu gösterse bile yeni dosyalar oluşturulamaz.

df -h /
df -i /

İlk komut blokları, ikincisi ise inode'ları sayar. Her birinin kullanım sütununu karşılaştırın. Blok kullanımı düşük, inode kullanımı ise sınırda ise sorun, çok sayıda çok küçük dosyanın bulunmasıdır.

df, aynı çağrıda -i ve --output parametrelerini kabul etmez. Bu nedenle ham sayıları okumak veya başka bir komuta aktarmak istediğinizde, inode alanlarını isimleriyle seçin ve -i parametresini kullanmayın.

df --output=itotal,iused,iavail,ipcent /

Bu sütunlar, df -i komutunun yazdırdığı muhasebe verilerini ayrıştırılabilir bir biçimde taşır.

Dosyaları bayt yerine giriş sayılarını sayarak bulun.

sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | head

Aynı komutu, en çok dosya barındıran dizin üzerinde bir alt seviyeye inerek, dosyaları oluşturan ağaca ulaşana kadar tekrarlayın. Eğer du sürümünüz --inodes parametresini desteklemiyorsa, sudo find /var -xdev -type f | wc -l komutu alt ağacı yavaş yöntemle sayacaktır.

Çözüm, bu dosyaların silinmesi veya taşınmasıdır. Mevcut bir ext4 dosya sistemine inode ekleyemezsiniz; çünkü sayı mkfs zamanında sabitlenmiştir. Bu sayıyı artırmak, dosya sistemini yeniden oluşturmayı ve yedekten geri yükleme yapmayı gerektirir. XFS, inode'ları ihtiyaç duydukça tahsis eder, bu nedenle benzer bir sabit sınıra takılmaz. Konteyner çalıştıran bir makine, imaj katmanları birçok küçük dosya barındırdığı için her iki sınıra da normalden daha hızlı ulaşır. Bu tür bir makinede VPS üzerinde Docker disk kullanımını temizleme işlemi özel çözümdür ve dosya sisteminde yapılacak genel bir taramadan çok daha fazla alan geri kazanımı sağlar.

Bağlama noktası altında gizli alan

Bir dizin, üzerine herhangi bir şey bağlanmadan önce dosyaları barındırabilir. Bir dosya sistemini bu dizinin üzerine bağladığınızda, alttaki dosyalar oldukları yerde kalırlar: hala tahsis edilmiş durumdadırlar, df tarafından hala sayılırlar ancak artık isimleriyle erişilemezler. du, bağlama işlemi üzerlerini örttüğü için bu dosyaları göremez.

Bunu, boş disk alanı gerektirmeyen tmpfs ile gösterin. Bu kısım, bağlama yapma izninizin olduğu bir makine gerektirir, bu nedenle bir KVM VPS üzerinde çalışır.

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

Ortadaki ls boş bir dizini gösterir. Kopyalama işlemi hiçbir yere gitmemiştir: hala kök dosya sistemindedir ve bağlantıyı kaldırdığınız anda geri döner. Şimdi, birisi üzerine bir birim bağlamadan önce bir ay boyunca bu yola günlük kaydı yapan bir servis hayal edin.

Çalışan bir sunucuda gerçek dosyaları bulmak için, kök dosya sistemini başka bir yere ikinci kez bağlayın. Bir bind mount, içine bağlı diğer dosya sistemleri olmadan tek bir dosya sistemini gösterir.

sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheck

Bu listede görünen ancak normal yolun altında görünmeyen her şey, bir bağlama noktasının altında gömülüdür. İşiniz bittiğinde bind mount bağlantısını kaldırın; aksi takdirde -x içermeyen sonraki bir du, aynı dosyaları iki kez sayacaktır.

root kullanıcısı için ayrılmış bloklar

ext4, disk tamamen dolduğunda root kullanıcısının sisteme giriş yapmasını ve onarım gerçekleştirmesini engellememek için bloklarının bir kısmını root kullanıcısına ayırır. Normal bir kullanıcı tarafından çalıştırılan bir süreç bu sınıra ulaştığında, df hala küçük bir boşluk olduğunu gösterir. Varsayılan değerleri kabul etmek yerine kendi dosya sisteminizdeki ayarı kontrol edin.

dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'

Bu komut, toplam blok sayısını ve ayrılmış blok sayısını aynı birimlerle yazdırır; böylece aralarındaki oran doğrudan görülebilir. df, mevcut sütununu normal bir kullanıcının hala kullanabileceği alan olarak raporlar; bu nedenle kullanılan alan ile mevcut alanın toplamı, toplam boyuttan daha küçük çıkar. Aradaki fark, ayrılmış olan kısımdır.

Bu değeri sudo tune2fs -m <percent> "$dev" ile değiştirin. Değişiklik anında uygulanır ve yeniden mount işlemi gerektirmez. Ayrı bir veri dosya sisteminde ayrılmış alanı düşürmek mantıklıdır. Kök (root) dosya sisteminde ise root kullanıcısının yazmaya devam edebilmesi için yeterli alan bırakın; çünkü tamamen dolu bir kök dosya sistemini onarmak çok daha zordur. tune2fs, ext2, ext3 ve ext4 üzerinde çalışır. XFS dosya sisteminde buna karşılık gelen bir ayar bulunmamaktadır.

du komutunun tek başına yanıltıcı olduğu durumlar

du aracının dört alışkanlığı, yanlış görünen toplamlar üretmesine neden olur.

  • Sabit bağlantılar (Hard links): du, birden fazla isim aynı inode'u işaret etse bile onu yalnızca bir kez sayar; bu nedenle sabit bağlantılarla dolu bir dizin ağacı, dosyalarının toplam boyutundan daha düşük bir değer rapor eder.
  • Seyrek dosyalar (Sparse files): du, fiilen ayrılmış blokları rapor ederken, ls -l görünen boyutu rapor eder. Diğer değeri görmek için --apparent-size bayrağını ekleyin.
  • İzinler: Normal bir kullanıcı olarak çalıştırıldığında, du okuyamadığı dosyaları atlar ve eksik raporlama yapar. Ekrana yazdırdığı hatalar, kullanıcıların genellikle /dev/null dosyasına yönlendirip okumayı bıraktığı hatalardır.
  • Dosya sistemi sınırları: -x kullanılmadığında, du / aracı / altında bağlı olan her dosya sistemini sayar; bu nedenle toplam değer, df / aracının rapor ettiğinden daha yüksek çıkabilir.

df aracının da bilinmesi gereken bir alışkanlığı vardır. Her dosya sistemini ayrı ayrı rapor eder; bu yüzden komutu, yazma işleminin başarısız olduğu tam yol üzerinde çalıştırın. Ayrı bir /boot bölümü, çekirdek paketleri biriktikçe kendi zamanlamasına göre dolar ve Ubuntu üzerinde eski çekirdekleri kaldırmak, / üzerindeki alanı temizlemekten farklı bir işlemdir.

Gerçek bir olayda çalışma düzeni

  1. Başarısız yazma işleminin hedeflediği dosya sistemi üzerinde df -h <path> ve df -i <path> komutlarını çalıştırın; refleks olarak / üzerinde işlem yapmayın.
  2. sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -h komutunu çalıştırın, ardından en büyük dizinin içine girin.
  3. du, df tarafından raporlanan kullanım miktarını açıklayamıyorsa, /proc üzerinde silinmiş ancak hala açık olan dosyaları arayın.
  4. İki değer birbirini tutuyorsa, dosya sistemini başka bir yere bind mount edin ve mount noktası altında kalan dosyaları inceleyin.
  5. Sınırda olan inode kullanımı ise, bayt yerine dosya sayısını kontrol edin.

Buradaki her adım, çıktısını okuyabileceğiniz bir komuttur. Sorunu tahmin ederek değil, bu şekilde çözebilirsiniz.

FAQ

df komutu diski dolu gösterirken du neden çok daha az yer kaplandığını söylüyor?

Bunun yaygın nedeni, bir işlem tarafından açık tutulan ancak silinmiş bir dosyadır. Dosyayı silmek dizin girdisini kaldırır; bu nedenle du dosyanın adını bulamaz ve saymayı bırakır. Inode ve ilgili bloklar, son dosya tanımlayıcısı (descriptor) kapanana kadar tahsis edilmiş halde kalır ve df tahsis edilen tüm blokları sayar. Hedefi silinmiş olarak işaretlenmiş sembolik bağlantıları bulmak için /proc/<pid>/fd dizinini inceleyin; böylece hem dosyayı hem de onu tutan işlemi tespit edebilirsiniz. Karşılaştırmaya güvenmeden önce du komutunu root yetkileriyle ve -x bayrağıyla çalıştırdığınızdan emin olun; aksi takdirde normal bir kullanıcı okuyamadığı dizinleri sessizce atlayacaktır.

lsof kullanmadan açık olan silinmiş bir dosyayı nasıl bulabilirim?

Çekirdeğin açık tanımlayıcı kayıtlarını kullanın. sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null, adı olmayan bir dosyayı işaret eden her tanımlayıcıyı listeler; işlem kimliği (PID) ise yazdırdığı yolun içinde yer alır. Bu tanımlayıcı yollarından birinde sudo stat -Lc %s komutunu çalıştırmak dosya boyutunu raporlar; böylece bunları sıralayabilir ve önemli olanı seçebilirsiniz. Bu yöntem herhangi bir paket kurulumu gerektirmez; boş alanı kalmamış bir dosya sistemine yeni paket kurmak başarısız olabileceği için bu önemlidir.

İşlemi sonlandırmadan alanı boşaltabilir miyim?

Bazen mümkündür. sudo truncate -s 0 /proc/<pid>/fd/<n>, tanımlayıcı aracılığıyla aynı inode'a ulaşır ve işlem çalışmaya devam ederken blokları serbest bırakır. Bu yöntem, işlem dosyayı ekleme (append) modunda açtıysa en temiz sonucu verir; çünkü yazma işlemleri her zaman dosyanın sonuna yapılır. Eğer dosya bu modda açılmadıysa, yazma imleci kaldığı yerde kalır ve bir sonraki yazma işlemi dosyanın başında bir boşluk (hole) oluşturarak dosyayı yeniden yaratır; bu durumda raporlanan boyut geri döner ancak boşluğun altındaki bloklar serbest kalır. Birimi yeniden başlatmak veya dokümantasyonunda belirtilen sinyali göndererek log dosyalarını yeniden açmasını sağlamak, geride seyrek (sparse) dosya bırakmayan kesin çözümdür.

df boş alan olduğunu gösteriyor ancak yazma işlemleri başarısız oluyor. Başka ne olabilir?

Aynı yol üzerinde df -i ile inode durumunu kontrol edin; çünkü boş blokları olan ancak boş inode'u kalmamış bir dosya sistemi yeni dosyaları reddeder. Yazma işleminin root olmayan bir kullanıcı tarafından, yalnızca ayrılmış blokların kaldığı bir ext4 dosya sistemine yapılıp yapılmadığını kontrol edin; bunu cihaz üzerinde sudo tune2fs -l komutuyla görebilirsiniz. Yazma işleminin hedeflediği dosya sistemini okuduğunuzdan emin olun; çünkü ayrı bir /boot veya /var, / dosya sisteminden bağımsız olarak dolar.

du neden df'den daha büyük bir toplam raporluyor?

-x bayrağı olmadan kullanılan du, verdiğiniz yolun altına bağlanmış (mount edilmiş) her dosya sistemine girer; bu nedenle birden fazla dosya sistemini toplar, oysa df tek bir tanesini tanımlar. Bind mount işlemleri durumu daha da karmaşıklaştırır; çünkü aynı dosyalar göründükleri her yol altında tekrar sayılır. du komutunu tek bir dosya sistemi üzerinde tutmak için -x bayrağını ekleyin ve df komutuna aynı yolu verin; böylece her iki komut da aynı şeyi tanımlamış olur.