ディスクとinodeの診断
目標
ディスク容量の問題をブロックとinodeの2つの軸に分けて見て、「削除したのに容量が減らない」状況を自分で作り、診断して復旧します。
なぜ重要なのか
No space left on deviceは、「ブロックがない」という意味ではなく、「カーネルがこの書き込みを受け入れるリソースがない」という意味です。そのリソースは、ブロックのことも、inodeのことも、root予約分を除いた空きのこともあります。そのためdf -hとdf -iを一緒に見る必要があり、dfとduが食い違ったら、削除されたが開いたままのファイルを疑う必要があります。特にステップ5–6で作る状況は、実務で最もよく出会う形です。そしてその状況でプロセスを再起動した瞬間に、復旧の機会も一緒に消えます。順序がそのまま実力です。
ステップ
/root/diskディレクトリで作業します。
/rootが属するファイルシステムのinode使用率(%)を、数字だけ/root/disk/inode_pct.txtに書いてください。/etcディレクトリの実使用量を、KB単位の数字だけ/root/disk/etc_kb.txtに書いてください。/usr/binの直下にある通常ファイルのうち、最も大きいもののファイル名を/root/disk/biggest.txtに書いてください。/root/disk/manyディレクトリを作成し、サイズ0のファイルをちょうど500個入れてください。そして、そのディレクトリのdu -skの値を/root/disk/many_kb.txtに書いてください。- 10MB以上の
/root/disk/ghost.logを作成し、あるプロセスがそのファイルを開き続けている状態で、ファイル名だけを削除してください。そのプロセスのPIDを/root/disk/ghost_pid.txtに書いてください。採点時点で、そのプロセスは生きている必要があります。 - ステップ5のプロセスが握っているそのファイルの内容を、
/root/disk/recovered.logに復旧してください。サイズが元のファイルと同じである必要があります。 /root/disk/findghosts.sh <최소바이트>を作成してください(プレースホルダーは最小バイト数です)。システム全体から、削除されたが開いたままのファイルのうち、そのサイズ以上のものを探し、pid=<PID> bytes=<크기>の形式で1行ずつ出力します(bytesの後ろのプレースホルダーはサイズです)。/root/disk/diskreport.sh <디렉터리>を作成してください(プレースホルダーはディレクトリです)。そのディレクトリの配下すべての通常ファイルの個数とバイト合計を、次の2行で出力します(プレースホルダーは、順に個数と合計です)。存在しないディレクトリなら、0以外のコードで終了する必要があります。files=<개수>bytes=<합계>
参考
readlink /proc/<PID>/fd/<N>で、fdが何を指しているかを確認できます。削除されたファイルには、後ろに(deleted)が付きます。stat -L -c %s /proc/<PID>/fd/<N>は、シンボリックリンクをたどって実際のサイズを教えてくれます。find "$d" -type f -printf '%s\n'でサイズの一覧を取得し、合計できます。- よくあるミス1: ステップ5でファイルを開いているプロセスが死ぬと、幽霊ファイルが消えて、ステップ6–7がすべて失敗します。
- よくあるミス2: ステップ7で
/proc/selfや採点ツール自身のfdまで数えないように注意してください。
inode使用率を読み取る
/rootが属するファイルシステムのinode使用率(%)を、数字だけ/root/disk/inode_pct.txtに書いてください。
dfには、ブロックではなくinodeを表示するオプションが別にあります。%記号は除いて、数字だけを書いてください。
ディレクトリの実使用量を測る
/etcディレクトリの実使用量を、KB単位の数字だけ/root/disk/etc_kb.txtに書いてください。
duはパスをたどりながら、実際に占有しているブロックを数えます。KB単位で集計してくれるオプションの組み合わせがあります。
一番大きいファイルを探す
/usr/binの直下にある通常ファイルのうち、最も大きいもののファイル名を/root/disk/biggest.txtに書いてください。
findの-printfでサイズと名前を一緒に取り出して、並べ替えてください。必要なのはパスではなく、ファイル名だけです。
空のファイルを500個作る
/root/disk/manyディレクトリを作成し、サイズ0のファイルをちょうど500個入れてください。そして、そのディレクトリのdu -skの値を/root/disk/many_kb.txtに書いてください。
ブレース展開やseqで一度に作れます。内容は0バイトなのに、duは0にならないことを確認してください。
削除されたが開いたままのファイルを作る
10MB以上の/root/disk/ghost.logを作成し、あるプロセスがそのファイルを開き続けている状態で、ファイル名だけを削除してください。そのプロセスのPIDを/root/disk/ghost_pid.txtに書いてください。採点時点で、そのプロセスは生きている必要があります。
ファイルを作り、あるプロセスに開き続けさせてから、名前だけを削除します。tail -fが適しています。
幽霊ファイルを復旧する
ステップ5のプロセスが握っているそのファイルの内容を、/root/disk/recovered.logに復旧してください。サイズが元のファイルと同じである必要があります。
/proc//fd/<番号>は、そのファイルを指すシンボリックリンクです。そのパスをそのままコピーしてください。
幽霊ファイルの検出スクリプト
/root/disk/findghosts.sh <최소바이트>を作成してください(プレースホルダーは最小バイト数です)。システム全体から、削除されたが開いたままのファイルのうち、そのサイズ以上のものを探し、pid=<PID> bytes=<크기>の形式で1行ずつ出力します(bytesの後ろのプレースホルダーはサイズです)。
/proc/*/fd/*をreadlinkして、(deleted)で終わるものだけを選びます。サイズはstat -Lで測ります。
再帰的な容量集計スクリプト
/root/disk/diskreport.sh <디렉터리>を作成してください(プレースホルダーはディレクトリです)。そのディレクトリの配下すべての通常ファイルの個数とバイト合計を、次の2行で出力します(プレースホルダーは、順に個数と合計です)。存在しないディレクトリなら、0以外のコードで終了する必要があります。
files=<개수>bytes=<합계>
findで通常ファイルを探し、個数とサイズの合計を求めます。存在しないディレクトリは、エラーとして処理してください。