開いているが削除された大きなファイルを見つけて削除する


120

削除されたがアプリケーションでまだ開いている大きなファイルを見つけるにはどうすればよいですか?プロセスが開いている場合でも、このようなファイルを削除するにはどうすればよいですか?

状況は、ログファイルを非常に高速でいっぱいにするプロセスを実行していることです。理由はわかっていますが、修正できます。それまでは、プロセスをシャットダウンせずにログファイルをrmまたは空にしたいと思います。

単純に行うrm output.logと、ファイルへの参照のみが削除されますが、プロセスが終了するまでディスク上のスペースを占有し続けます。さらに悪いrmことに、ファイルの場所やサイズを見つける方法がなくなりました。ファイルが別のプロセスでまだ開いている場合でも、ファイルを見つけて空にする方法はありますか?

具体的には、DebianやRHELなどのLinuxベースのオペレーティングシステムを指します。


2
pidがわかっている場合は、使用lsof -p <pid>して、開いているファイルとそのサイズをリストできます。削除されたファイルには、その(deleted)隣にあります。削除されたファイルは/proc/<pid>/fd/1おそらくリンクされます。プロセスを終了せずにファイル記述子への書き込みを停止させる方法がわかりません。それはプロセスに依存すると思います。
歯磨きに成功した

ありがとう。rmまだ開いているすべてのedファイルのPIDを取得するにはどうすればよいですか?
dotancohen

@donothingsuccessfully lsofによって報告される「deleted」タグはSolaris固有であり、実際にはSolaris 10以降のみです。OPは、使用しているオペレーティングシステムを指定しませんでした。@dotancohen Solarisでは、lsofの出力をパイプして削除済みを検索できます(例:) lsof | grep "(deleted)"。削除されたファイルを開いたままにするプロセスがなくなると、カーネルはiノードとディスクブロックを解放します。プロセスには、開いている、本質的にロックされたファイルがディスクから削除されたことを通知できる「ハンドラ」がありません。
ヨハン

2
@ Johan、lsof | grep '(deleted)'Linux上でも動作します。Linuxでは、inotifyのメカニズム(IN_DELETE_SELFイベント)でファイル削除の(すでにもうは/ proc /一部-PID / FD以外の任意のディレクトリ内のエントリを持っていなくてもファイル)を通知することができます
ステファンChazelas

somefileVIMで作成して開きrm、別のbashプロセスで編集しました。次に実行するlsof | grep somefileと、ファイルがVIMで開いていてもそこにありません。
dotancohen

回答:


141

アプリケーションを強制終了できない場合は、ログファイルを削除する代わりに切り捨ててスペースを再利用できます。ファイルが追加モード(でO_APPEND)で開かれていなかった場合、ファイルは次にアプリケーションが書き込みを行う前と同じ大きさで表示されます(ただし、先頭部分はまばらで、NULバイトを含んでいるかのように見えます)再利用されます(ただし、スパースファイルをサポートしないApple OS / X上のHFS +ファイルシステムには適用されません)。

切り捨てるには:

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

Linuxで既に削除されている場合は、次のようにして切り捨てることができます。

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

どこに$pidファイルを持っているプロセスのプロセスIDが開かれ、$fd1つのファイルディスクリプタは、それはそれはあなたがしてチェックすることができた(下オープンしましたlsof -p "$pid"

pidがわからず、削除されたファイルを探している場合は、次のことができます。

lsof -nP | grep '(deleted)'

lsof -nP +L1@ user75021で述べたように、さらに優れた(より信頼性が高く、移植性の高い)オプション(1つ未満のリンクを持つファイルを一覧表示する)です。

または(Linuxの場合):

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

または、次のもので大きなものを見つけるにはzsh

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

別の方法として、アプリケーションが動的にリンクされている場合は、デバッガをアプリケーションにアタッチし、呼び出しのclose(fd)後にnewを続けopen("the-file", ....)ます。


1
truncate同じことをより明示的に行うコマンドもあります。
東武

1
@dotancohen Stephaneは、pidが不明な場合にこれを行う方法に関する情報を含めるように編集しました。
ディディコーエン

1
@OlivierDulacは、lsofおそらく、開いているファイルを一覧表示できるポータブルソリューションに最も近いものになるでしょう。アプリケーションの足元でfdを閉じるデバッガーアプローチも、非常に移植性が高いはずです。
ステファンシャゼル

2
@StephaneChazelas:ありがとう。:私は、各パーティション上のファイルをオープンしているすべてのPIDを一覧表示する方法を発見df -k | awk 'NR>1 { print $NF }' | xargs fuser -Vud (とFDを解放するためにそれらを強制的に犯罪者に信号を送ることが、その後は簡単)
オリヴィエ・デュラック

6
を使用することもできますlsof +L1。lsofのマニュアルページから:「フォーム+L1の指定は、+aL1 <file_system>リンク解除されたオープンファイルを選択します。フォームの指定は、指定されたファイルシステム上のリンクされていないオープンファイルを選択します。」それはgreppingよりも少し信頼できるはずです。
シンクロ14年

31

こちらのクイックスタートをご覧ください:lsofクイックスタート

lsofクイックスタートファイル(lsofに含まれる)について誰も言及していないことに驚いています。セクション「3.a」は、開いているリンクされていないファイルを見つける方法を示しています。

lsof -a +L1 *mountpoint*

例えば:

[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)

Red Hatシステムでは、クイックスタートファイルのローカルコピーを見つけるために、通常次のようにします。

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

...またはこれ:

[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

割り当てられたスペースを実際に解放するのはファイルシステムドライバー次第であり、通常、そのファイルを参照するすべてのファイル記述子が解放された後にのみ発生します。そのため、アプリケーションでファイルを閉じない限り、スペースを実際に再利用することはできません。これは、それを終了するか、デバッガーで「少し」再生することを意味します(たとえば、ファイルを閉じて、再び開いたり書き込んだりしないようにしたり、/dev/null代わりに開いたりします)。または、カーネルをハックすることもできますが、それはお勧めしません。

Stephaneが示唆するようにファイルを切り捨てることは役立つかもしれませんが、実際の結果はファイルシステムにも依存します(たとえば、事前に割り当てられたブロックは、いずれにしてもファイルを閉じた後にのみ解放される可能性があります)。

この動作の背後にある理論的根拠は、カーネルがそのようなファイルを対象とするデータ要求(読み取りと書き込みの両方ですが、実際には読み取りがより重要です)をどうするかを知らないことです。


2
Linuxはほとんどのファイルシステムでスパースファイルをサポートしているため、動作は明確に定義されており、ディスクドライバーは実際にディスク領域を解放できます。ext3とext4でテストしましたが、Stephaneが書いたように動作します。
ジョフェル

1
ファイルを切り捨てても、事前に割り当てられたブロックが再利用されないと言うことは何ですか?切り捨ては、データの割り当てを解除することを意味しますが、あいまいさはありません。
ステファンシャゼル

1
ファイルシステムは、特に時間を節約するために、特に切り捨てる前に十分な大きさの場合、時間を節約するためにブロックを割り当てたままにすることがあります。少なくとも、XFSはこれを実行しているようです。
ペテルフ

ピーターありがとう。この投稿で「なぜ」に対処してくださることをうれしく思います。
-dotancohen

2
私が知る限り、開いているファイルを切り捨てると、XFS上のスペースも再利用されます。通常のファイルとfallocateLinux 4.9で割り当てられたファイルの両方でテスト済み。ファイルを切り捨ててスペースを再利用しないファイルシステムと条件を明確にしてください。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.