ハードウェアの認識と制御
DELL PowerEdge SC440 は、 インテル 82801GR I/O コントローラー・ハブ (ICH7R) を使っている。 ところが、ICH7 にあるはずの ウォッチドッグ・タイマ (Watchdog Timer) 機能が利用できない。 例えば Linux だとブート時に 「reboot disabled by hardware」すなわち 「ハードウェアによってリブートが禁止されている」とカーネル・ログに出力される:
iTCO_vendor_support: vendor-support=0 iTCO_wdt: Intel TCO WatchDog Timer Driver v1.02 (26-Jul-2007) iTCO_wdt: failed to reset NO_REBOOT flag, reboot disabled by hardware iTCO_wdt: No card detected
この「reboot disabled by hardware」とは何なのかを調べてみると、 Intel I/O Controller Hub 7 (ICH7) Family Datasheet の 78ページ、 Table 2-23. Functional Strap Definitions (Sheet 3 of 3) に、
| Signal | Usage | When Sampled | Comment |
|---|---|---|---|
| SPKR | No Reboot | Rising Edge of PWROK | The signal has a weak internal pull-down. If the signal is sampled high, this indicates that the system is strapped to the "No Reboot" mode (ICH7 will disable the TCO Timer system reboot feature). The status of this strap is readable via the NO REBOOT bit (Chipset Config Registers:Offset 3410h:bit 5). |
と書いてある。 つまり ICH7 の SPKR 端子 (Ball# A19) はスピーカ出力なのであるが、 入力端子としても使われていて、 PWROK 入力端子 (Ball# AA4) の立ち上がりエッジ時 (すなわち電源投入時) において SPKR 端子が H レベルであれば、 「No Reboot」モードに固定される。
「No Reboot」モードというのは、 TCO タイマ (つまり Watchdog Timer) による再起動を行なわないモードで、 通常はソフトウェアでこのモードの設定/解除が可能なのであるが、 SPKR 端子によって「固定される」と No Reboot モードのまま変更できなくなる。
具体的には、 「No Reboot」モードの設定/解除は、 ICH7 の「NO REBOOT bit」に 1/0 を書込むことによって行ない、 逆にこの「NO REBOOT bit」を読むことによって現在のモードを確認できる。 Linux カーネルの drivers/watchdog/iTCO_wdt.c に、 このビットを解除し、解除できたか確認するコードがある:
static int iTCO_wdt_unset_NO_REBOOT_bit(void)
{
...
/* Unset the NO_REBOOT bit: this enables reboots */
if (iTCO_wdt_private.iTCO_version == 2) {
val32 = readl(iTCO_wdt_private.gcs);
val32 &= 0xffffffdf;
writel(val32, iTCO_wdt_private.gcs);
val32 = readl(iTCO_wdt_private.gcs);
if (val32 & 0x00000020)
ret = -EIO;
...
return ret; /* returns: 0 = OK, -EIO = Error */
}
この iTCO_wdt_unset_NO_REBOOT_bit 関数は、 GCS (General Control and Status Register, オフセット 0x3410) のビット5 に 0 を書込むことによって No Reboot モードの解除を試み、 続いてこのビットを読んで正しく 0 に変わっているか確認し、 確認結果を返す。 つまりこの関数が正常に 0 を返せば、 ICH7 の Watchdog Timer が利用可能であることを示し、 -EIO を返せば、 (No Reboot モード固定なので) 利用不可能であることを示す。
というわけで、 DELL PowerEdge SC440 で Intel TCO Watchdog Timer が利用できない理由は、 電源投入時に SPKR 端子に電圧がかかってしまっていて、 No Reboot モード固定になっているためだろう。 SPKR 端子は内部的にプルダウン (20kΩ) されているので、 SPKR 端子につながっているスピーカを切り離せば SPKR 端子は L レベルになり、 Watchdog Timer が利用できるようになるはず。
続きを読むハードディスクが故障したので、RMA 手続きを行なった上でメーカへ送り返したら、わずか4日で代替品が返ってきた (6月28日)。 RMA++ と思っていたら、 10日後の 7月8日にシンガポールのフェデラル・エクスプレスから 「請求書在中」と書かれた AIR MAIL な封書が送られて来た。 え〜 せっかく RMA を誉め称えるブログを書いたのに、 今になって何か追加で請求されるとわ... orz と、 暗澹たる気持ちで開封してみると...
どきどきしながら「請求書 INVOICE」と書かれた一枚目の書類に目を通すと、 請求額は 1000円。 そんなに高額の請求ではなかったので一安心。 内訳を見ると、
| Other Charges | 消費税/付加価値税(Consumption Tax/VAT) | 500 |
| Other Charges | 関税・消費税特別手数料(D/T Advancement Fee) | 500 |
| 合計(Total) | 1,000 |
|---|
関税?
日本って工業製品に対して関税なんてかけていたっけ?
と思いつつ
二枚目の「輸入許可通知書」に目を通すと、
| 税科目 | 税額合計 | 個数 |
|---|---|---|
| D 関税 | ¥0 | 0 |
| F 消費税 | ¥400 | 1 |
| A 地方消費税 | ¥100 | 1 |
なるほど、 メーカが申告した価格 (CIF) $108.00 に対して約 5% の消費税がかかる、 ということで納税額が 500円なのか。 でも「関税・消費税特別手数料」って何なのだろう? 少なくともこの「輸入許可通知書」には「特別手数料」の文字は見当たらない。
まあ高々 1000円だから払っちゃおうか、という考えが頭をよぎる。 ご丁寧にコンビニ払いの用紙まで添付されている。 コンビニ払いか銀行振込を選択可能なようだ。
消費税ってのはいわゆる付加価値税のことである (なぜ VAT (= 付加価値税) という世界的に一般的な名称ではなく、 「消費税」という聞きなれない名称にしたのやら...)。 物品に価値が加わったときにその増分に対して一定割合 (現在は 5%) を納税するのが趣旨であるが、 故障したハードディスクを交換したことが「付加価値」に該当するのだろうか?
確かに私にとっては、 故障したハードディスクは価値ゼロで、 交換してもらったハードディスクは 13000円 (現時点での WD10EACS の小売価格) くらいの価値があるから一見価値が増えたように見えるが、 より厳密に考えると「故障したハードディスク」には「RMA 保証」がついていた (だからこそ交換してもらうことができた) ので、 13000円の価値があったと言ってもよい。
そもそも消費税は、このハードディスクを買ったときに支払っている。 当時は 28140円もしたから、なんと 1340円 (本体価格 26800円の 5%) も、 消費税を払っているわけである。 この上、さらに 500円も消費税を払わされてはかなわない。 これは同一物に対する二重課税ではないのか〜っ。 もんもんと考えているうちに、だんだんハラが立ってきた (^^;)。
というわけで、 なんとかこの理不尽な課税を回避できないか試みることにした。 もちろん、たかが 500円の課税であるので回避できたところで、 かけた労力に見合うわけはないのだが、 まあなにごとも経験である。 軽減できる税金は最大 500円であっても、 軽減交渉という経験はプライスレス。
続きを読む「故障した HDD WD10EACS を RMA (Return Merchandise Authorization, 返却承認) 手続きで交換してみた」で書いたように、 RMA 手続きを行なった上で Western Digital へ故障したハードディスク ドライブ (以下 HDD と略記) を送ったら、 激しく文字化けしたメールが送られてきた。
あとは HDD が送られてくるのを のんびり待つだけと思っていたら、 わずか一日後 6/26 18:44 に Western Digital からメールが来た。 しかし文字化けがひどくて読めない。 最初は何語で書いてあるかすら判然としなかったのだが、 どうやら Shift JIS で書かれた文面を quoted-printable エンコードする際に なにか問題があったようだ。 例えば 0x82 が「,」に、0x95 が「.」に置き換わってしまっている。 置換が規則的でないので、 暗号解読よろしく一文字一文字置き換え規則を推測していくしかない。
文面を再現するのに時間がかかりそうだなぁ〜と思っている間に、 交換品の HDD が届いてしまったので、 「暗号」解読するモチベーションを失ってしまっていたのだが、
Posted by 通りすがり 2008年07月02日 00:36
結局、メールにはなんて書いてあったのでしょうか?同ページ コメント欄 から引用
というコメントを頂いてしまったので、 暗号解読してみることにした。
以下、Western Digital からの文字化けメールを全文引用 (一部伏字) する:
From: "Western Digital RMA" <noreply@wdc.com>
To: <sengoku@gcd.org>
Date: Thu, 26 Jun 2008 02:44:25 -0700
MIME-Version: 1.0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
X-Mailer: Microsoft CDO for Windows 2000
Content-Class: urn:content-classes:message
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1896
X-OriginalArrivalTime: 26 Jun 2008 09:44:25.0728 (UTC) FILETIME=[3861F800:01C8D771]
HIROAKI SENGOKU -l,=D6=81A
^=C8?=BA,=C9.\Z=A6,=B3,=EA,=BD RMA =
,=CCfXfe=81[f^fX,=F0Sm"F,=B5,=C4,=AD,=BE,=B3,=A2=81B RMA
,=C9S=D6,=B7,=E9,=A8-=E2,=A2=8D?,=ED,=B9,=CD,=B1,=CCf=81=81[f<,=C9.=D4=90=
M,=B5,=C4,=AD,=BE,=B3,=A2=81B
=8F=EE.=F1,=AA=90=B3,=B5,=A2=8F=EA=8D?=81A,=B1,=CC"dZqf=81=81[f<,=C9,=CD.=
=D4=90M,=B5,=C8,=A2,=C5,=AD,=BE,=B3,=A2=81B
RMA "=D4=8D?=81F 8083XXXX
--------------------------------------------------------------
O=F0S=B7fhf?fCfu,=F0 5=81`7 ?c<=C6"=FA'?,=C9"=AD'-,=B5,=DC,=B7=81B
^=C8?=BA,=CCfhf?fCfu,=F0 Western Digital =
,=CDZ=F3-=CC,=B5,=DC,=B5,=BD=81F
fVfSfAf<"=D4=8D? =90=BB.i"=D4=8D? =
Z=F3-=CC"=FA=81iGMT=81j
------------ --------------- -------------
WCASJxxxxxxx WD10EACS-00ZJB0 6/25/2008
--------------------------------------------------------------
^=C8?=BA,=C9.\Z=A6,=B3,=EA,=BD RMA =
"=AD'-=8F=F3<=B5,=F0Sm"F,=B5,=C4,=AD,=BE,=B3,=A2=81B
-A'-<=C6Z=D2,=CCfVfXfef?,=CC=8DX=90V,=C91?c<=C6"=FA,=AA,=A9,=A9,=E8=81A,=BB=
,=CCO=E3"=AD'-'=C7=90=D5"=D4=8D?,=AA-LO=F8,=C9,=C8,=E8,=DC,=B7,=CC,=C5=81=
A,=B2-=B9=8F=B3,=AD,=BE,=B3,=A2=81B
O=F0S=B7fhf?fCfu,=CC'-.t=90=E6=81F
HIROAKI SENGOKU
XXXXXXXXXXXXXXXXXXXXXXXXX TAKATSU
KAWASAKI, Japan 213-XXXX
JAPAN
"z'-<=C6Z=D2=81F Fedex
"z'-'=C7=90=D5"=D4=8D?=81F XXXXXXXXXXXX
fVfSfAf<"=D4=8D? =90=BB.i"=D4=8D? =
"=AD'-"=FA=81iGMT=81j
------------ --------------- -------------
WCASJXXXXXXX WD10EACS-32ZJB0 6/26/2008
--------------------------------------------------------------
S=D6~AfSf"fN=81F
RMAZ=E8=8F?ZwZ=A6=8F=EE.=F1,=CC?{--/^=F3=8D=FC
- =
http://websupport.wdc.com/rd.asp?t=3D102&l=3Djp&p=3Dm&r=3D8083XXXX&f=3De
"=AD'-,=C6=8D=AB.=EF,=CC=8F=EE.=F1
- http://websupport.wdc.com/rd.asp?t=3D103&l=3Djp&p=3Drp
RMAfXfe=81[f^fX,=CC?{--
- =
http://websupport.wdc.com/rd.asp?t=3D104&l=3Djp&p=3Dv&r=3D8083XXXX&z=3D21=
3-XXXX
Western Digital fTf|=81[fgfz=81[f?fy=81[fW
- http://websupport.wdc.com/rd.asp?t=3D105&l=3Djp&p=3Dh
^=C8=8F=E3=81A
WD RMA f`=81[f?
http://websupport.wdc.com/rd.asp?t=3D105&l=3Djp&p=3Dh
ヘッダに「quoted-printable」と書いてあるとおり、 quoted-printable エンコーディングを行なったのだろうが、 のっけから「^=C8?=BA,=C9.\Z=A6,=B3,=EA,=BD」となっていて、 一体何語なんだ?と思わせる始まり方である。
ちなみに quoted-printable というのは 8bit データを、 「印字可能 (printable)」つまり 7bit の英数字・記号だけで表現するための方法 (エンコーディング) で、 印字可能でない 8bit データは 16進数で表わして前に「=」をつける (「=」自身は「=3D」で表現する)。 例えば「^=C8?=BA,=C9.\Z=A6,=B3,=EA,=BD」は、 16進数で書くと 「5E C8 3F BA 2C C9 2E 5C 5A A6 2C B3 2C EA 2C BD」 という 8bit データ列を意味する。
腕に覚えのあるかたは、解答を見ずに解読を試みてはいかがだろうか?
続きを読む廉価な 1TB SATA ハードディスク ドライブ (以下 HDD と略記) として有名な、 Western Digital 製 WD Caviar GP WD10EACS は、 省電力・静音を謳っている。 環境に優しいのは結構なことだが、 その実現方法:
IntelliPower - きめ細かく調整された ディスク回転速度 転送速度 及びキャッシュサイズの調和により飛躍的な省電力と確実なパフォーマンスを提供します
IntelliPark - 風損を減らす為のアイドル時の自動ヘッド退避によりドライブは消費電力を低減する
IntelliSeek - 電力消費量、ノイズおよび振動を低減させるために、最適なシーク速度を計算します。
GreenPower ハードドライブ から引用
のうち、特に「アイドル時の自動ヘッド退避」というのがいただけない。 ヘッドを退避すれば空気抵抗が減ってモーターの負荷が減るから 低消費電力が実現できる (実際、アイドル時の消費電力は際立って低い)、 ということなのだろうが、 常時使用する PC (特にサーバ) だと「自動ヘッド退避」の回数が とんでもないことになる。 SMART 情報を見ると:
# smartctl -a /dev/sdb smartctl version 5.37 [i686-pc-linux-gnu] Copyright (C) 2002-6 Bruce Allen Home page is http://smartmontools.sourceforge.net/ === START OF INFORMATION SECTION === Device Model: WDC WD10EACS-00ZJB0 Serial Number: WD-WCASJxxxxxxx Firmware Version: 01.01B01 User Capacity: 1,000,204,886,016 bytes ... Vendor Specific SMART Attributes with Thresholds: ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED RAW_VALUE ... 9 Power_On_Hours 0x0032 095 095 000 Old_age Always 3826 12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always 24 192 Power-Off_Retract_Count 0x0032 200 200 000 Old_age Always 19 193 Load_Cycle_Count 0x0032 197 197 000 Old_age Always 11327 ...
わずか 3826 時間 (159日、約5ヶ月) で、 実に 11327回もの自動ヘッド退避が行なわれている。
この異常な回数の自動ヘッド退避が原因かどうかは分からないが、 この 1TB HDD は 2007年11月30日に 28140円で購入してから わずか 5ヶ月余りの 2008年5月2日に故障した。 こんなに早く故障するとは思ってもいなかったので、 T-Zone の延長保証 (200円の追加で通常3ヶ月保証を最長6ヵ月保証) を掛けていなかった。 6ヶ月ではどーせ故障しないから保証を掛けるだけ無駄と判断したのだった (ついでに言うと、6ヶ月では故障しないだろうと高を括っていて、 まだ一部バックアップしていないデータがあったので、 復旧にえらく手間取った。1TB もあると復旧も一筋縄にはいかない)。
運が悪かったとあきらめるしかない (二度とグリーン・パワー・ハードディスクは買わないぞっ!) と思っていたら、 RMA (Return Merchandise Authorization, 返却承認) という メーカによる保証があるということを同僚から教えてもらった (社内IRC で HDD の故障を嘆いていたら、哀れに思って教えてくれたらしい ^^;)。 RMA番号を取得した上で故障品をメーカへ送ると、 代替品を送り返してくれる、という保証。
ステップ3
製品が故障していて交換が必要と判断された場合、 RMA タイプを下から選択して RMA(返却承認)手続きを開始してください。
Standard Replacement
お客様から故障製品を受け取ったあとに代替製品を送付します。 RMA が作成されてから30日以内に故障製品を返送してください。エンドユーザー向け製品交換 から引用
Western Digital の エンドユーザー向け保証確認ページで、 故障した HDD のシリアル番号を入力してみると、
おお、「限定保証期間内」と表示された。 有効期間は再来年の 12月まで、三年間もあるらしい。 もしかしたら交換してもらえるかも?と期待が膨らむ。 といっても RMA なんて今まであることすら知らなかったわけで、 どうやって故障品を送ったらいいのか見当もつかない。
続きを読む「ハードウェア・ウォッチドッグ・タイマー iTCO_wdt のススメ」へのリンクを張って頂いた:
HP ML115 には IPMI (Intelligent Platform Management Interface) という 便利なインターフェイスが内蔵されています。 ... (中略) ... IPMI 機能の一つ、watchdog timer 機能を利用してみようと思います。
... (中略) ...
watchdog timer の動作に関しては、 こちらの方が 詳しいので興味ある方はご確認ください。 さて、どうやって watchdog を起こすかというと、 先ほどインストールしたドライバと ipmitool を利用します。
うっ、ML115 の IPMI には、 ウォッチドッグ・タイマーの機能もあったのか (何たる不覚 orz)。 今まで ML115 では、 ソフトウェア版ウォッチドッグ (softdog.ko モジュール) を 使っていたので、 速攻で IPMI のハードウェア・ウォッチドッグ・タイマーに乗り換えてみた。
Linux カーネル・ソースの Documentation/IPMI.txt を見ると、
A watchdog timer is provided that implements the Linux-standard
watchdog timer interface. It has three module parameters that can be
used to control it:
modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
preaction=<preaction type> preop=<preop type> start_now=x
nowayout=x ifnum_to_use=n
ブート時に「modprobe ipmi_watchdog」を実行するだけで使えそうである。 タイムアウトを「timeout=<t>」で指定できるが、 私のマシンでは「蹴り代行」デーモンを走らせている (「ハードウェア・ウォッチドッグ・タイマー iTCO_wdt のススメ」参照) ので、 デフォルトのタイムアウトである 10 秒のままでも問題無い。
「action=<action type>」には、タイムアウト時の挙動を指定する。 「reset」(ハードウェア・リセット)、 「power_cycle」(電源OFF してから電源ON)、 「power_off」(電源OFF) を指定できるが、 デフォルトは「reset」なので、これも指定しなくて構わない。
「nowayout=0」を指定すると、 /dev/watchdog をクローズ時にウォッチドッグ・タイマーが止まる。 ウォッチドッグ・タイマーは、 いったん動き出したら何が起ろうと止めるべきではないと思うし、 デフォルトは「nowayout=1」(つまりクローズしても止まらない) なので、 これも指定する必要はない。
というわけで、ipmi_watchdog を使ってみる:
# modprobe ipmi_watchdog # echo @ > /dev/watchdog
/dev/watchdog が存在しない場合は、「mknod /dev/watchdog c 10 130」を実行して、 /dev/watchdog を作成しておく。
10秒後、勝手にリセットがかかった (めでたしめでたし)。 リセットを防ぐには 10秒以内に /dev/watchdog へ書込み続けなければならない。 例えば、
#!/bin/sh
while true; do
echo @ > /dev/watchdog
sleep 5
done
といったスクリプトを走らせ続ける。 このスクリプトだとシンプルすぎて、 システムに異常が起きたときも動き続けてしまう (だからタイムアウトが発生しない) 恐れがあるので、 while ループの中にシステム異常を検知する (異常が起きたときは 10秒以上時間がかかる) ようなコマンドを入れておくとよい。
何かの都合でタイマーを止めたい (止めるべきではないが) ときは、 「V」を /dev/watchdog に書込む。
64bit Linux (x86_64 別名 amd64) は、 CONFIG_IA32_EMULATION を有効にしておくことにより、 32bit プログラム (i386 別名 ia32) を走らせることができる。 したがって 64bit へ移行する際は、 全プログラムを一度に 64bit 化する必要はなく、 まずカーネルだけ 64bit 化しておいて、 各プログラムは (バージョンアップの機会などに) 徐々に 64bit 化していけばよい。 ただし 32bit プログラムがカーネルの機能を呼び出す場合は、 各機能それぞれが 32bit プログラムからの呼び出しに対応していることが前提となる。
32bit プログラムからの呼び出しに対応するといっても、 基本的には引数の型を変換するだけである。 x86_64 の整数データモデルは LP64、 つまり long int 型とポインタ型が 64bit で (引数の型として多用される) int型は 32bit のままなので、 変換が不要なケースも多い。
例えば ioctl システムコールはファイル・ディスクリプタ (file descriptor, 以下 fd と略記) ごとに カーネルが実行すべき機能は変わってくるわけで、 その実装は各デバイス・ドライバに委ねられることが多い。 したがって 32bit プログラムからの ioctl 呼び出しに応えられるか否かは、 各ドライバが 32bit 対応しているか否かに依存する。 不幸にしてドライバが対応していない場合は、
ioctl32(tv:11028): Unknown cmd fd(5) cmd(40045613){t:'V';sz:4} arg(081ec8b4) on /dev/video0
などといったカーネル・メッセージ (dmesg) が出力される。 このメッセージは、 カーネル・ソース中 fs/compat_ioctl.c の compat_ioctl_error が出力している:
static void compat_ioctl_error(struct file *filp, unsigned int fd,
unsigned int cmd, unsigned long arg)
{
...
compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
"cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n",
current->comm, current->pid,
(int)fd, (unsigned int)cmd, buf,
(cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK,
(unsigned int)arg, fn);
...
}
fs/compat_ioctl.c は 32bit 版 ioctl システムコールを実装していて、 32bit プログラムが ioctl システムコールを呼び出すと、 この中の compat_sys_ioctl ルーチンが呼ばれる:
asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
unsigned long arg)
{
...
if (filp->f_op && filp->f_op->compat_ioctl) {
error = filp->f_op->compat_ioctl(filp, cmd, arg);
if (error != -ENOIOCTLCMD)
goto out_fput;
}
...
compat_ioctl_error(filp, fd, cmd, arg);
...
out_fput:
fput_light(filp, fput_needed);
out:
return error;
}
つまりドライバ側で file 構造体の compat_ioctl 関数ポインタ (filp->f_op->compat_ioctl) が定義されていればそれが呼ばれ、 未定義ならば上記のような「Unknown cmd」エラーが出力される。
ちなみにこのエラーメッセージの「tv:11028」は、 ioctl を呼び出した 32bit プロセスの名前 (コマンド名) とプロセスID であり、 fd(5), cmd(40045613), arg(081ec8b4) は、 それぞれ ioctl システムコールの第一 (つまり fd 番号)、 第二 (ioctl リクエスト番号)、第三引数 (ioctl リクエストの引数) であり、 最後の on /dev/video0 は (第一引数の) fd 番号に対応するファイルのパス名である。
そして、この tv コマンドは 「ビデオキャプチャ・カード GV-MVP/RX2W を使って Linux 2.6.24.4 でテレビ録画」で紹介した perl スクリプト であり、 その名称から推測できるとおりテレビ録画を行なうためのスクリプトである。
このスクリプトでは Video::ivtv モジュールを利用していて、 このモジュールが /dev/video0 つまり TV キャプチャ・デバイスに対して、 ioctl システムコールを呼び出している。 上記エラーはスクリプト中 $IvTV->stopEncoding($TunerFD); を実行したときに発生した。
その名称から推測できる通り、 stopEncoding メソッドはキャプチャ・デバイスに対して エンコーディングの停止を指示するためのもので、 内部で ioctl(fd, VIDIOC_STREAMOFF) などと ioctl 呼び出しを行なっている。 VIDIOC_STREAMOFF は videodev2.h にて、
#define VIDIOC_STREAMOFF _IOW ('V', 19, int)
と定義されていて、このマクロを展開すると 40045613 (16進) となり、 上記カーネル・メッセージ「cmd(40045613)」と一致する。
というわけで、(少なくとも Linux 2.6.24.7 に含まれる) ivtv ドライバは、 残念ながら 32bit 対応していないことが分かった。 もちろん x86_64 なカーネルではなく、 i386 カーネルを使えば 32bit プログラムから ivtv ドライバを使うことができるが、 x86_64 なカーネルでは、32bit プログラムからの ioctl システムコールを 64bit カーネルが受付けられる形に変換できないということだ。
とはいうものの、 32bit だろうが 64bit だろうが ioctl のインタフェースに大した変わりはないはずだ。 どうして ivtv ドライバは 32bit 呼び出しをサポートしていないのだろう? と 思いながらドライバのソースを眺めていると... drivers/media/video/compat_ioctl32.c を見つけた。 名前からしていかにも 32bit 版 ioctl のように見える。
compat_ioctl32.c の中の v4l_compat_ioctl32 ルーチンは、 32bit な ioctl 呼び出しを受付けて 引数を 64bit へ変換し (といっても int 型はどちらも 32bit だが)、 本来の (64bit な) ioctl を呼び出し直す仕組みになっている。 なぜ ivtv ドライバは、このルーチンを利用していないのだろうか。
static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
...
/* First, convert the command. */
switch(cmd) {
...
case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
};
switch(cmd) {
...
case VIDIOC_STREAMOFF:
err = get_user(karg.vx, (u32 __user *)up);
compatible_arg = 1;
break;
...
};
if(err)
goto out;
if(compatible_arg)
err = native_ioctl(file, realcmd, (unsigned long)up);
else {
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
err = native_ioctl(file, realcmd, (unsigned long) &karg);
set_fs(old_fs);
}
...
return err;
}
long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
...
ret = do_video_ioctl(file, cmd, arg);
break;
...
return ret;
}
ざっと見た感じ、 ivtv ドライバからこの v4l_compat_ioctl32 ルーチンを呼んでも 特に問題は無いように思われる。
そこで、ivtv ドライバの file 構造体 (の中の file_operations 構造体) の compat_ioctl 関数ポインタに、 v4l_compat_ioctl32 を設定してみた。
--- linux-2.6.24.5.org/drivers/media/video/ivtv/ivtv-streams.c 2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24.5/drivers/media/video/ivtv/ivtv-streams.c 2008-05-04 09:10:07.581416212 +0900
@@ -49,6 +49,7 @@
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.ioctl = ivtv_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
};
@@ -59,6 +60,7 @@
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.ioctl = ivtv_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_dec_poll,
};
このパッチをあてることにより、 x86_64 なカーネル上で i386 な Video::ivtv モジュールを使って、 ビデオキャプチャ・カード GV-MVP/RX2W を コントロールすることができるようになった。 一週間ほど使ってみた (多数の TV 番組を予約録画した) が、 今のところ問題は起きていない。
ついに Linux 2.6.24 で I-O DATA 製 ハードウェア MPEG-2 エンコーダ搭載TVキャプチャボード GV-MVP/RX2W (2006年7月5日生産終了) が標準カーネルのままでテレビ視聴が可能になった。 もはやカーネルのバージョンを上げるたびにパッチを当て直す必要はない。 仕様が公開されていないハードウェアを解析してドライバを開発し、 それを標準カーネルにマージすべく働き掛けた方々の努力に敬意を表したい。
この TVキャプチャボードのおかげで、 私はリアルタイムでテレビを視聴する習慣を無くすことができた。 録画したものを見れば「飛ばし読み」や「斜め読み」が可能だし、 1TB のディスクに録りだめしておいて優先順位をつけて見ることもできる。 ニュースやスポーツ以外であれば放送日に見る必要はそもそもないし、 下らないと判明した時点で視聴を打ち切って 別の録画した番組を見るようにすれば、 駄作をだらだらと見続けて時間を無駄にすることもない。
この手のハードウェアは、 Linux などのオープンソースな OS で動いてこそ真価を発揮するのだと思う。 視聴方法は人によって様々であるから、 全てのユーザニーズを満たすような万能なソフトウェアを、 ハードウェアメーカが製品出荷時に開発することなど、 そもそも無理な話ではないのか?
ハードウェアメーカはドライバ (あるいはハードウェア仕様) の公開だけにとどめ、 ソフトウェアの開発は他者に任せてはどうか。 餅は餅屋というではないか。 一つの万能ソフトウェアより、 ニーズに応じて単機能なソフトウェアを使い分ける方が合理的だし、 さらに言えばどんな OS 上でそのソフトウェアが動いて欲しいかは、 ユーザによって異なるだろう。
例えば私の場合、 24時間365日、安定して録画し続けることが最優先であるし、 「使い易い」グラフィカルなユーザインタフェースよりは、 perl スクリプトから 自由にコントロールできることのほうが重要である。 私もノートPC では Windows VISTA を使用しているが、 録画サーバの OS に Windows を使う気にはなれない。
GV-MVP/RX2W は生産終了になって久しく、 後継の GV-MVP/RX3 や GV-MVP/GX2W はまだ Linux では使えないらしい (はたして地上アナログ停波までに使えるようになるだろうか?)。 I/Oデータの製品は Linux で使えないことが多いので注意が必要だろう。 Windows のみ対応しているハードウェア製品だと、 サポートが打ち切られて Windows の新 OS に対応しなくなった段階で、 使うことができなくなってしまう (サポート終了を理由に VISTA 対応版を出していないハードウェア製品は多い)。 もっとも、メーカ側からすると早く使えなくして、 新製品に買い換えてもらいたいのだろうが。
なお冒頭で「パッチを当て直す必要はない」と書いたが、 GV-MVP/RX2W には DeEmphasis (DEM) モードを設定すると常にモノラル音声になるという問題がある。 標準カーネルでは DEM ON がデフォルトになっているので、 Linux 2.6.24.4 に以下のパッチをあてて、 DEM OFF をデフォルトにしてみた。 このパッチをあてることにより、 デフォルトで二か国語/ステレオ放送の録画ができるようになる。
--- linux-2.6.24.4.org/drivers/media/video/tda9887.c 2008-01-25 07:58:37.000000000 +0900 +++ linux-2.6.24.4/drivers/media/video/tda9887.c 2008-04-13 11:41:30.232518786 +0900 @@ -227,8 +227,7 @@ .name = "NTSC-M-JP", .b = ( cNegativeFmTV | cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | + .c = ( cDeemphasisOFF | cTopDefault), .e = ( cGating_36 | cAudioIF_4_5 |
HP と DELL がエントリ・サーバ (タワー型) のキャンペーン販売を行なっていたので、 試しに買ってみた。 どちらも 2万円以下。
| HP ProLiant ML115 | DELL PowerEdge SC440 | |
|---|---|---|
| 価格 | 15,750円 (21,000円割引) | 19,800円 (46,875円割引) |
| プロセッサ | AMD Athlon 3500+ | Pentium Dual-Core E2180 |
| チップセット | nVidia MCP55S Pro | Intel 3000 |
| グラフィック | Matrox G200e (ServerEngines) | ATI ES1000 |
| メモリ | PC2-5300 ECC Unbuffered DDR2 SDRAM 512MB | |
| HDD | 80GB SATA 7200rpm | |
| 光学ドライブ | TSSTcorp CD-ROM TS-H192C | TSSTcorp DVD-ROM TS-H352C |
PowerEdge というと (ラック・マウント型の) 爆音サーバのイメージが強かったので、 自宅で 24時間通電は難しいのではないかと思っていたのだが、 普通のデスクトップPC 並に静かで驚いた。 ProLiant のほうは、爆音というほどではないがそれなりにファンの音がする。
ProLiant ML115 は、 ビデオ・メモリが 2MB しかなくて画面の解像度の限界が 1024x768 16bit だったり、 光学ドライブが DVD でなかったり、 PCI が 3.3V 専用だったりと、 デスクトップPC として使うには少々難がある (もちろんサーバとして使う場合は問題無い)。
それに比べると PowerEdge SC440 は、 デスクトップPC としても使える。 手持ちのサウンド・カード Vortex2 SQ2500 (5V PCI なので ProLiant ML115 では使用不可) を差して Ubuntu をインストールしてみた。 ただし、DRI (Direct Rendering Infrastructure) は使えないので、 ビデオ再生などには向かない。
また、PowerEdge SC440 は ECC 付メモリしか使えないので、 安価なメモリを使いたい場合は不便。 一方 ProLiant ML115 はECC 無しメモリも利用できるので、 私は ProLiant ML115 の 512MB ECC 付 DDR2/667 メモリを PowerEdge SC440 へ移し、 ProLiant ML115 には、 4800円で購入した KINGBOX 1GB ECC 無し DDR2/800 2枚組を差して使っている。
「1/9 以降、Windows VISTA 搭載 レッツノートのハードディスクが突然死する可能性がある」問題を解決するための BIOS が公開された。
レッツノート (1/21):
本BIOSの導入によって現象を回避することが可能ですが、 詳細が判明次第、弊社Webサイトにてご報告いたしますので、 引き続き弊社Webサイトからお知らせを覧いただきますようお願いします。
ただし、本現象がすでに発生している場合は、 対策のBIOSアップデートプログラムを導入できません。
大変お手数ですが、下記の修理相談窓口に修理のご相談をお願いします。
Lenovo ThinkPad (1/15):
注意:Windows Vistaを使用しているシステムで、 電源投入時に"2100: Initialization error on HDD0 (Main hard disk drive)"と 表示され、 HDDから起動できなくなることがある問題を修正しました。
レッツノートの BIOS アップデートは Windows 上から実行する必要があるので、 「本現象がすでに発生している場合は」、 まず「Windows VISTA 用の更新プログラム KB943899 が原因で突然死したハードディスクを復旧させる方法」などを用いてハードディスクをスピン・アップさせ、 Windows を正常起動させておく必要がある。 「修理相談窓口に修理のご相談を」するのは「大変お手数」なので、 ハードディスク以外の方法 (USB メモリからの起動など) で 起動する手段を提供すべきだと思うのだが...
さっそくレッツノートで BIOS アップデートを行なってみた。
試しに、 ハードディスクを故意に Power-Up In Standby 状態にしてみる。 すなわち、 「Windows VISTA 用の更新プログラム KB943899 が原因で突然死したハードディスクを復旧させる方法」 の 「お手軽パック」などを使って Linux を起動し、 hdparm コマンドを使って Power-Up In Standby 状態にしてみる:
# mount -t vfat /dev/sdb1 /mnt # /mnt/hdparm -s1 /dev/sda /dev/sda: Use of -s1 is VERY DANGEROUS. This requires BIOS and kernel support to recognize/boot the drive. Please supply the --yes-i-know-what-i-am-doing flag if you really want this Program aborted #
おお、fool proof 機能付とは、なかなか親切なコマンドだ。 とても危険なので、 「何をしようとしているか分かっている」場合のみ、 「--yes-i-know-what-i-am-doing」オプションを付けて再実行する:
# /mnt/hdparm -s1 --yes-i-know-what-i-am-doing /dev/sda
/dev/sda:
setting power-up in standby to 1 (on)
# /mnt/hdparm -I /dev/sda | grep Power-Up
* Power-Up In Standby feature set
#
これで、ハードディスクが Power-Up In Standby 状態になった。 つまり電源投入時にスタンバイ・モードに入り、 明示的に spin up 命令を送らない限りは回転を始めない。 だから、 レッツノートの以前の BIOS ではハードディスクを認識できず起動に失敗していた。
Ctrl-Alt-Del を押して再起動すると、 ハードディスクから正常にブートした。 再び「お手軽パック」を使って Linux を起動し、 ハードディスクの状態を確認してみる:
# /mnt/hdparm -I /dev/sda | grep Power-Up
Power-Up In Standby feature set
#
Power-Up In Standby 機能が無効になっていた。 新しい BIOS は、 ハードディスクに spin up 命令を送るだけでなく、 Power-Up In Standby 機能を無効にする命令も送っているようだ。
昨日書いた
「1/9 以降、Windows VISTA 搭載 レッツノートのハードディスクが突然死する可能性がある
」を大変多くの方に読んで頂けた。
頂いたコメントで目立ったのが、
復旧方法が万人向けではない、という点。
確かに Linux 2.6.22 以上の LiveCD を自前で調達しなければならないというのは、
よほど普段から Linux を使いこなしていない限りは難しいだろう。
というわけで、 突然死したハードディスクを復旧させる「お手軽パック」を作ってみた。 もちろん無保証である。 いかなる損害が発生しても私は何の責任も負えない、 ということに同意して頂けるかたのみに対して使用を許諾する。
まず、この zip アーカイブ をダウンロードして、 USB メモリへ展開する。 以下の例では USB メモリが「ドライブ D」になっているが、 実際の USB メモリのドライブ名で読み替えて欲しい。
D:\>dir
ドライブ D のボリューム ラベルがありません。
ボリューム シリアル番号は 0000-0000 です
D:\ のディレクトリ
2007/07/16 08:49 23,040 syslinux.exe
2008/01/18 07:33 537,844 hdparm
2007/12/25 08:07 2,411,333 initz
2007/12/24 09:50 1,423,768 linuz
2008/01/18 08:18 58 syslinux.cfg
5 個のファイル 4,396,043 バイト
0 個のディレクトリ 510,672,896 バイトの空き領域
D:\>
Windows のコマンド プロンプト にて、 D:\syslinux.exe を以下のように実行する。 もちろん、引数の「D:」は USB メモリのドライブ名で読み替える。
D:\>syslinux.exe -ma D: D:\>
これで Linux 2.6.23.12 がブート可能な USB メモリができた。 このメモリをレッツノートに差して起動する。 BIOS 設定で USB から起動可能にしておくのを忘れずに。
ハードディスクが回転しないのであるから、 以下のメッセージが表示されて止まってしまうが、
Phoenix TrustedCore(tm) NB Copyright 1985-2004 Phoenix Technologies Ltd. All Rights Reserved Copyright (C) Matsushita Electric Industrial Co.,Ltd. 2007 BIOS Version 1.00-L13 CPU = 1 Processors Detected, Cores per Processor = 2 Intel(R) Core(TM) Duo CPU U2400 @ 1.06GHz 2048MシステムRAMテスト完了。 システムBIOSがシャドウされました。 ビデオBIOSがシャドウされました。 ハードディスク0: マウスが初期化されました。 エラー 0200: ハードディスクエラーです。 0 <F2>キーを押すとセットアップを起動します。
ここで構わず <F1>キーを押すと、 USB メモリからの起動が始まる。
linux が起動すると /bin/sh が実行されてプロンプト「#」が表示されるが、 その後 USB メモリが認識されてカーネル・ログが出力される。
... PWD='/' ROOTPARM=' -o ro' TERM='linux' initrd='initz' /bin/sh: can't access tty; job control turned off # [ 31.556958] scsi 6:0:0:0: Direct-Access Multi Flash Reader 1.00 PQ: 0 ANSI: 0 [ 32.077952] sd 6:0:0:0: [sdb] 1006592 512-byte hardware sectors (515 MB) [ 32.079952] sd 6:0:0:0: [sdb] Write Protect is off [ 32.080089] sd 6:0:0:0: [sdb] Mode Sense: 03 00 00 00 [ 32.080094] sd 6:0:0:0: [sdb] Assuming drive cache: write through [ 32.085449] sd 6:0:0:0: [sdb] 1006592 512-byte hardware sectors (515 MB) [ 32.087574] sd 6:0:0:0: [sdb] Write Protect is off [ 32.087699] sd 6:0:0:0: [sdb] Mode Sense: 03 00 00 00 [ 32.087704] sd 6:0:0:0: [sdb] Assuming drive cache: write through [ 32.087830] sdb: sdb1 [ 32.090803] sd 6:0:0:0: [sdb] Attached SCSI removable disk [ 32.091527] usb-storage: device scan complete
プロンプトの後にカーネル・ログが出力されてしまっているため紛らわしいが、 Enter キーを押せばプロンプトが表示される。
このカーネル・ログでは [sdb] と表示されているが、 レッツノートに接続した USB デバイスが他にもあれば、 sdc や sdd になっているかもしれない。 その場合は、以下の sdb を sdc なり sdd なりで読み替えて欲しい。
以下のように mount コマンドを実行して、 USB メモリを /mnt へマウントする。 そして USB メモリ上の hdparm コマンドを実行してみる:
# mount -t vfat /dev/sdb1 /mnt
# /mnt/hdparm -i /dev/sda
/dev/sda:
Model=Hitachi HTS541612J9SA00 , FwRev=SBDOC70P, SerialNo= SBXXXXXXXXXXXX
Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs }
RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=4
BuffType=DualPortCache, BuffSize=7516kB, MaxMultSect=16, MultSect=?16?
CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=234441648
IORDY=on/off, tPIO={min:120,w/IORDY:120}, tDMA={min:120,rec:120}
PIO modes: pio0 pio1 pio2 pio3 pio4
DMA modes: mdma0 mdma1 mdma2
UDMA modes: udma0 udma1 udma2 udma3 udma4 *udma5
AdvancedPM=yes: mode=0x80 (128) WriteCache=enabled
Drive conforms to: ATA/ATAPI-7 T13 1532D revision 1: ATA/ATAPI-2,3,4,5,6,7
* signifies the current active mode
#
以上のように、 レッツノートのハードディスク (/dev/sda) の諸元が表示されれば成功である。 以下のように hdparm を実行して「Power-Up In Standby feature」を無効にすれば、 ハードディスクの復旧が完了する。
# /mnt/hdparm -s0 /dev/sda /dev/sda: spin-up: setting power-up in standby to 0 (off) #
後は、Ctrl-Alt-Del を押すなどして再起動すれば、 ハードディスクから正常にブートする。 USB メモリを抜くのを忘れずに。
先日 1/10 (運悪く出張初日だった *_*) に、 レッツノート CF-R6MWVAJP のハードディスク・ドライブ (以下、HDD と略記) が 回転しなくなり (スピン・アップしない) 往生した。 電源を入れても、 BIOS が
Phoenix TrustedCore(tm) NB Copyright 1985-2004 Phoenix Technologies Ltd. All Rights Reserved Copyright (C) Matsushita Electric Industrial Co.,Ltd. 2007 BIOS Version 1.00-L13 CPU = 1 Processors Detected, Cores per Processor = 2 Intel(R) Core(TM) Duo CPU U2400 @ 1.06GHz 2048MシステムRAMテスト完了。 システムBIOSがシャドウされました。 ビデオBIOSがシャドウされました。 ハードディスク0: マウスが初期化されました。 エラー 0200: ハードディスクエラーです。 0 <F2>キーを押すとセットアップを起動します。
というメッセージをビープ音とともに出力して止まってしまう。 HDD が壊れたのかと思い、 BIOS で HDD を起動ドライブから外して USB メモリからブートを試みたが、 起動ドライブから外しても内蔵 HDD に問題があると先に進めないようだ。
HDD を完全に取り除いてしまえば USB メモリからブートするらしいが、 このような中途半端な死にかただとスピン・アップ待ちになってしまって、 そこから先に進めなくなる (後で知ったのだが、 実は上記画面で止まっているとき <F1> を押すと、 ブートを継続できて USB メモリ等からブートできる)。
昔、HDD のスピンドル (spindle) が固着して、 スピン・アップ (spin up) しなくなる症状に見舞われたことがあったが、 今回はつい数分前まで全く正常に動いていた HDD が、 突然スピン・アップしなくなったのであって、 あからさまに症状が異なるように思われた。 しかもごく短い距離を移動するためにレッツ・ノートを閉じただけなので、 途中衝撃なども一切与えていない。 機械的な障害ではないように思われた。
とはいえ、 いちおー無駄な抵抗は試みた (^^;)。 すなわち、 HDD が回転しなくなったときに、 HDD を振り回すことによってトルクを与える手法や、 あるいは結露等で回路に異常がおきたときに、 結露を霧散させる手法 (平たく言うとしばらく放置しただけ ;) を試したのだが、 HDD が回転音を発することは無かった。 出張初日で、 代替マシンの調達もままならず、 Advanced/W-ZERO3[es] に USB キーボードをつないで急場をしのいだものの、 えらく難儀した。
結論から言うと、 想像通りハードウェア的にはなんら故障していなかった。 単に HDD が 「電源投入時にスタンバイ・モードに入る (power-on in standby)」 状態になっていただけだった。
1/9 に行なわれた Windows Update KB943899 が原因らしいです。 おそらくこの Update のバグで、 HDD に power-on in standby を有効にする命令が 送られてしまうことがあるのでしょう。 私の CF-R6 は 1/10 に発症しましたが、 他にも同様の発症例が多数あるとか。
例えば、 Linux の hdparm コマンドのマニュアルには、 次のような記述がある。
NAME
hdparm - get/set hard disk parameters
SYNOPSIS
hdparm [ flags ] [device] ..
OPTIONS
-s Enable/disable the power-on in standby feature, if supported by
the drive. VERY DANGEROUS. Do not use unless you are abso-
lutely certain that both the system BIOS (or firmware) and the
operating system kernel (Linux >= 2.6.22) support probing for
drives that use this feature. When enabled, the drive is pow-
ered-up in the standby mode to allow the controller to sequence
the spin-up of devices, reducing the instantaneous current draw
burden when many drives share a power supply.
「VERY DANGEROUS」と書いてある通り、 HDD がひとたびこの「power-on in standby」モードになってしまうと、 電源を投入してもスピン・アップしなくなる (スタンバイ状態になる)。 HDD が沢山あるサーバなどで、 全ディスクが一斉に回転を始めると、 突入電流が電源の許容範囲を超えてしまったりするわけで、 それを回避するためのモードらしい。 つまり、 電源を投入したあと、 おもむろに HDD を一台づつスピン・アップしていくことにより、 回転開始にともなう突入電流を分散させることができるというわけ。
実験してみる (非常に危険なので何をやっているか完全に理解するまでは 真似しないでください):
# hdparm -s1 /dev/sda
/dev/sda:
setting power-up in standby to 1 (on)
# hdparm -I /dev/sda
/dev/sda:
ATA device, with non-removable media
Model Number: Hitachi HTS541612J9SA00
Serial Number: SBXXXXXXXXXXXX
Firmware Revision: SBDOC70P
Standards:
Used: ATA/ATAPI-7 T13 1532D revision 1
Supported: 7 6 5 4
Configuration:
Logical max current
cylinders 16383 16383
heads 16 16
sectors/track 63 63
--
CHS current addressable sectors: 16514064
LBA user addressable sectors: 234441648
LBA48 user addressable sectors: 234441648
device size with M = 1024*1024: 114473 MBytes
device size with M = 1000*1000: 120034 MBytes (120 GB)
Capabilities:
LBA, IORDY(can be disabled)
Queue depth: 32
Standby timer values: spec'd by Vendor, no device specific minimum
R/W multiple sector transfer: Max = 16 Current = 16
Advanced power management level: 128 (0x80)
Recommended acoustic management value: 128, current value: 254
DMA: mdma0 mdma1 mdma2 udma0 udma1 udma2 udma3 udma4 *udma5
Cycle time: min=120ns recommended=120ns
PIO: pio0 pio1 pio2 pio3 pio4
Cycle time: no flow control=120ns IORDY flow control=120ns
Commands/features:
Enabled Supported:
* SMART feature set
* Security Mode feature set
* Power Management feature set
* Write cache
* Look-ahead
* Host Protected Area feature set
* WRITE_BUFFER command
* READ_BUFFER command
* NOP cmd
* DOWNLOAD_MICROCODE
* Advanced Power Management feature set
* Power-Up In Standby feature set
* SET_FEATURES required to spinup after power up
SET_MAX security extension
Automatic Acoustic Management feature set
* 48-bit Address feature set
* Device Configuration Overlay feature set
* Mandatory FLUSH_CACHE
* FLUSH_CACHE_EXT
* SMART error logging
* SMART self-test
* General Purpose Logging feature set
* WRITE_{DMA|MULTIPLE}_FUA_EXT
* 64-bit World wide name
* IDLE_IMMEDIATE with UNLOAD
* SATA-I signaling speed (1.5Gb/s)
* Native Command Queueing (NCQ)
* Host-initiated interface power management
* Phy event counters
Non-Zero buffer offsets in DMA Setup FIS
DMA Setup Auto-Activate optimization
Device-initiated interface power management
In-order data delivery
* Software settings preservation
Security:
Master password revision code = 2007
supported
enabled
not locked
frozen
not expired: security count
not supported: enhanced erase
Security level maximum
72min for SECURITY ERASE UNIT.
Checksum: correct
#
「Power-Up In Standby feature set」が有効になっていることが分かる。 この状態で再起動する (HDD の電源をいったん切る) と、 冒頭に引用した「0200: ハードディスクエラーです。 0」を表示して止まってしまう。 <F1> を押して HDD 以外から起動させると、
[ 0.000000] Linux version 2.6.23.12 (sengoku@senri.gcd.org) (gcc version 4.1.2) #1 SMP Mon Dec 24 09:50:41 JST 2007 ... [ 72.479025] ata3.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x0 [ 72.479031] ata3.00: irq_stat 0x40000001 [ 72.479044] ata3.00: cmd c8/00:08:00:00:00/00:00:00:00:00/e0 tag 0 cdb 0x0 data 4096 in [ 72.479047] res 51/04:08:00:00:00/00:00:00:00:00/e0 Emask 0x1 (device error) [ 72.481033] ata3.00: configured for UDMA/33 [ 72.481043] sd 2:0:0:0: [sda] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE,SUGGEST_OK [ 72.481051] sd 2:0:0:0: [sda] Sense Key : Aborted Command [current] [descriptor] [ 72.481060] Descriptor sense data with sense descriptors (in hex): [ 72.481066] 72 0b 00 00 00 00 00 0c 00 0a 80 00 00 00 00 00 [ 72.481082] 00 00 00 00 [ 72.481089] sd 2:0:0:0: [sda] Add. Sense: No additional sense information [ 72.481099] end_request: I/O error, dev sda, sector 0 [ 72.481114] ata3: EH complete [ 72.481738] sd 2:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 72.481794] sd 2:0:0:0: [sda] 234441648 512-byte hardware sectors (120034 MB) [ 72.481818] sd 2:0:0:0: [sda] Write Protect is off [ 72.481824] sd 2:0:0:0: [sda] Mode Sense: 00 3a 00 00 [ 72.481861] sd 2:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
何度も HDD へリクエストを再送した末、「I/O error」になる。 Linux 2.6.22 以降の場合、 I/O error にはなるものの HDD デバイス自体は認識しているので、 hdparm コマンドからコントロールすることができる。
逆に言うと、古いカーネルだとデバイス認識も行なわれないので、 hdparm コマンドすら使えなくなってしまい 以下の方法では復旧できない。 現時点では Knoppix などの LiveCD の多くは、 2.6.21 以前のカーネルのまま (例えば Knoppix v5.1.1 は 2.6.19) なので注意。
hdparm を使って「Power-Up In Standby feature」を無効にする:
# hdparm -I /dev/sda | grep Power-Up * Power-Up In Standby feature set # hdparm -s0 /dev/sda /dev/sda: setting power-up in standby to 0 (off) # hdparm -I /dev/sda | grep Power-Up Power-Up In Standby feature set #
これで、電源投入時に HDD は自動的に回転を始めるようになる。
再起動すれば HDD から正常にブートする。
Linux でテレビ録画を行なう方法は、 多くの Web ページで紹介されているが、 ビデオキャプチャ・カードによっては、 Linux カーネルのバージョンが変わると一筋縄にはいかなかったりするので、 現時点での Linux カーネル安定版の最新バージョン 2.6.22.10 で、 I-O DATA 製 ハードウェア MPEG-2 エンコーダ搭載TVキャプチャボード GV-MVP/RX2W (2006年7月5日生産終了) を使う方法をメモ (2.6.24.4 で使う方法)。
といっても多くの方々の努力により、 GV-MVP/RX2 は標準のカーネルのままで (多少の不具合はあるにせよ) テレビ視聴が可能になりつつあるので、 Linux 2.6.22.10 の時点で必要なパッチは、 以下の三ヵ所のみ (モノラル音声で構わなければ saa7115 に対するパッチのみ)。 なお、 IVTV プロジェクト で 最新ドライバが公開されているが、 少なくとも GV-MVP/RX2W を使う限りにおいては 既に Linux 2.6.22.10 カーネルに取り込まれているドライバだけで問題がないので、 標準のカーネルのドライバのみを使っている。
まず、SAA7115 Video Decoder ドライバ・モジュール saa7115.ko に対するパッチ:
diff -ru linux-2.6.22.10.org/drivers/media/video/saa7115.c linux-2.6.22.10/drivers/media/video/saa7115.c --- linux-2.6.22.10.org/drivers/media/video/saa7115.c 2007-08-23 08:23:54.000000000 +0900 +++ linux-2.6.22.10/drivers/media/video/saa7115.c 2007-10-14 06:37:09.000000000 +0900 @@ -1543,7 +1543,8 @@ saa711x_writeregs(client, saa7113_init); break; default: - state->crystal_freq = SAA7115_FREQ_32_11_MHZ; + state->ucgc = 1; + state->cgcdiv = 0x04; saa711x_writeregs(client, saa7115_init_auto_input); } saa711x_writeregs(client, saa7115_init_misc);
CGC (Clock Generation Circuit) の設定。 SAA7115 は 32.11MHz か 24.576MHz の水晶発振子を利用できて、 GV-MVP/RX2 では後者なのであるが、 このパッチをあてておかないと 32.11MHz の設定になってしまって、 録画したものを再生すると音声が早回しになってしまう。
次に、オーディオ・チップ・ドライバ・モジュール tvaudio.ko に対するパッチ:
diff -ru linux-2.6.22.10.org/drivers/media/video/tvaudio.c linux-2.6.22.10/drivers/media/video/tvaudio.c
--- linux-2.6.22.10.org/drivers/media/video/tvaudio.c 2007-08-23 08:23:54.000000000 +0900
+++ linux-2.6.22.10/drivers/media/video/tvaudio.c 2007-10-14 06:38:26.000000000 +0900
@@ -528,6 +528,31 @@
chip_write(chip,TDA985x_C6,c6);
}
+static int gvmvprx_getmode(struct CHIPSTATE *chip) {
+ return VIDEO_SOUND_MONO;
+}
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+static void gvmvprx_setmode(struct CHIPSTATE *chip, int mode) {
+ u8 data[3] = { 0x00, 0x00, 0x04 };
+
+ switch (mode) {
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ break;
+ case VIDEO_SOUND_STEREO:
+ data[1] = 0x01;
+ break;
+ case VIDEO_SOUND_LANG2:
+ data[1] = 0x02;
+ break;
+ }
+
+ if (i2c_master_send(&chip->c, data, sizeof(data)) != sizeof(data)) {
+ v4l_err(&chip->c, "%s: I/O error setting audmode\n", chip->c.name);
+ }
+}
+
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for tda9873h */
@@ -1307,17 +1332,17 @@
.checkmode = generic_checkmode,
},
{
- .name = "tda9850",
+ .name = "tda9850 (GV-MVP/RX)",
.id = I2C_DRIVERID_TDA9850,
.insmodopt = &tda9850,
.addr_lo = I2C_ADDR_TDA985x_L >> 1,
.addr_hi = I2C_ADDR_TDA985x_H >> 1,
.registers = 11,
- .getmode = tda985x_getmode,
- .setmode = tda985x_setmode,
+ .getmode = gvmvprx_getmode,
+ .setmode = gvmvprx_setmode,
- .init = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+ .init = { 3, { 0x00, 0x01, 0x04 } }
},
{
.name = "tda9855",
ステレオ/モノラル/音声多重(二ヶ国語放送) 音声モードの変更。 GV-MVP/RX2W は他のチューナと異なり、 設定変更の際 3 バイトのデータを送信する必要があるらしい。
tda9887 を deemphasis->off (このチップは deemphasis すると音声を強制でモノラルにしてしまう。 tda9887.c の NTSC-M-J の項では deemphasis を default で OFF にすべきなのではないでしょうか。 素人考えかな。)
ivtv-0.2.0-rc3j-paken.051002-bilingul.patch をベースに MPX 操作 (レジスタ0に3バイト書き込むほう) すればうちのカードでは音声多重に対応できるようです。 レジスタ 0 に 1 バイト書き込むほうのMPX操作では うちのカードでは動作しませんでした。 カードのリビジョンとかの関係かもしれません。ぱ研「LinuxでITVC16-STVLP」 の kazz 氏コメント (2007-03-10) から引用
DeEmphasis (DEM) モードを設定すると常にモノラル音声になってしまう。 kazz 氏が言及しているように default で DEM を off にしておけば 済むような気がするし、 そもそもなぜ DEM がデフォルトで ON になっているのか疑問だったので、 以下のようなパッチを tuner チップ・ドライバ・モジュール tuner.ko の tda9887.c にあてて、 NTSC-M-JP の場合は DeEmphasis を off にしてみた。
diff -ru linux-2.6.22.10.org/drivers/media/video/tda9887.c linux-2.6.22.10/drivers/media/video/tda9887.c --- linux-2.6.22.10.org/drivers/media/video/tda9887.c 2007-08-23 08:23:54.000000000 +0900 +++ linux-2.6.22.10/drivers/media/video/tda9887.c 2007-10-14 11:59:50.000000000 +0900 @@ -214,8 +214,7 @@ .name = "NTSC-M-JP", .b = ( cNegativeFmTV | cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | + .c = ( cDeemphasisOFF | cTopDefault), .e = ( cGating_36 | cAudioIF_4_5 |
「cDeemphasisON | cDeemphasis50」の部分を「cDeemphasisOFF」に変更しただけの 安易なパッチ (^^;) であるが、 とりあえずこれでステレオ/音声多重での録画が可能になっている。
以上のように tvaudio と tuner (tda9887.c) の両ドライバ・モジュールに パッチをあてることにより、 ステレオ/音声多重で録画できる。 もちろん v4l2-ctl コマンドで音声モードを変更することもできるが、 録画は常に「ステレオ/音声多重」で行なっておいて、 再生時に音声モードを切替えたほうが便利。
私は録画 perl スクリプトを自作して使っているが、 この perl スクリプトで使用している Video::ivtv & Video::Frequencies モジュールには若干問題がある。 すなわち setFrequency する際にチューナ形式を指定し忘れているので、 正しく TV チャンネルの変更が行なえない。 私は以下のような修正パッチをあてて使用している。
diff -u Video-ivtv-0.13/ivtv.xs.org Video-ivtv-0.13/ivtv.xs
--- Video-ivtv-0.13/ivtv.xs.org 2004-06-14 06:07:40.000000000 +0900
+++ Video-ivtv-0.13/ivtv.xs 2007-10-08 10:03:57.000000000 +0900
@@ -132,6 +132,7 @@
}
CODE:
vf.tuner = tuner;
+ vf.type = V4L2_OUTPUT_TYPE_ANALOG;
if (ioctl(fd, VIDIOC_G_FREQUENCY, &vf) < 0)
{
RETVAL = -1;
@@ -158,6 +159,7 @@
}
CODE:
vf.tuner = tuner;
+ vf.type = V4L2_OUTPUT_TYPE_ANALOG;
vf.frequency = freq;
if (ioctl(fd, VIDIOC_S_FREQUENCY, &vf) < 0)
{
この録画スクリプトは
予約録画 (-t オプション) もサポートしている他、
tv -P 1234
などと実行すると、
TV サーバとして利用することもできる。
つまり LAN 内の任意のマシンで、
VLC media player を使って
http://senri:1234/?c=1
などとチャンネル指定付で tv サーバへ接続し、
TV を視聴できる。
(ビデオキャプチャ・カード GV-MVP/RX2W を使って Linux 2.6.24.4 でテレビ録画)
極めて稀とはいえ、Linux もハングすることはある。 ハードウェア自体には何ら異常はなく、 リセットスイッチを押したら正常に再起動してしまって、 何が問題だったか分からずじまい、という経験は誰にでもあるのではなかろうか。 原因不明のハングが全く無くなるのが理想ではあるのだが、 ハングして止ったままになるよりは、 自動的にリセットがかかって再起動してくれたほうがいい、という場合もあるだろう。
もちろんハードウェア障害が原因でハングしてしまった場合は、 リセットスイッチを押しても解決にはならない。 再起動を試みることにより、障害がより致命的になる可能性もあるので、 ウォッチドッグ・タイマーを設定する際は、 「止ったまま」と「自動再起動」とどちらがマシか天秤にかける必要がある。
そんなとき、 ウォッチドッグ・タイマー (watchdog timer) が便利。 一定時間 (例えば 30秒) 放置すると、 システムを自動的にリセットするタイマーである。 この自動リセットを回避するには、 定期的に (30秒以内に) タイマーを元に戻す (以下、番犬 (watchdog) に「蹴りを入れる」と略記) 必要があるわけで、 システムが正常に動作している時は 定期的に「蹴り」を入れ続けるようなプログラムを走らせておく。 で、 カーネルがハングしたなどの理由によって 「蹴り」を入れるプログラムが動かなくなると、 自動的にシステム・リセットがかかって ハング状態を脱出できる、という仕掛け。
ソフトウェアにどんなトラブルが起きても確実に再起動を行なわせるには、 ハードウェアで物理的にリセット スイッチを押す ハードウェアを用いるのが一番であるが、 まずはお手軽にソフトウェア版を利用してみることにした。仙石浩明の日記: ウォッチドッグ タイマ から引用
わざわざハードウェア・ウォッチドッグ・タイマーを買ってきて 組み込むのは大変と思ったので、 上に引用した日記 (2006年5月) で書いたように ソフトウェア版ウォッチドッグ (softdog.ko モジュール) を使っていたのだが、 実はインテル・チップセットであれば大抵の PC に標準で ハードウェア・ウォッチドッグ・タイマーがついていた (何たる不覚 orz)。
Intel TCO Timer/Watchdog
Hardware driver for the intel TCO timer based watchdog devices. These drivers are included in the Intel 82801 I/O Controller Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB controller hub.linux/drivers/char/watchdog/Kconfig から引用
つまり Intel の ICH には最初から ハードウェア・ウォッチドッグ・タイマーがついていたようである。 最近の Linux カーネルには、 このウォッチドッグ・タイマーのドライバが含まれているので早速使ってみた。 というか、 Linux 2.6.22.9 を使っていたら、 このドライバ・モジュール iTCO_wdt が自動的に読み込まれていた (^^;) ので、 このウォッチドッグ・タイマーの存在に気づいた、という次第。 /dev/watchdog に何か書込んでみるだけで (例えば「echo @ > /dev/watchdog」を実行)、 タイマーがスタートした (/dev/watchdog が存在しない場合は、 「mknod /dev/watchdog c 10 130」を実行する)。
そして 30秒後、勝手にリセットがかかった (めでたしめでたし)。
ウォッチドッグ タイマというと、 普通は 60秒くらいに設定しておくものだとは思うが、 自宅サーバの場合、一時間くらいハング状態が続いてもそんなに困らない ;) のと、 あまりタイマの間隔が短すぎると、 不用意に再起動してしまう恐れもあるので、 3600秒 (一時間) に設定している。 つまり一時間以内にタイマをリセットしないと、 自動再起動が行なわれる。仙石浩明の日記: ウォッチドッグ タイマ から引用
じゃ、iTCO_wdt.ko モジュールでも同様に heartbeat=3600 を指定すればいいのかな と思っていたら、 heartbeat は最大 613 秒までしか設定できない (TCO v2 の場合) ようである。 わずか 10分足らずでは不用意に再起動してしまう恐れ大。 そこで、 監視プログラムが直接 /dev/watchdog に「蹴り」を入れる代わりに、 監視プログラムは /var/run/watchdog に「蹴り」を入れることにして、 /var/run/watchdog を監視して /dev/watchdog に「蹴り」を入れる 「蹴り代行」デーモンを走らせておくことにした。
つまり、監視プログラムは 20分に一度 /var/run/watchdog に「蹴り」を入れるだけで、 あとは「蹴り代行」デーモンが 5秒に一度、 /dev/watchdog に「蹴り」を入れ続けてくれる。 だからウォッチドッグ・タイマーのドライバの設定は、 デフォルト (30秒) のままで済むし、 また「蹴り代行」デーモンの設定次第で、 20分といわずもっと長い余裕を持たせることも可能。
/service/watchdog/run
#!/usr/bin/perl
use strict;
use warnings;
$| = 1;
my $watchdog_uid = getpwnam("adsl_check");
my $watchdog_gid = getgrnam("watchdog");
my $watchdog_file = "/var/run/watchdog";
my $watchdog_dev = "/dev/watchdog";
print "start\n";
if (! -f $watchdog_file) {
if (!open(WATCHDOG, ">$watchdog_file")) {
print "can't create $watchdog_file exiting...\n";
exit 1;
}
close(WATCHDOG);
chown $watchdog_uid, $watchdog_gid, $watchdog_file;
}
($(, $)) = ($watchdog_gid, $watchdog_gid);
($<, $>) = ($watchdog_uid, $watchdog_uid);
while (-z $watchdog_file) {
sleep 5;
}
print "confirmed $watchdog_file\n";
truncate($watchdog_file, 0);
if (!open(WATCHDOG, ">$watchdog_dev")) {
print "can't open $watchdog_dev exiting...\n";
exit 1;
}
select(WATCHDOG);
$| = 1;
select(STDOUT);
for (my $i=0; $i < 240; $i++) {
print WATCHDOG "\@\n";
sleep 5;
}
print WATCHDOG "\@\n";
close(WATCHDOG);
print "exiting...\n";
exit 0;
「/service/watchdog/run」というパス名からも分かる通り、 このスクリプトは daemontools 配下で動かしている。 このスクリプトは、 20分間 (5 秒 * 240) /dev/watchdog に蹴りを入れ続けると終了する。 そして daemontools がこのスクリプトを再起動すると、 /var/run/watchdog の存在を確認した上で再び蹴りを入れ続ける。 つまり、 20 分間以上 /var/run/watchdog に蹴りが入れられないと、 この「蹴り代行」スクリプトは止ってしまい、 /dev/watchdog への蹴りも止ってしまう。
ここでなぜ 20分毎にこのスクリプトを終了するようにしているかというと、 daemontools の動きも監視対象に含めたいから。 つまり、システムの負荷が高くなり過ぎて daemontools による再起動に時間がかかるような事態になっても、 /dev/watchdog への蹴りが止る。
まとめると、 /var/run/watchdog への蹴りが止ったり、 あるいは daemontools による再起動が滞ったりすると、 /dev/watchdog への蹴りも止ってしまって、 ウォッチドッグ・タイマーが時間切れになり、 ハードウェア的に自動リセットがかかる、という仕掛け。
私は他のマシンから
ssh server "echo '@' > /var/run/watchdog"
などと ssh でアクセスするよう cron に設定している。 ssh が成功すれば /var/run/watchdog へ書き込み、 すなわち蹴りが入れられるので、 蹴り代行スクリプトによってウォッチドッグ・タイマーに蹴りが入れられる。
これまでLinuxのハードウェア自動認識と言えば、 /sys/bus/pci/devices 以下と、 /lib/modules/`uname -r`/modules.pcimap を照らし合わせて 解析していくのが定石でした。 USBにも対応しようとすると、もう一つ大変です。
しかしこれからの常識は、 /sys/bus/*/devices/*/modalias と
/lib/modules/`uname -r`/modules.alias です。古橋貞之の日記「20行できる高精度ハードウェア自動認識」から引用
すばらしい。 確かに modules.alias を使う方が、 簡単かつ確実に必要なモジュールを読み込むことができそう。 さっそくこの方法を使って initramfs の init スクリプトを書き直してみた。
tmp=/tmp/dev2mod
echo 'dev2mod(){ while read dev; do case $dev in' > $tmp
sort -r /lib/modules/`uname -r`/modules.alias \
| sed -n 's/^alias *\([^ ]*\) *\(.*\)/\1)modprobe \2;;/p' >> $tmp
echo 'esac; done; }' >> $tmp
. $tmp
rm $tmp
cat /sys/bus/*/devices/*/modalias | dev2mod
わずかに 8行 (^^)
(9/30追記: modules.alias を逆順ソートしておく必要があることが判明、sort -r を追加)。
シェルスクリプト版はRuby版と比べて40倍くらい遅いので注意。同ページ(古橋貞之の日記)から続けて引用
sh スクリプトの名誉のために言っておくと、 私が書いた上記 sh スクリプトだと、 古橋さんの Ruby 版と比べて 4倍くらいの遅さで済んでいる。
% time ./dev2mod ide_cd intel_agp intelfb uhci_hcd ...(中略)... libusual usbcore 0.252u 0.012s 0:00.77 33.7% 0+0k 0+0io 0pf+0w % time ./detect_kmod.rb ["ivtv", "snd_intel8x0", "intelfb", "libusual", "ftdi_sio", "usbhid", "uhci_hcd", "ehci_hcd", "usbcore", "via_velocity", "eepro100", "e100", "3c59x", "psmouse", "ide_cd", "i2c_i801", "hw_random", "intel_agp"] 0.072u 0.008s 0:00.18 38.8% 0+0k 0+0io 0pf+0w
ちなみに古橋さんのスクリプトは、
modules.alias の各行それぞれに対し、
マッチするデバイスが /sys/bus/*/devices/*/modalias に存在すれば、
そのモジュールを読み込む処理になっている。
しかしながら、これだと一つのデバイスに対し、
複数のモジュールが読み込まれてしまうことになるのではないだろうか?
古橋さんが同日追記されているように、 複数のモジュールが読み込まれること自体は簡単に修正可能で、 むしろモジュールの読み込み順が modules.alias に載っている順になることのほうが問題。 この問題点を解決するため、 /sys/bus/*/devices/*/modalias の各行それぞれに対し、 マッチするモジュールを modules.alias から見つける修正版が追記された。 さすが古橋さん、すばやい。9/30追記
例えば古橋さんのスクリプトだと、 私の手元のマシンでは e100 と eepro100 の両方のモジュールが読み込まれてしまう。 つまり、
% cat /sys/bus/pci/devices/0000:01:08.0/modalias pci:v00008086d00001050sv0000107Bsd00004043bc02sc00i00
が、modules.alias の次の二つの行にマッチするため、 このようなことが起こる。
alias pci:v00008086d00001050sv*sd*bc*sc*i* eepro100 alias pci:v00008086d00001050sv*sd*bc02sc00i* e100
modules.alias を検索する際は、 マッチする行が見つかった時点で以降の行はスキップしないと、 この例のように複数のモジュール読み込みが起きる恐れがある。 マッチした以降の行を読み飛ばすには、 私が書いた上記 sh スクリプトのように、 /sys/bus/*/devices/*/modalias の各行それぞれに対し、 マッチするモジュールを一つだけ modules.alias から見つけて読み込む処理のほうが、 簡単に書けるのではないかと思うがどうだろうか。
とはいえ、実際の NIC は Intel Pro 10/100 だったりする (^^;) ので、 読み込むべきモジュールは e100 であるような気もする。 もし e100 が正しいモジュールであるのなら、 modules.alias における eepro100 のパターンが適切ではないということになるのかも。9/30追記「*」を多く含むパターンは「後で」マッチさせたほうが、 より適切なモジュールを選択できると考えられるため、 modules.alias を逆順ソートしておくことにした。 これにより、eepro100 ではなく、e100 を読み込むようになった。9/30さらに追記
参考までに initramfs の /init スクリプト全体を添付しておく:
続きを読むlinux をブートさせる際、 さまざまな PC に対応させようとすると、 多くのデバイスドライバをカーネルに組み込んでおかねばならない。 つまりルートファイルシステム (root file system, 以下 rootfs と略記) をマウントするまでは、 その rootfs 上にインストールしたモジュール群 (/lib/modules/ の下に置いた *.ko ファイル群) を読めないからだ。 rootfs さえマウントできてしまえば、 あとはいくらでもモジュールを必要に応じて読み込むことができるようになる。 だから、さまざまなハードウェアへの対応といっても、 重要なのは rootfs をマウントするまで、である。
しかしながら、 rootfs をマウントするまでの辛抱といっても、 rootfs をマウントするにはハードディスクを認識しなければならないし、 それには ATA ドライバやら SCSI ドライバやら、 果ては AHCI ドライバなどが、 ハードウェアに応じて必要になる。
個人で管理する PC の全てのハードウェアに対応させるだけなら、 全てのドライバをあらかじめカーネルに読み込んでおくのもアリだろう。 しかし汎用的なディストリビューションなど、 (カーネル再構築を行なわずに) 多くのハードウェアに対応する必要がある場合は、 必要になるかも知れない全てのドライバを、 あらかじめカーネルに読み込んでおくなどということは非現実的である。
ちなみに私は、1993年頃から linux を使っているが、 いまだに当時インストールした slackware を使用し続けている。 もちろん kernel や libc をはじめとして、 ほぼ全てのソフトウェアをアップデートしてしまっているし、 しかも起動スクリプトをはじめとして、 あらゆる設定を好き勝手に書き換えてしまっているので、 インストールしてから 10年以上たった今となっては、 元の slackware の痕跡は全くといっていいほど残っていない。 もはや、私独自のディストリビューションと呼んでしまっても差し支えないだろう。 私が個人的に管理しているマシンには、 全てこの「my distribution」をインストールしている。 そんなわけで、私は「普通の」ディストリビューションを使ったことがない。 initrd がディストリビューションの「常識」となってからも、 私は initrd は使わずに、 自分が管理する PC のハードウェアに合わせてカーネルを再構築して使ってきた。
そこで linux では、 initrd (Initial RAM Disk) という仕掛けが使われてきた。 すなわちハードディスクを rootfs としてマウントする前に、 一時的にマウントする「ミニ」ルート (mini root) である。 このミニルートには、 ハードディスク (あるいは 1CD Linux の場合であれば CD だし、 ネットワークブートする場合であれば NFS サーバ) を rootfs としてマウントするのに必要となる可能性がある モジュール群一式を置いておき、 ハードウェアに応じて必要なモジュールをミニルートから読む。 そして、ハードディスクをマウントして、 / (ルート) をミニルートからハードディスクへ切り替える。
ただ、この initrd は少々扱いが面倒くさい。 initrd は RAM ディスクという「本物の」ブロックデバイスなので、 「本物の」ファイルシステム (例えば ext2) で mkfs しなければならない。 initrd にモジュールを追加しようとすれば、 initrd イメージを (losetup コマンドを使って) ループバックデバイス経由でマウントして内容を書き換えなければならないし、 たくさんのモジュールを追加した結果、 もしファイルシステムが一杯にでもなったりしたら、 initrd イメージのサイズを大きくして mkfs からやり直しである。
メンドクサイだけでなく、 RAM ディスク自体が非効率なものであるようで、 ファイルからブロックデバイスを作る方法としては、 すでに「semi-obsolete」とまで言われてしまっているようである:
Another reason ramdisks are semi-obsolete is that the introduction of loopback devices offered a more flexible and convenient way to create synthetic block devices, now from files instead of from chunks of memory. See losetup (8) for details.linux/Documentation/filesystems/ramfs-rootfs-initramfs.txt から引用
というわけで、initrd に代わる仕掛けとして、 linux kernel 2.6 からは initramfs と呼ばれる仕掛けが導入された。 すなわち RAM ディスクというブロックデバイスを用いるのではなく、 RAM 上に直接ファイルシステムを作る ramfs を用いた「ミニルート」である。 私自身は今まで initrd を使っていなかったのであるが、 cpio アーカイブを作るだけでいいというのは、 とても手軽であるように思えたし、 カーネルにどんどんドライバを組み込んで肥大化させるよりは、 initramfs を使う方がヨサゲである (もちろん、どんどんドライバを組み込めば、 initramfs が肥大化するのだが、 カーネルが肥大化するデメリットとは比較にならない) ように感じてきたので、 宗旨替えすることにした。
| initrd | initramfs | |
|---|---|---|
| イメージ | ファイルシステム (ext2など + gzip) | アーカイブ (cpio + gzip) |
| 実装 | ブロックデバイス (RAM ディスク) | ファイルシステム |
| 実行 | /linuxrc | /init |
| rootfs マウント |
適当なディレクトリへマウントして pivot_root |
/ へマウント (switch_root) |
| init 起動 | /linuxrc 終了後、カーネルが起動 | /init が exec /sbin/init する |
ブートパラメータとして「initrd=」を与えると、 ブートローダがイメージをメモリ上に読み込んでカーネルに渡す。 するとカーネルはそのイメージがファイルシステムなのか、 cpio アーカイブなのか調べる。 もしファイルの magic number が cpio であれば、 ramfs としてマウントする。 そして /init が実行可能ならば、 initramfs として扱い、 /init を起動する。
以上の条件が一つでも成立しない場合、
すなわち cpio アーカイブでない場合や、
/init が実行できない (/init が存在しない) 場合は、
initrd 扱いになるので注意が必要である。
すなわち RAM ディスクとしてマウントしようとするので、
カーネルに RAM ディスクドライバが組み込まれていなかったり、
「root=/dev/ram0」カーネルパラメータを指定していなかったりすると、
kernel panic を起こす。
実は、initramfs として起動できるようになるまで、 かなりハマってしまった。 まず、cpio アーカイブを作るところで、いきなりハマった。
(cd /usr/src/initramfs/; find . | cpio -o -H newc ) | gzip > initrd.gz
などとしてアーカイブを作ればいいだけの話なのであるが、 このコマンドラインを /bin/csh 上で実行したために、 アーカイブの先頭にゴミが入ってしまった。 つまり、
senri:/ % (cd /usr/src/initramfs/; find . | cpio -o -H newc ) | cpio -tv | head cpio: Malformed number 0000000. cpio: Malformed number 000000. cpio: Malformed number 00000. cpio: Malformed number 0000. cpio: Malformed number 000. cpio: Malformed number 00. cpio: Malformed number 0. cpio: Malformed number . cpio: warning: skipped 56 bytes of junk drwxr-xr-x 13 root root 0 Aug 27 17:56 . drwxr-sr-x 2 root root 0 Aug 25 10:00 bin -rwxr-xr-x 1 root root 1392832 Aug 25 18:36 bin/busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/addgroup -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/adduser -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/ash -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/cat -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/catv -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/chattr -> busybox lrwxrwxrwx 1 root root 7 Aug 25 10:09 bin/chgrp -> busybox
何が起きているかお分かりだろうか? お恥ずかしながら、アーカイブにゴミが混入していると気づくまで、 何度も kernel を panic させてしまった。 シェルのカスタマイズをやりすぎるとロクなことにならない、 という典型例なのかも (^^;)。
senri:/ % (cd /usr/src/initramfs/; echo test) | od -t a
0000000 esc E m A c S c d sp / u s r / s r
0000020 c / i n i t r a m f s nl esc E m A
0000040 c S c d sp / u s r / s r c / i n
0000060 i t r a m f s nl t e s t nl
0000075
senri:/ % alias cd
set back="$cwd";chdir !*;if(!* =~ "..")set cwd="$back:h";chdir "$cwd";setProm
senri:/ % alias setProm
set prompt="${HOST}:${cwd} $prompt_tail_char "
この alias 設定は、 もうかれこれ 10年以上使い続けてきた設定。 こんな形で悪さをするとは... orz
ようやくマトモなアーカイブを作れたと思ったら、 今度は以下のような Kernel panic が起きた:
Unpacking initramfs... done Freeing initrd memory: 1412k freed ...(中略)... No filesystem could mount root, tried: Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,1)
「Unpacking initramfs... done」と出ているのだから、 cpio アーカイブはちゃんと展開できて ramfs としてマウントできているはず。 なぜに「Unable to mount root fs」なのか、 と思っていたのだが、 これは initramfs に「/init」が無いためだった (エラーメッセージが不親切杉!)。 initrd みたいなものだろうと思って、 起動スクリプトを「/linuxrc」というファイル名で作っていたのが敗因。
「/init」がないと initrd 扱いになってしまい、 RAM ディスクを mount しようとしていたが、 RAM ディスクドライバが組み込まれていなかったのでマウントできない、 というのが、このエラーメッセージの主旨だったようだ (素直に /init が見つからない、って言ってくれればいいのに...)。 「/linuxrc」を「/init」へファイル名変更してみると、 あっさり initramfs 上での起動に成功した。
% ls -lt /boot/*-2.6.20.* -rw-r--r-- 1 root root 1643881 Sep 3 07:55 /boot/initz-2.6.20.18 -rw-r--r-- 1 root root 1193392 Sep 1 23:10 /boot/linuz-2.6.20.18 -rw-r--r-- 1 root root 2017936 May 12 19:31 /boot/linuz-2.6.20.11
2.6.20.11 を make したときは、 rootfs のマウントに必要なドライバを全てカーネルに詰め込んでいたのに対し、 2.6.20.18 では、 マウントに必要なドライバは極力 initramfs に入れた。 これにより linuz 単体のサイズは半分近くに減っている。 linuz (カーネル) + initz (initramfs) の合計サイズは 2.6.20.11 に比べ増えてしまっているが、 これは busybox だけで 1.3MB ほどあるため。 とはいえ、 initramfs 内では busybox よりも lib/modules 以下のサイズの方が倍ほど大きいので、 非効率というほどでもない。
senri:/usr/src/initramfs % ls -l bin/busybox -rwxr-xr-x 1 root root 1392832 Sep 1 11:24 bin/busybox senri:/usr/src/initramfs % du --max-depth=2 --byte 1397502 ./bin 4740 ./sbin 6204 ./usr/bin 4334 ./usr/sbin 8226 ./usr/share 22860 ./usr 4096 ./dev/pts 4096 ./dev/shm 12338 ./dev 4108 ./etc 4096 ./mnt 2422679 ./lib/modules 2426775 ./lib 4096 ./proc 4096 ./tmp 4096 ./var 4096 ./sys 3895272 .
じゃ、いよいよハードウェアの自動認識をして、 適切なモジュールのみを組み込むようにしてみようかと思って、 いろいろ探してみたのだが、 どうしたことか適当なスクリプトが見当たらない。 1CD Linux の /linuxrc をいろいろ読んでみたのだが、 いまいちパッとするものがない。 デバイスの ID などがゴリゴリ書いてあるものが大半で、 どれもアドホックすぎるように思えたのである。
かといって、ハードウェアの認識を udev などに行なわせる、 というのは牛刀過ぎるように思えた。 なんたって init を起動する前のブートストラップなのである。 目的は rootfs をマウントするだけなのであるから、 あまりに汎用的な仕掛けは、いかがなものかと思うのである。
というわけで、 busybox だけでハードウェアの自動認識 & モジュール読み込みを実現することを 目標にしてみた。 前フリが長くなった (長すぎ!) が、ようやくここからが本題である。
続きを読むノートPC を持ち歩いていると、たまに起動ディスクが欲しくなる。 カーネルや起動スクリプト、あるいはブートローダなどをいじっていて、 起動しなくなることが (しばしば ^^;) あるからだ。 ハードディスクから起動しなくなってしまうと、 起動ディスクが最後の手段となる (昔のノートPC では、 分解してハードディスクを取り出して内容を修正する、 という手段を使ったこともあったが、 最近のノートだと「ハードディスク保護」の仕掛けがあるようなので難しいだろう)。
昔は起動ディスクと言えばフロッピーディスクだった。 slackware の救急用ディスクを常備していた人も多いだろう。 そして今でも最後の最後の手段としてフロッピーディスクは万能である (実はつい最近、昔の VAIO C1 (無印) をいじっていたら起動しなくなって、 フロッピーディスクのお世話になってしまった)。 最近だとフロッピーディスクドライブがついているノート PC は、 ほとんど皆無だろう。 大抵のノートPC は、 USB 接続のフロッピーディスクドライブを使って起動できるとは思うが、 非常用起動ディスクのためだけにドライブを持ち歩くのもあまり現実的ではない。
フロッピーディスクの次に確実なブート手段というと、 CD/DVD ROM だろう。 CD からブートできない PC は、 さすがに最近ではほとんど見かけなくなった。 前述の VAIO C1 も CD からもブートできるのだが、 ドライブが悪いのか CD が悪いのか分からないが、 読み取りエラーが多発してブートできなかった。 滅多に使わないドライブだと光学系が経年劣化してしまうのか、 いつのまにか使えなくなってしまうので注意が必要である。
CD/DVD ドライブが内蔵のノートであれば、 Knoppix などの 1CD Linux を持ち歩けばよい。 12cm CD を常に持ち運ぶのが面倒という場合は、 名刺サイズの CD-R もある。 職場や自宅に何枚か 1CD Linux を常備している人も多いだろう。
私が普段持ち歩いているノートPC は、 レッツノート CF-R6MWVAJP (CF-W2FW6AXR から乗り換えた) なので CD/DVD ドライブが外付けである。 長期の旅行などでなければドライブを持ち歩くことはない。 なので、CF-W2 から CF-R6 へ乗り換えたのを機に、 非常用起動ディスクとして USB フラッシュメモリを使うようになった。 CD に比べコンパクトな上に起動時間も早いし、 (ライトワンスな CD-R と比べて) 内容の変更も手軽に行なえるので便利である。
しかし便利になると、もっと便利さを求めたくなるのがサガというもので、 USB メモリを常に持ち歩くのが面倒になってきた。 できたら常に持ち歩いているケータイを起動ディスクにできないだろうか?
幸い、私が使っているケータイ Advanced/W-ZERO3[es] (アドエス) は、 WM5torage を使うと、 アドエスを USB 大容量記憶デバイス (USB Mass Storage device) として使うことができるようなので、 syslinux を使って、 アドエスにブートローダを書込んでみると、 あっさり起動ディスクとして使えてしまった。 アドエスには 2GB の microSD を入れてあるので、 その片隅に 1CD Linux を入れておいても容量的には大して問題にならない。 常に持ち歩いているケータイをそのまま非常用の起動ディスクとして使えるので、 とても便利である。
と、これだけでは内容が無い (^^;) ので、 1CD Linux を USB メモリに入れて使う方法の解説などを... USB メモリへの書込むためのスクリプトを用意している 1CD Linux もあるようだが、 以下に説明するように 1CD Linux の起動の仕組みさえ理解していれば、 必要なファイル (基本的には、 カーネルと initrd と圧縮ディスクイメージの 3 つ) を USB メモリへコピーするだけの作業である。
むしろ CD に書込んで (仮想マシンを使えば書込まずに済むが、 面倒であることにはかわり無い) 1CD Linux をブートさせ、 書込みスクリプトを実行するよりは、 1CD Linux の ISO イメージから必要なファイルを取り出してコピーする方が、 手軽と言えるのではないだろうか? (もちろん万人向けの方法ではないが)
1CD Linux の起動は、おおむね次のようなステップを経る:
- BIOS が CD メディア上のブートローダを実行
- ブートローダが起動メニュー等を表示
ユーザがブートパラメータを必要に応じて編集 - ブートローダがカーネル (vmlinuz など) と initrd を読み込む
CD からの読み込みは、BIOS 経由 - ブートローダがカーネルを起動
- カーネルが initrd を RAM ディスクに展開し、ルートとしてマウント
- カーネルが RAM ディスク上の /linuxrc を実行
- /linuxrc がブロックデバイスをスキャン
圧縮ディスクイメージ (/KNOPPIX/KNOPPIX など) が存在する ブロックデバイスを探す - /linuxrc が見つけたブロックデバイスをマウント
- /linuxrc がマウントしたファイルシステム上の圧縮ディスクイメージをマウント
- /linuxrc の実行が終了すると、 通常の起動プロセス (つまり init の実行) が始まる
1CD Linux を USB メモリに入れるには、 上記ステップ 1. と 8. において、CD ではなく USB メモリが対象となるようにすればよい。 ステップ 1. は、BIOS による CD メディアの認識であり、 ステップ 8. は、カーネルによる CD メディアの認識である。 同じ CD メディアではあるが、認識を行なうプログラムが異なるので、 ステップ 7. で認識可能な全てのブロックデバイスをスキャンして、 自メディアを見つける必要がある。
なお、Puppy Linux の場合は、 ブートパラメータとして PMEDIA= を指定することにより、 スキャンするデバイスの種類を限定できる。 USB メモリに限定したいときは、「PMEDIA=usbflash」を指定すればよい。
スキャンしたデバイスが、 自メディアか否かを確認する方法は様々であるが、 おおむね特定のファイルが存在するか否かで判断している。 例えば、以下のような感じ:
| 1CD Linux | 確認方法 | |
|---|---|---|
| Knoppix | /KNOPPIX/KNOPPIX | knoppix_dir=, knoppix_name= で変更可能 |
| Damn Small Linux | /KNOPPIX/KNOPPIX | knoppix_dir=, knoppix_name= で変更可能 |
| INSERT | /INSERT/INSERT | insert_dir=, insert_name= で変更可能 |
| Puppy Linux | /pup_216.sfs | 「216」の部分はバージョン番号 |
| SLAX | /livecd.sgn |
ほとんどの 1CD Linux で、 圧縮ディスクイメージ (KNOPPIX, INSERT, pup_216.sfs など) の存在を 調べることによって自メディアを探し出しているが、 SLAX (Linux Live system) のように、 チェック用ファイル /livecd.sgn を CD に置いているケースもある。 /livecd.sgn は 243 バイトほどのファイルで、 以下のような内容である:
All available discs and CDROMs are mounted during the boot process. When done, linuxrc script is looking for this livecd.sgn file. It tells linuxrc where to mount the live filesystem from. Don't delete this file, else your LiveCD won't work.
「Don't delete this file, else your LiveCD won't work.」と書いてある通り、 このファイルが存在しないと、 /linuxrc が SLAX のメディアを見つけられなくなってしまう。
これらの特定のファイルが存在するメディアであれば、 それがブートローダを読み込んだメディアと異なるメディアであっても、 構わず圧縮ディスクイメージをマウントして Linux が起動する。 だから例えば PXE でネットワーク経由 (tftp) で Knoppix のカーネルと initrd を読み込んで、 Knoppix CD メディアから起動させる、といったようなこともできる。 つまり、 カーネルが起動するまで認識できないデバイス (BIOS が USB 接続された CD/DVD ドライブを認識できない場合など) から起動させることが可能になる。
どのように自メディアを確認しているかは initrd の中の /linuxrc を読めば分かるのだが、 サイズ削減のためにカーネルの機能を絞っている場合があるので注意が必要である。 例えばINSERT v1.3.9b の場合、 カーネルが VFAT ファイルシステムをサポートしているにもかかわらず、 「Codepage 437」(VFAT ファイルシステムのデフォルト) をサポートしていないので、 VFAT ファイルシステムをマウントしようとしても失敗してしまう。 つまり圧縮ディスクイメージを VFAT ファイルシステム上に置くことができない。 /linuxrc 中には、
case "$fs" in vfat) # We REALLY need this for INSERT on DOS-filesystems shortname="shortname=winnt" [ -n "$options" ] && options="$options,$shortname" || options="-o $shortname" ;; esac mount -t $fs $options $1 $2 >/dev/null 2>&1 && return 0
「INSERT on DOS-filesystems」という記述があるにもかかわらず、 カーネルに「Codepage 437」機能を組み込んでいないのはバグだと思われる。 このバグを回避するため、INSERT を USB メモリに入れるのであれば、 (1) USB メモリ全体を (FAT ではなく) ext2 でフォーマットするか、あるいは (2) USB メモリに複数のパーティションを作って、 圧縮ディスクイメージ INSERT を置くパーティションは ext2 でフォーマットする、 などとして カーネルがマウントできるファイルシステム (つまり ext2) 上に、 圧縮ディスクイメージを置く必要がある。 (1) の場合は、ブートローダとして extlinux を使えばよい。 ただし PC によっては、 FAT 以外でフォーマットした USB メモリではブートできない場合もあるので、 (2) のほうがお勧め。
さて、 ステップ 1. の BIOS によるブートローダの実行であるが、 大半の 1CD Linux では CD のブートローダとして isolinux が使われている。 isolinux というのは syslinux に含まれる、 CD-ROM 用のブートローダ。 syslinux には以下のブートローダが含まれる:
| ブートローダ | ブートメディア |
|---|---|
| syslinux | MS-DOS/Windows FAT ファイルシステム |
| pxelinux | PXE ネットワークブート |
| isolinux | ISO9660 CD-ROM |
| extlinux | Linux ext2/ext3 ファイルシステム |
各ブートローダは、 設定ファイル (isolinux の場合であれば isolinux.cfg) の書式が共通なので、 ブートメディアを変更しても、 設定ファイルはほとんど修正する必要がない。 1CD Linux を USB メモリ (FAT ファイルシステム) に入れる場合であれば、 設定ファイルのファイル名を isolinux.cfg から syslinux.cfg に変更するだけでよい。
1CD Linux から必要なファイルを USB メモリへコピーし、 syslinux コマンドを使ってブートローダを USB メモリへ書込めば、 Linux ブート可能な USB メモリを作ることができる。
参考までに、 私が SLAX 日本語版 を アドエスに入れた例を紹介する。 まず以下のファイルを SLAX 日本語版 CD-ROM からアドエスの microSD へ (WM5torage を activate した状態で) コピーした (もちろん memtest は、使わないならコピーする必要はないし、 起動画面の画像やヘルプ画面も、表示する必要がなければ不要)。
| SLAX CD-ROM | アドエス microSD | |
|---|---|---|
| /isolinux.cfg | /boot/syslinux/syslinux.cfg | syslinux 設定ファイル |
| /boot/memtest | /boot/syslinux/memtest | memtest プログラム |
| /boot/vmlinuz | /boot/syslinux/slax/vmlinuz | カーネル |
| /boot/initrd.gz | /boot/syslinux/slax/initrd | initrd |
| /boot/splash.cfg | /boot/syslinux/slax/splash.cfg | SLAX 起動画面 |
| /boot/splash.lss | /boot/syslinux/slax/splash.lss | SLAX 起動画面の画像 |
| /boot/splash.txt | /boot/syslinux/slax/splash.txt | F1 を押したときのヘルプ画面 |
| /boot/splash2.txt | /boot/syslinux/slax/splash2.txt | F2 を押したときのヘルプ画面 |
| /livecd.sgn | /livecd.sgn | SLAX チェック用ファイル |
| /base/* | /base/* | SLAX のベースモジュール |
| /modules/* | /modules/* | SLAX のモジュール |
syslinux 3.35 から、 設定ファイルをメディアのルートディレクトリだけでなく、 /boot/syslinux ないし /syslinux にも 置くことができるようになった。 microSD のルートディレクトリにたくさんのファイルを置くと混乱の元なので、 /boot/syslinux に置くことにした。 この場合、設定ファイルに相対パス名を書くときは、 設定ファイルを置いたディレクトリからの相対パスとなる。
SLAX CD-ROM の isolinux.cfg は、 カーネルのパス名などを相対パス名で指定しているので適宜修正する。 修正ついでということで、 SLAX 関係のファイルを /boot/syslinux/slax にまとめることにした。 こうすることにより SLAX 以外の 1CD Linux を同居させる際に混乱せずに済む (Knoppix, Damn Small Linux, Puppy Linux, SLAX を全て一本の USB メモリに 入れることも可能)。
また、SLAX 起動画面 splash.cfg は、 ファイル中に起動画面の画像 (四葉のクローバーの絵) splash.lss へのパスを指定しているので、 これも適宜修正する。
ブートローダの書き込みは、 Windows マシンで以下のように実行:
syslinux -ma -d /boot D:
「-ma」は、 「D:」ドライブ (USB フラッシュメモリのドライブ名) に MBR (マスターブートレコード) を書込むための「-m」オプションと、 そのパーティションをアクティブにするための「-a」オプションの指定。 Linux 上で syslinux コマンドを使ってブートローダを書込む場合は、 「-m」オプションが指定できないので、 別途 (dd コマンド等で) MBR を書込む必要がある。
「-d /boot」はブートローダ本体である「ldlinux.sys」を 書込むディレクトリの指定。 どこでもいいのであるが、まあ /boot あたりが無難だろう。 このコマンドを実行すると、 「/boot/ldlinux.sys」というファイルが作られる。
このブートローダは、設定ファイル syslinux.cfg を、 (/, /boot/syslinux, /syslinux の中から) 自動的に探してくれるので、 syslinux.cfg を編集したとしてもブートローダを再度書込む必要はない。 だから、別の 1CD Linux をこの USB メモリに同居させようとする場合は、 カーネルと initrd と圧縮ディスクイメージを適当なディレクトリへコピーし、 syslinux.cfg に必要な変更を加えるだけでよい。