前ブログ、 HDL-GS500が故障の続きです。
壊れたHDL-GS500のHDDを交換するために、新しいHDDを買いました。そのときの店員さんの話では、今販売しているHDDのほとんどがAdvanced Formatということでした。
今後、修理や交換のために入手できるHDDは、Advanced Formatの選択肢しか残らないようですね。
今回買ったのは、HITACHI HDS721010DLE630 1.0TB Advanced Formatです。
Advanced Format のHDDとは
近年に登場した4096バイト・セクターのHDDには、内部のファームウェアで、4096バイトの物理セクターを、512バイト単位の8個の論理セクターに分割するしくみ (512バイト・セクター・エミュレーション)をもったものがあります。これらのHDDは4kセクターHDDや、Advanced FormatのHDDと呼ばれています。
セクターサイズを512バイトから、4096バイトへ拡大する理由や課題について、以下に簡単に纏めてみました。詳細については後述する参考Webサイトを参照ください。
- HDDの大容量化に伴って、512バイト・セクターの抱える課題が顕著になってきた。
- ディスクの総容量に対するセクター・サイズとの比率が大きくなることで、エラー修正が煩雑になり効率が低下してしまう。
- 面密度の増加に伴って、1セクターあたりの表面積が縮小していくことになり、メディア欠損時のエラー修正がより困難になってきた。
- セクター・サイズの拡大による利点として、エラー修正機能の改善、フォーマット効率の向上が挙げられている。
-
512バイト・セクター・エミュレーション。
- 従来の512バイト・セクターを対象にした機器との互換を保ちながら、4096バイト・セクターへの移行をスムーズに進めるためのしくみ。
- HDD内部のファームウェアにより、4096バイトの物理セクターを、512バイト単位の8個の論理セクターに分割してデータ処理を行う。
- このしくみを使うことでPCから見たHDDは、今まで同様に512バイト・セクターのHDDように振る舞う。
-
ユーザー側で回避すべき重要な課題
- 512バイト・セクター・エミュレーションが、パフォーマンスに与える影響を最小限にするため、HDDへの書き込み時の、読み出し・修正・書き込みプロセスの発生頻度を最小限に抑えることが重要。
- ファイルシステムのデータ構造と、パーティションのアライメント・マッチングが必須。
- 適切なブロックサイズの選択が重要。
-
適切なパーティショニング・ツールの選択。
- 各パーティションの開始位置を、アライメント0の状態に設定できるツールを使用する。
- アライメント0の位置とは、セクター位置が8の倍数になる位置のことを言う。
(4096 バイト/セクター = 512 バイト/セクター × 8 ) - 従来のパーティショニング・ツールでは、シリンダ境界をパーティション境界に設定するようになっているので、そのまま使用するとアライメントがズレてしまうことになる。
この場合、デフォルトの操作単位を、シリンダーからセクターに変更する機能があれば、アライメント0のパーティションを作成できる場合がある。 - HDDの開始セクターの位置は、クロスプラットフォームの観点から見た場合は2048が無難。
Linuxでの、Advanced Formatの使用については、以下のWebサイトが参考になりました。
IBM developerWorks 4KB セクター・ディスクで Linux を使用する: 実用的なアドバイス
Seagate アドバンスド・フォーマット4Kセクター・ハードディスク・ドライブへの移行
HDL-GS500修復用HDDの、パーティショニングの考察
今回の修復作業におけるLinux使用時の注意点は、以下の内容が考えられます。
- HDDの開始セクター位置を 2048 に設定する。
- 各パーティションの開始位置を、アライメント0の状態にする。
- ただし、sda6のアライメントは調整しない。
- ファイルシステムのブロックサイズを、4096バイトにする。
このあたりを考慮しながら、進めていくことにしました。
先日確認したときの、壊れたHDDのパーティション構成は以下のようになっていました。
~# fdisk -l /dev/sda Disk /dev/sda: 500.1 GB, 500107862016 bytes 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 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: 0xee4739c6 Device Boot Start End Blocks Id System /dev/sda1 16065 642599 313267+ 83 Linux /dev/sda2 642600 1461914 409657+ 83 Linux /dev/sda3 1461915 5670944 2104515 82 Linux swap / Solaris /dev/sda4 5670945 976559219 485444137+ 5 Extended /dev/sda5 5670946 6088634 208844+ 83 Linux /dev/sda6 6088636 976559219 485235292 83 Linuxそれぞれのパーティション先頭セクターの値を、8の倍数に調整した結果、各パーティションの開始セクターの位置を以下の値に決めました。
- sda1の開始セクタ 2048、
- sda2の開始セクタ 628584、
- sda3の開始セクタ 1461912、
- sda5の開始セクタ 5670944、
拡張領域sda4の開始セクターはsda5の開始セクター-1としました。いまのところ、この領域の開始セクター位置も、アライメント0にする必要があるのかは良くわかっていません。入れ子になっている論理領域sda5やsda6の外側の領域なので、あまり影響が無いと考えています。
sda6の開始セクターは、今回のデータの修復のために、パーティション全体をコピーするので、あえて変更しないことにします。ここを変更するとセクター位置がズレてしまい、xfsファイルシステムにアクセスできなくなる心配があります。そのため、この部分のアライメントのズレはやむおえません。 データ修復後に改めて、sda6のアライメント調整をすることにしました。
初期化用シェルスクリプト tar2disk を利用する
先日USBメモリに保存することができた初期化シェルスクリプト、tar2diskの9行目の内容を、こちら のWebサイトの情報を元にして、
sddev=/dev/hdb を sddev=/dev/sda に。修正してtar2disk実行したところ、この新しいHDDのサイズを正常に1.0GBと認識して、初期化することができました。ただし、この時点では、まだアライメント調整はできていません。
次に、tar2diskで初期化した1.0TB HDDのマスターブートレコード(MBR)と、拡張パーティションブートレコード(Extended Partition Boot Record)を 調べてみました。
オリジナルの、HDDのパーティションと比べたところ、各パーティション開始セクターの位置が、両方とも同じでした。
さらに、初期化用シェルスクリプトtar2diskを調べてみると、各パーティションの先頭位置は、あらかじめ決められた値に固定されており。
cat /sys/block/$disk/sizeで、取得したHDDの総セクター数を元にして、拡張領域sda4のサイズと、論理領域sda5,sda6のサイズを計算しているようだ、ということがわかりました。
そこで、このシェルスクリプトを少し修正してみることにしました。修正点はパーティショニングと、ext3のブロックサイズの変更です。
disk2cyl( )を、HDDから取得した総セクター数を元にして、データ保存領域に使用するシリンダ数を計算している部分を、セクター数で返すようにに変更しました。
partition( )は、sfdiskコマンドを使い、一括してパーティショニングを行っています。この部分のシリンダ単位で指定している部分を、セクター単位で指定するように変更しました。
format( )は、 ext3のブロックサイズを4096バイトに修正しました。
現時点では、壊れた500GBのHDD修復が目的なので、sda6の開始セクター位置のアライメントを調整していません。これは、データの修復のためにパーティション全体をコピーする必要があるからです。 また、新しいHDDには1.0TBを使用していますが、修復の都合上HDDサイズを500GBで初期化するようにしています。
シェルスクリプト中の下に示す行は、初期化する環境に合わせて変更が必要です。
sddev=/dev/hdb # ##### 初期化する環境に合わせて変更してください #####例えば、初期化するHDDが/dev/sdaなら、sddev=/dev/sdaに変更します。
HDDサイズは500GBに固定、アライメント調整適用済みtar2disk 修復用暫定版、
#!/bin/sh # # tar2disk: tar ball をディスクに展開 # # usage: tar2disk sda # ##### 2012/10/01 sfdiskをシリンダ指定から、セクタ指定へ変更。##### mnt=./mnt sddev=/dev/hdb # ##### 初期化する環境に合わせて変更してください ##### PATH=$PATH:/sbin # # 16進->10進変換 # hex2dec() { expr 1 + `printf "%d" $1` } # # モデルごとの制限セクタ数 # sector160=`hex2dec 0x12A05FBF` sector250=`hex2dec 0x1D1A9C7F` sector300=`hex2dec 0x22ECB57F` sector320=`hex2dec 0x2540BF7F` sector400=`hex2dec 0x2E90F73F` sector500=`hex2dec 0x3A353900` sector750=`hex2dec 0x574FCD9F` sector1000=`hex2dec 0x74706DAF` #cyl_end=379 # sda5 の終了セクタ cyl_end=6088636 # ##### シリンダ値をセクタ値に変更 ##### # # ディスク名からモデルで丸められたセクタ数を得る # ##### 2012/10/01 セクタ数を返すように修正 ##### disk2cyl() { local disk=$1 #local sector=`cat /sys/block/$disk/size` local sector=976566529 # ##### 修復のため、HDDサイズを500GBに固定。 ##### if [ $sector -lt $sector160 ]; then echo -n error exit 1 elif [ $sector -lt $sector250 ]; then expr \( \( $sector160 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector300 ]; then expr \( \( $sector250 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector320 ]; then expr \( \( $sector300 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector400 ]; then expr \( \( $sector320 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector500 ]; then expr \( \( $sector400 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector750 ]; then expr \( \( $sector500 / 255 / 63 \) \* 16065 \) - $cyl_end elif [ $sector -lt $sector1000 ]; then expr \( \( $sector750 / 255 / 63 \) \* 16065 \) - $cyl_end else expr \( \( $sector1000 / 255 / 63 \) \* 16065 \) - $cyl_end fi return 0 } # # パーティションを切る # ##### 2012/10/01 シリンダ指定からセクタ指定へ変更 sda6の開始セクタは暫定値 ##### partition() { local disk=$1 local c5=417689 # ##### 26*255*63-1 ##### local cyl=`disk2cyl $disk` local ext=`expr $cyl + $c5 + 4` dd if=/dev/zero of=/dev/$disk bs=512 count=2 || exit 1 sfdisk -f -u S /dev/$disk <<EOF || exit 1 2048,626535,L 628584,833327,L 1461912,4209030,S 5670943,$ext,E 5670944,$c5,L 6088636,$cyl,L EOF } # # format # ##### 2012/10/01 ブロックサイズを4096バイトに変更。##### format() { local i=$1 if [ $i -eq 1 ]; then [ $flag_reset -eq 1 ] && return 0 mke2fs -b 4096 -j -m1 $sddev$i || return 1 elif [ $i -eq 2 ]; then mke2fs -b 4096 -j -m1 $sddev$i || return 1 elif [ $i -eq 5 ]; then mke2fs -b 4096 -j -N 100000 \ -O dir_index,filetype,sparse_super $sddev$i || return 1 else [ ! -f /sbin/mkfs.xfs ] && cp -a ${SCRIPT_PATH}/mkfs.xfs /sbin/ mkfs.xfs -f $sddev$i || return 1 fi return 0 } # # fw_install # fw_install() { touch verify_on_boot cp -a ../sd?.tgz ../tar2disk ./.landisk/ mkdir ./.landisk/mnt } # # 初期化後updateの為にflag fileをtouchする # set_reset_flag() { touch ./.landisk/reset_ok } # # ディスクを 0 クリアする # sanitize_disk() { local i=$1 echo "--- sanitize disk" dd if=/dev/zero of=$sddev$i bs=1M || return 1 } # # install_logを 作成する # set_install_log() { local end_time local j local mac_addr=`/sbin/ifconfig eth0 | sed -n 's/^.*HWaddr \([0-9A-F:]*\)[ ]*$/\1/p'` local log_dir="$mnt/factory_log" local install_log="$log_dir/install.log" mount ${sddev}5 $mnt || return 1 if [ ! -d $log_dir ]; then mkdir $log_dir || return 1 fi end_time=`date` echo "Mac Address: $mac_addr" > $install_log echo "Install Start: $START_TIME" >> $install_log echo "Install End: $end_time" >> $install_log for j in 1 2 3 4 5 6 7 8 9 10; do sync umount $mnt && break || sleep 1 done } # # factorylogの退避 # bk_factory_log() { local factory_tgz=$topdir/factory_log.tar.gz if [ ! -f $factory_tgz ]; then mount ${sddev}5 $mnt || return 1 tar cpzf $factory_tgz -C $mnt factory_log umount $mnt fi } # # factorylogの書き戻し # restore_factory_log() { local factory_tgz=$topdir/factory_log.tar.gz if [ -f $factory_tgz ]; then tar xpzf $factory_tgz echo `LANG=C date`: reset_script: >> factory_log/powerlog rm -f $factory_tgz fi } # # smartチェックを行う # smart_check() { local disk=$1 local RESULT_SMARTCTL=0 local RESULT_SMARTCTL_BIT0=0 local RESULT_SMARTCTL_BIT1=0 local RESULT_SMARTCTL_BIT2=0 local RESULT_SMARTCTL_BIT3=0 [ ! -f /usr/sbin/smartctl ] && cp -a ${SCRIPT_PATH}/smartctl /usr/sbin/ /usr/sbin/smartctl --smart=on --offlineauto=on --saveauto=on \ /dev/${disk} /usr/sbin/smartctl -a /dev/${disk} RESULT_SMARTCTL=$? RESULT_SMARTCTL_BIT0=$((${RESULT_SMARTCTL} & 1)) RESULT_SMARTCTL_BIT1=$((${RESULT_SMARTCTL} & 2)) RESULT_SMARTCTL_BIT2=$((${RESULT_SMARTCTL} & 4)) RESULT_SMARTCTL_BIT3=$((${RESULT_SMARTCTL} & 8)) if [ ${RESULT_SMARTCTL_BIT0} -ne 0 ]; then echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***" echo "*** COMMAND LINE PARSE ERROR ***" return 1 fi if [ ${RESULT_SMARTCTL_BIT1} -ne 0 ]; then echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***" echo "*** DEVICE OPEN FAILED ***" return 1 fi if [ ${RESULT_SMARTCTL_BIT2} -ne 0 ]; then echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***" echo "*** S.M.A.R.T. COMMAND FAILED ***" return 1 fi if [ ${RESULT_SMARTCTL_BIT3} -ne 0 ]; then echo "*** S.M.A.R.T ERROR DETECTED DISK=${disk} ***" echo "*** STATUS: DISK FAILING ***" return 1 fi return 0 } # # メイン # disk=$1 mode=$2 topdir=`pwd` if [ "$disk" = "" ]; then echo usage: tar2disk sda 1>&2 exit -1 fi if [ "x$mode" == "xreset" ]; then flag_install=0 flag_reset=1 flag_reset_full=0 elif [ "x$mode" == "xreset_full" ]; then flag_install=0 flag_reset=1 flag_reset_full=1 else flag_install=1 flag_reset=0 flag_reset_full=0 fi for i in 1 2 5 6; do umount $sddev$i done if [ $flag_install -eq 1 ]; then smart_check $disk || exit 1 partition $disk fi mkswap /dev/${disk}3 swapon /dev/${disk}3 trap "swapoff /dev/${disk}3" 0 for i in 1 2 5 6; do cd $topdir echo --- partitioning $i [ $i -eq 6 -a $flag_reset_full -eq 1 ] && sanitize_disk $i [ $i -eq 5 -a $flag_reset -eq 1 ] && bk_factory_log echo --- format partition format $i || exit 1 mount $sddev$i $mnt || exit 1 echo --- extracting tar ball cd $mnt || exit 1 tar zxf ../sd$i.tgz || exit 1 [ $i -eq 1 -a $flag_install -eq 1 ] && fw_install [ $i -eq 1 -a $flag_reset -eq 1 ] && set_reset_flag [ $i -eq 5 -a $flag_reset -eq 1 ] && restore_factory_log cd $topdir || exit 1 echo --- unmounting for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do sync umount $mnt && break || sleep 1 done [ "$?" -ne 0 ] && exit 1 done [ $flag_install -eq 1 ] && set_install_log exit 0
修正したシェルスクリプトを使って初期化した後のパーティション構成です。拡張領域sda4の、開始セクター位置のアライメントがズレているとメッセージが出ています。やっぱりここの位置合わせも行ったほうがいいのでしょうか?
root@Microknoppix:~# fdisk -l /dev/sda Disk /dev/sda: 1000.2 GB, 1000204886016 bytes 255 heads, 63 sectors/track, 121601 cylinders, total 1953525168 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sda1 2048 628582 313267+ 83 Linux /dev/sda2 628584 1461910 416663+ 83 Linux /dev/sda3 1461912 5670941 2104515 82 Linux swap / Solaris /dev/sda4 5670943 976559219 485444138+ 5 Extended Partition 4 does not start on physical sector boundary. /dev/sda5 5670944 6088632 208844+ 83 Linux /dev/sda6 6088636 976559219 485235292 83 Linux Partition 6 does not start on physical sector boundary.
さらに念のため、この1.0TB HDDのマスターブートレコード(MBR)と、拡張パーティションブートレコード(Extended Partition Boot Record)を調べてみました。
sda6の開始セクター位置を計算すると 5670943 + 417690 + 3 = 6088636 になるので、たぶんこれで大丈夫そうです。
この後、このHDDでHDL-GS500を組み立てなおし、正常に動作できることが確認できました。さらに一歩前進できました。
この後の計画
いろいろと試行錯誤しながらでしたが、前回計画したstep5まで、なんとか進めることができました。
この後、計画step6から、
GNU ddrescueを使って、壊れたHDDからデーターを救出。
へ続きます。
- 新HDDを取出し、旧HDDと共にPCへSATA接続。
- 旧HDDのsda6を、新HDDのsda6にコピーする。
- 新HDDで再組立て。
- HDL-GS500を起動して、保存しているデータのバックアップを取る。
0 件のコメント :
コメントを投稿