Linuxカーネルがディスクシリアル番号を読み込む問題
従来の観点では「カーネルの中で文字列を処理しないでください」ということです.実は、確かにそうすべきだ.
Linuxカーネルのブロックデバイス駆動は、ディスクの制御チップROMに格納されたディスクのシーケンス番号を読み取る能力がある.カーネルはどのような形でこのシーケンス番号を呼び出し者に提示すべきですか?lsこのディレクトリを見てみましょう.
/dev/disk/by-id
ll/dev/disk/by-id/...
lrwxrwxrwx 1 root root 9 10月17:11 scsi-SATA_ST3500413AS_Z2A2AGQA -> ../../sdb
1つのディスクは、従来の/dev/sdXでインデックス化されてもよいし、by-YYでインデックス化されてもよい.ここで、by-idはシーケンス番号でインデックス化され、上記の出力では、下線の後ろにシーケンス番号が表示されます.同様に、hdparmツールプログラムで読み取ることができ、同じ結果を読むことができます.hdparmのコード実装では、次のコードセグメントを見ることができます.
しかし、2.6.8の古いバージョンのカーネル、例えば2.6.8のバージョンでは、do_identifyには次の呼び出しがあります.
ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
ではこのide_fixstringは何をしていますか?その実装は以下の通りであり、詳細なコメントには答えが示されています.
Linuxカーネルは最も原始的なバイナリ情報を迅速に返し、解析タスクをアプリケーションに残すべきで、効率的な考慮だけでなく、カーネルがこれらの情報をどのように解読するか分からないことが多い.幸いなことに、高バージョンのカーネルはディスクのシリアル番号を処理せず、元の情報だけを返しました.残念なことに、問題が発生しました.
仕事中に問題があったら、私はどんな設備の駆動を振り回すほど暇ではありません.システムはカーネルをアップグレードするだけですが、アップグレード前後にディスクのシリアル番号と保存されたシリアル番号の比較が必要です.古いバージョンのカーネルと新しいバージョンのカーネルのディスクのシリアル番号の読み取り動作の違いによって、カーネルはアプリケーションに透明ではありません.どうする?古いバージョンのエラーに対応するために、高バージョンのカーネルドライバを修正するしかありません.
互換性は大きな万人の穴で、どれだけのエリートを埋葬したのか分からない.
Linuxカーネルのブロックデバイス駆動は、ディスクの制御チップROMに格納されたディスクのシーケンス番号を読み取る能力がある.カーネルはどのような形でこのシーケンス番号を呼び出し者に提示すべきですか?lsこのディレクトリを見てみましょう.
/dev/disk/by-id
ll/dev/disk/by-id/...
lrwxrwxrwx 1 root root 9 10月17:11 scsi-SATA_ST3500413AS_Z2A2AGQA -> ../../sdb
1つのディスクは、従来の/dev/sdXでインデックス化されてもよいし、by-YYでインデックス化されてもよい.ここで、by-idはシーケンス番号でインデックス化され、上記の出力では、下線の後ろにシーケンス番号が表示されます.同様に、hdparmツールプログラムで読み取ることができ、同じ結果を読むことができます.hdparmのコード実装では、次のコードセグメントを見ることができます.
static char *strip (char *s)
{
char *e;
while (*s == ' ') ++s;
if (*s)
for (e = s + strlen(s); *--e == ' '; *e = '\0');
return s;
}
static void dump_identity (__u16 *idw)
{
int i;
char pmodes[64] = {0,}, dmodes[128]={0,}, umodes[128]={0,};
char *model = strip(strndup((char *)&idw[27], 40));
char *fwrev = strip(strndup((char *)&idw[23], 8));
char *serno = strip(strndup((char *)&idw[10], 20));
__u8 tPIO;
printf("
Model=%.40s, FwRev=%.8s, SerialNo=%.20s", model, fwrev, serno);
...
}
は明らかで、シーケンス番号が表示されるとstripは先頭と末尾のスペースを削除します.スペースが表示されるのは意味がないからです.これは普通です.だが...しかし、2.6.8の古いバージョンのカーネル、例えば2.6.8のバージョンでは、do_identifyには次の呼び出しがあります.
ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
ではこのide_fixstringは何をしていますか?その実装は以下の通りであり、詳細なコメントには答えが示されています.
void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
{
u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
if (byteswap) {
/* convert from big-endian to host byte order */
for (p = end ; p != s;) {
unsigned short *pp = (unsigned short *) (p -= 2);
*pp = ntohs(*pp);
}
}
/* strip leading blanks */
while (s != end && *s == ' ')
++s;
/* compress internal blanks and strip trailing blanks */
while (s != end && *s) {
if (*s++ != ' ' || (s != end && *s && *s != ' '))
*p++ = *(s-1);
}
/* wipe out trailing garbage */
while (p != end)
*p++ = '\0';
}
はほとんどhdparmのstripのもっと厳格な意味での翻版です!これは何か問題がありますか.問題が大きくなった.このカーネルは、元のディスクシーケンス番号、すなわちシーケンス番号自体をユーザーに提示することはできません.なぜアプリケーションに処理を残さないのですか?Linuxカーネルは最も原始的なバイナリ情報を迅速に返し、解析タスクをアプリケーションに残すべきで、効率的な考慮だけでなく、カーネルがこれらの情報をどのように解読するか分からないことが多い.幸いなことに、高バージョンのカーネルはディスクのシリアル番号を処理せず、元の情報だけを返しました.残念なことに、問題が発生しました.
仕事中に問題があったら、私はどんな設備の駆動を振り回すほど暇ではありません.システムはカーネルをアップグレードするだけですが、アップグレード前後にディスクのシリアル番号と保存されたシリアル番号の比較が必要です.古いバージョンのカーネルと新しいバージョンのカーネルのディスクのシリアル番号の読み取り動作の違いによって、カーネルはアプリケーションに透明ではありません.どうする?古いバージョンのエラーに対応するために、高バージョンのカーネルドライバを修正するしかありません.
互換性は大きな万人の穴で、どれだけのエリートを埋葬したのか分からない.