前ブログ、 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 件のコメント :
コメントを投稿