Açık ancak silinmiş büyük dosyaları bulup kaldırın


120

Biri silinmiş ancak hala bir uygulamada açık olan büyük dosyaları nasıl bulur? Bir süreç açılmış olsa bile böyle bir dosyayı nasıl kaldırabilirim?

Durum, bir günlük dosyasını müthiş bir oranda dolduran bir işlem yürütüyor olmamızdır. Sebebini biliyorum ve düzeltebilirim. O zamana kadar, süreci kapatmadan günlük dosyasını rm ya da boşaltmak istiyorum.

Basitçe yapmak rm output.logyalnızca dosyaya yapılan referansları kaldırır, ancak işlem sonlandırılıncaya kadar diskte yer kaplamaya devam eder. Daha da kötüsü: rming sonra şimdi dosyanın nerede olduğunu veya ne kadar büyük olduğunu bulmak için hiçbir yolu yok! Dosyayı bulmanın ve başka bir işlemde hala açık olsa bile, muhtemelen boşaltmasının bir yolu var mı?

Özellikle Debian veya RHEL gibi Linux tabanlı işletim sistemlerine atıfta bulunuyorum.


2
Pid'i biliyorsanız o zaman lsof -p <pid>açık dosyalarını ve boyutlarını listelemek için kullanabilirsiniz . Silinen dosya (deleted)yanında olacaktır. Silinen dosya /proc/<pid>/fd/1muhtemelen bağlanacaktır . Bir işlemi durdurmadan dosya tanımlayıcısına yazma işlemini nasıl durduracağımı bilmiyorum. Bunun sürece bağlı olacağını düşünüyorum.
donothings başarılı bir şekilde

Teşekkürler. İnsan rmhala açık olan tüm ed dosyalarının PID'lerini nasıl alabilir ?
dotancohen

@donothingsuccessfully lsof tarafından bildirilen "deleted" etiketi Solaris'e özgüdür, aslında sadece Solaris 10 veya üstü. OP hangi işletim sistemini kullandığını belirtmedi. @dotancohen Solaris'te silinmiş aramak için lsof çıkışını borulandırabilirsiniz, örn lsof | grep "(deleted)". Silinen bir dosyayı açık tutan başka işlem olmadığında, çekirdek inode ve disk bloklarını serbest bırakır. İşlemlerde, açık, esasen kilitli bir dosyanın diskten çıkarıldığı bildirilebilecekleri "işleyiciler" yoktur.
Johan

2
@Johan, lsof | grep '(deleted)'Linux üzerinde de çalışır. Linux'ta, inotify mekanizmasıyla (IN_DELETE_SELF olayı) dosya silme durumundan (artık / proc / some-pid / fd dışında herhangi bir dizinde zaten bir girişi olmayan dosyalar bile) haberdar olun
Stéphane Chazelas

somefileVIM'de yarattım ve açtım, sonra rmbaşka bir bash işleminde edindim. Sonra çalıştırın lsof | grep somefileve dosya VIM'de açık olsa bile, orada değil.
dotancohen

Yanıtlar:


141

Uygulamanızı öldüremezseniz, alanı geri kazanmak için günlük dosyasını silmek yerine kesebilirsiniz. Dosya ekleme modunda (with O_APPEND) açılmadıysa , dosya bir dahaki sefere uygulamanın (önceki kısım seyrek ve NUL bayt içeriyormuş gibi görünüyor olsa da) yazdığı zamanki kadar büyük görünür. geri kazanılmış olacak (Apple OS / X'teki HFS + dosya sistemleri için geçerli değildir, ancak seyrek dosyaları desteklememektedir).

Kısaltmak için:

: > /path/to/the/file.log

Önceden silinmişse, Linux'ta aşağıdakileri yaparak onu kesebilirsiniz:

: > "/proc/$pid/fd/$fd"

Nerede $pidaçılmış dosyası vardır işlemin işlem kimliği olduğunu ve $fdbir dosya tanıtıcı buna sen ile kontrol edebilirsiniz hangi (altında açılan sahiptir lsof -p "$pid".

Pid'i bilmiyorsanız ve silinen dosyaları arıyorsanız, şunları yapabilirsiniz:

lsof -nP | grep '(deleted)'

lsof -nP +L1, @ User75021 tarafından belirtildiği gibi (1 taneden az bağlantıya sahip liste dosyaları) daha iyi bir (daha güvenilir ve daha taşınabilir) seçenektir.

Veya (Linux'ta):

find /proc/*/fd -ls | grep  '(deleted)'

Ya da büyük olanları bulmak için zsh:

ls -ld /proc/*/fd/*(-.LM+1l0)

Alternatif olarak, uygulama dinamik olarak bağlantılıysa, ona bir hata ayıklayıcı eklemek ve onu close(fd)yeni bir çağrı takip etmektir open("the-file", ....).


1
truncateAynı şeyi daha açık bir şekilde yapan bir komut da var.
Tobu

1
@dotancohen Stephane, pid bilinmediğinde bunun nasıl yapılacağı hakkında bilgi içerecek şekilde düzenlendi.
Didi Kohen

1
@OlivierDulac, lsofmuhtemelen açık dosyaları listelemek için bulabileceğiniz taşınabilir bir çözüme en yakın olacak. Uygulama ayakları altında fd'yi kapatmak için kullanılan hata ayıklayıcı yaklaşımı da oldukça taşınabilir olmalıdır.
Stéphane Chazelas

2
@StephaneChazelas: teşekkürler. Her bölmede açık bir dosyaya sahip tüm PID'leri listelemenin bir yolunu buldum: df -k | awk 'NR>1 { print $NF }' | xargs fuser -Vud (ve sonra fd'yi serbest bırakmaya zorlamak için suçlulara sinyal göndermek kolay)
Olivier Dulac

6
Ayrıca kullanabilirsiniz lsof +L1. Man sayfasından: "Formun bir özelliği +L1, bağlantısı kaldırılmış olan açık dosyaları seçecektir. Formun bir +aL1 <file_system>özelliği, belirtilen dosya sistemindeki bağlantısız açık dosyaları seçecektir.". Greplemekten biraz daha güvenilir olmalı.
Synchro

31

Burada hızlı başlatmayı inceleyin: lsofHızlı başlat

Hiç kimse lsof quickstart dosyasından (lsof dahil) bahsettiğine şaşırdım. "3.a" bölümü açık, bağlantısız dosyaların nasıl bulunacağını gösterir:

lsof -a +L1 *mountpoint*

Örneğin:

[root@enterprise ~]# lsof -a +L1 /tmp
COMMAND   PID   USER   FD   TYPE DEVICE    SIZE NLINK  NODE NAME
httpd    2357 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
mysqld   2588  mysql    4u   REG 253,17      52     0  1495 /tmp/ibY0cXCd (deleted)
mysqld   2588  mysql    5u   REG 253,17    1048     0  1496 /tmp/ibOrELhG (deleted)
mysqld   2588  mysql    6u   REG 253,17       0     0  1497 /tmp/ibmDFAW8 (deleted)
mysqld   2588  mysql    7u   REG 253,17       0     0 11387 /tmp/ib2CSACB (deleted)
mysqld   2588  mysql   11u   REG 253,17       0     0 11388 /tmp/ibQpoZ94 (deleted)
httpd    3457   root   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8437 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8438 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8439 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8440 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8441 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8442 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8443 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8444 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   16990 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   19595 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   27495 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   28142 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   31478 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)

Hızlı başlangıç ​​dosyasının yerel kopyasını bulmak için Red Hat sistemlerinde genellikle şunu yaparım:

[root@enterprise ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART

... veya bu:

[root@enterprise ~]# rpm -qd lsof
/usr/share/doc/lsof-4.78/00.README.FIRST
/usr/share/doc/lsof-4.78/00CREDITS
/usr/share/doc/lsof-4.78/00DCACHE
/usr/share/doc/lsof-4.78/00DIALECTS
/usr/share/doc/lsof-4.78/00DIST
/usr/share/doc/lsof-4.78/00FAQ
/usr/share/doc/lsof-4.78/00LSOF-L
/usr/share/doc/lsof-4.78/00MANIFEST
/usr/share/doc/lsof-4.78/00PORTING
/usr/share/doc/lsof-4.78/00QUICKSTART
/usr/share/doc/lsof-4.78/00README
/usr/share/doc/lsof-4.78/00TEST
/usr/share/doc/lsof-4.78/00XCONFIG
/usr/share/man/man8/lsof.8.gz

1

Ayrılan alanı gerçekten boşaltmak , dosya sistemi sürücüsüne bağlıdır ve bu, yalnızca bu dosyaya atıfta bulunan tüm dosya tanımlayıcıları serbest bırakıldığında gerçekleşir. Dolayısıyla, uygulamayı dosyayı kapatmazsanız, alanı gerçekten geri kazanamazsınız. Bu da, bir hata ayıklayıcısında onu sonlandırmak veya “biraz” oynatmak anlamına gelir (örn. Dosyayı kapatmak ve tekrar açılmadığından / tekrar açılmadığından emin olmak veya /dev/nullyerine açmak ). Ya da çekirdeği kesebilirsin ama buna karşı tavsiyem var.

Stephane'nin önerdiği gibi dosyayı kısaltmak yardımcı olabilir, ancak asıl sonuç dosya sisteminize de bağlı olacaktır (örneğin önceden tahsis edilmiş bloklar muhtemelen sadece dosyayı kapattıktan sonra serbest bırakılacaktır).

Bu davranışın arkasındaki mantık, çekirdeğin böyle bir dosyayı hedef alan veri talepleriyle (hem oku hem de yaz, ancak okuma aslında daha kritiktir) ne yapacağını bilmemesidir.


2
Linux çoğu dosya sistemindeki seyrek dosyaları desteklediğinden , davranışlar iyi tanımlanmıştır ve disk sürücüsü disk alanını gerçekten boşaltabilir. Ext3 ve ext4 için test ettim ve Stephane'un yazdığı gibi çalışıyor.
jofel

1
Bir dosyayı kesmenin önceden tahsis edilmiş blokları geri kazanmayacağını söyleyen nedir? Kısaltmak veriyi tahsis etmek içindir, bununla ilgili herhangi bir belirsizlik yoktur.
Stéphane Chazelas

1
Dosya sistemi daha sonra zaman kazanmak için tahsis edilmiş blokları (özellikle de dosya hala açıksa), özellikle de kesmeden önce yeterince büyük olduğunda, saklayabilir. En azından XFS öyle görünüyor.
Peterph

Teşekkürler Peter. Bu yazıdaki "neden" i belirttiğinize sevindim.
dotancohen

2
Söyleyebildiğim kadarıyla, açık dosyaların kesilmesi, XFS'de de alan kazanıyor. fallocateLinux 4.9 ile ayrılan normal dosya ve dosya ile test edilmiştir . Lütfen bir dosyayı kısaltmak için hangi dosya sistemini ve koşullarını alan kazanmadığını açıklayabilir misiniz?
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.