指定ブロックがどのファイルに属するか調べる
この記事では、ディスク上の指定のブロックがどのファイルに属するか調べる方法を説明します。主な目的は、ストレージに破損ブロックが生じたときに、どのファイルが破損したかを調べることです(そして重要なデータが失われたかどうかを確認できます)。
この記事の中のほとんどのコマンドを実行するには、root か、ディスクに直接読み込みアクセスができるユーザーになる必要があります(disk グループのメンバーであれば十分です)。いつもの通り、現在のバックアップを取っておくとよいでしょう。もうすぐディスクが壊れそうな場合は特にそうです。壊れそうかどうかを調べるには S.M.A.R.T. が役に立ちます。
今のところ、この記事は JFS と EXT ファイルシステムだけに向けて書かれています。
目次
破損ブロックを見つける
badblocks コマンドを使います。このコマンドにはいくつかのスキャンモードがあります。リードオンリーモード(デフォルト)は正確さが一番低くなります。破壊的書き込みモード(-w オプション)は最も正確ですが、より時間がかかり、(当然ながら)ディスク上の全データを破壊します。ですのでこれはブロックが属するファイルを見つけるのには使えません。そして最後に非破壊的読み書きモードがあります。これはおそらく破壊的モードと同じくらい正確で、唯一のデメリットはおそらく一番遅いことです。しかし、ディスクが壊れつつあるとわかっているときは、リードオンリーモードが一番安全でしょう。
次のいずれかのコマンドを実行し、-v オプション(冗長表示)つきでリードオンリースキャンを実行します(x はディスクを表す文字で、y はパーティション番号です)。
ディスク全体をスキャンする:
badblocks -v /dev/sdx
1個のパーティションをスキャンする:
badblocks -v /dev/sdxy
The downside to scanning the drive as a whole is that each filesystem is going to start its block count relative to the partition it's on. This means that if you have a bad block that happens to be on, let's say, the second partition, and that partition starts on block 1000, then you will have to subtract 1000 from your block number in order to get the number you want. So if a scan from the beginning of the disk results in block number 1005 being bad, then block 5 of the second partition is what you'll actually be using.
Otherwise, if you've found bad blocks after doing a full scan, you can simply figure out which partitions they're on, and rescan those in order to get the block number, rather than do any block math.
もう一つ覚えておきべきなのは、badblocks はデフォルトでは 1024 バイトを 1 ブロックとすることです。そのため、-b オプションでブロックサイズを変更してファイルシステムのブロックサイズに一致させるか、後の手順において手計算でブロック番号する必要があります。
パーティションの開始・終了位置を調べるには fdisk を使います(古いバージョンではデフォルトでシリンダー単位になるかもしれません。その場合は -u オプションでセクタ単位に変更できます)。fdisk で表示されるブロックサイズをメモしておいて、後でブロック数を変換できるようしておいてください。
fdisk -l /dev/sdx
255 heads, 63 sectors/track, 19457 cylinders, total 312581808 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00000000
これによって、破損ブロックのブロック番号(そのパーティションの開始位置からの相対位置)が分かりました。
ファイルシステムをデバッグする (JFS)
jfs_debugfs will give you access to all the low level structures within any JFS filesystem. Other filesystems such as the EXT filesystems have similar tools. It is probably a good idea to umount any filesystem before you run this on them. To use it just run:
jfs_debugfs /dev/sdxy
This puts you into a command console. The first thing you should note is your aggregate block size. This is (presumably) the block size the filesystem is using. JFS seems to default to 4096 bytes.
badblocks を実行したときのブロックサイズがこのファイルシステムのブロックサイズと一致していなかった場合は、ブロック番号を変換する必要があります(パーティションの開始位置からの相対ブロック番号を使うことに注意してください)。
つまり、ブロックサイズが 1024 バイトの場合のブロック番号 100 は、ブロックサイズが 4096 バイトの場合のブロック番号 25 になります。変換公式は:
(original block number) / ((filesystem block size) / (badblocks block size))
さて、本来の目的は inode 番号を取得することです。このコマンドを実行してください:
d blocknumber 0 i
この構文の意味は、d コマンドはディスプレイ、ブロック番号、オフセット(ここでは 0 にしている)、表示フォーマット i は inode となっています。
注意: ブロックが使用中でないと表示される場合は、そのブロックが割り当てられておらず、空きスペースになっていることを意味します。これは、何も重要なデータが失われていないということなので良いことです。
The decimal number that di_number is set to is the one we want. From here you type x to exit out of the display mode. Repeat the display command for each bad block that you have and note all of their inode numbers. For more info on the inode such as permissions and filetype type:
i inodenumber
When you have all the inode numbers type q to quit.
破損ファイルを見つける (JFS/Universal)
これでようやく破損ファイルを見つけられます。GNU find ユーティリティを使います。ファイルシステムをマウントして次を実行します:
find / -inum inodenumber
"/" はその inode が属するファイルシステムのマウントポイントで置き換えてください。 / を検索して 2 個以上のファイルシステムがマウントされていたら(普通はそうなっているでしょう)、異なるファイルシステム上で同じ inode 番号のファイルが複数見つかるでしょう。そしてその場合は明らかに時間が長くかかります。inode はファイルシステムの中でだけユニークなことに注意してください。
ファイルシステムをデバッグする (EXT(2/3/4))
tune2fs を使うと、各種 EXT ファイルシステム内の全ての低レベル構造にアクセスできます。これを行う前に全てのファイルシステムをアンマウントしておくとよいでしょう。
最初にやることは、ファイルシステムのブロックサイズを取得することです。これを実行します:
tune2fs -l /dev/sdxy | grep Block Block count: 29119820 Block size: 4096
この場合は 4096 がブロックサイズです(これがデフォルトのようです)。
badblocks を実行したときのブロックサイズがこのファイルシステムのブロックサイズと一致していなかった場合は、ブロック番号を変換する必要があります(パーティションの開始位置からの相対ブロック番号を使うことに注意してください)。
つまり、ブロックサイズが 1024 バイトの場合のブロック番号 100 は、ブロックサイズが 4096 バイトの場合のブロック番号 25 になります。変換公式は:
(original block number) / ((filesystem block size) / (badblocks block size))
さて、本来の目的は inode 番号を取得することです。このコマンドを実行してください:
debugfs
そして debugfs のコンソールにおいて、破損セクタを含んでいる EXT のパーティションを引数に open コマンドを実行します:
debugfs: open /dev/sdxy
最後に testb コマンドを実行してそのブロックに関する情報を取得します(この例ではブロック 1000 番):
debugfs: testb ブロック番号
注意: ブロックが使用中でないと表示される場合は、そのブロックが割り当てられておらず、空きスペースになっていることを意味します。これは、何も重要なデータが失われていないということなので良いことです。
ブロックが使用中なら、このコマンドで inode 番号を取得できます:
icheck ブロック番号
これは 2 個の数字を表示します。ブロック番号と inode 番号です。
破損ファイルを見つける (EXT(2/3/4))
inode 番号(icheck コマンドで表示される 2 番目の番号)を引数に ncheck コマンドを実行します:
ncheck inodenumber
この破損ブロックを使っているファイルのフルパスが表示されます。これで実際に何が破損したのかがわかります。
もし inode 番号が非常に小さくて ncheck がパス表示に失敗する場合は、おそらくジャーナル自体が壊れています。ジャーナルを削除するには、このコマンドをパーティションに対して実行します:
tune2fs -O ^has_journal /dev/sdxy
もう一度 debugfs コンソールでtestb コマンドを使ってそのブロックを調べると、もし本当にジャーナルに使われていたのであれば、今度は使われていると表示されないはずです。 次のコマンドで新しいジャーナルを構築します:
tune2fs -j /dev/sdxy
強制的に破損ブロックを再配置させる
First you'll want to see how many badblocks the harddrive is aware of through the smartctl command:
smartctl -t long /dev/sdx [wait until test completes, then] smartctl -l selftest /dev/sdx
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0 196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0 197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 0
To make the harddrive transparently map out the badblock with a spare good sector you will have to simply write zeros to the bad block using the dd command as root. Remember that with this command you have to work with the same block size as your filesystem and the block as to be relative to the partition the filesystem is on and NOT the harddrive as a whole:
dd if=/dev/zero of=/dev/sdxy bs=4096 count=1 seek=2269012 sync
You can see if the harddrive did indeed map out an additional bad sector by checking with the smartctl command and seeing if the reallocated sector or event count went up:
smartctl -A /dev/sdx ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 1 196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 1 197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 1
To get Offline_Uncorrectable to go back to 0 you need to run a SMART long test and a selftest:
smartctl -t long /dev/sdx [wait until test completes, then] smartctl -l selftest /dev/sdx