PowerBook G4の故障とその原因その6 [PowerBook G4故障のこと]
緊迫と衝撃の第6回!!
アホなこと言うとらんと、どうするかと言えば前回
- mmap()で仮想メモリを確保する
- それを全部「0」でうめる
- L2キャッシュがいっぱいになるまで繰り返す
- キャッシュから追い出されたと思われるメモリ領域をもう一度読み出して内容をチェックする
- 書いた内容と違うページがあったらそれをロックする
int main (int argc, const char * argv[]) { static const int cachesize = 512 * 1024; char **mmaptable; int ret; int n = 0, leap; int pagesize = getpagesize(); int maxsize = 1024 * 1024 * 1024 / pagesize; int leaplength = cachesize / pagesize; mmaptable = (char **)malloc(maxsize); while (n < maxsize) { fprintf(stderr, "*"); for (leap = 0 ; leap < leaplength ; leap ++) { // (1) if (mmapandfill(mmaptable + n + leap, pagesize) != OK) { fprintf(stderr, "error in mmap : %s\n", strerror(errno)); return -1; } } for (leap = 0 ; leap < leaplength ; leap ++) { // (2) if (checkmap(*(mmaptable + n + leap), pagesize) != OK) { if (mlock(*(mmaptable + n + leap), pagesize) < 0) //(3) fprintf(stderr, "error in mlock : %s\n", strerror(errno)); for (leap ++ ; leap < leaplength ; leap ++) // (4) munmap(*(mmaptable + n + leap), pagesize); while (-- n >= 0) munmap(*(mmaptable + n), pagesize); // (4) fprintf(stderr, "got a bad page and will go to sleep\n"); sleep(31536000); return 0; } } n += leaplength; } fprintf(stderr, "no memory error is found. quitting...\n"); return -1; }で、この中で呼んでるふたつの関数
static int mmapandfill(char **addrp, int pagesize) { char *bp, *addrend; *addrp = (char *)mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); // (5) if (*addrp == MAP_FAILED) return CNT; addrend = *addrp + pagesize; bp = *addrp; while (bp < addrend) { // (6) *bp = '\0'; bp ++; } return OK; } static int checkmap(char *addrp, int pagesize) { char *addrend = addrp + pagesize; while (addrp < addrend) { if (*addrp != '\0') { // (7) fprintf(stderr, "found %X\n", (unsigned int)(*addrp)); return NG; } addrp ++; } return OK; }こんなの。書き方まで行き当たりばったりになって読み辛いけど、ようするにやろうとしていることは前回と同じ、mmap()でメモリ領域を要求(5)して、問題ページをmlock()でロック(3)する。
前回は物理メモリをマップしようとしてOSに断られてうまく行かなかった。今回は、(1)のループでとにかく仮想ページを要求し続ける。そこに(6)で0を書き込む。そのあと(7)でチェックして0でないところが見つかればそのページをmlock()する。
問題のメモリ領域がどこの仮想メモリにマップされるかわからないし、書いてすぐチェックしたのではCPUのキャッシュを読み書きするだけなので、キャッシュよりも大きいバイト数を書き込んで(leaplengthページ)そのあと、チェックしている。こうすれば古いデータはキャッシュから追い出される。
さて、件のPowerBookをターゲットディスクモードにしてこれをコピーして、シングルユーザモードで立ち上げて実行した。
localhost:/ root: ./a.out & *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************found FFFFFF80 got a bad page and will go to sleepやたっ。188MBチェックし終わって捕まえた。mlock()もエラーを返してないみたいなので成功しているはず。物理メモリの前の方からmmapして行くとするとこないだのmemtestで行き着いた問題物理アドレス0x05cb3090は(前の方50MBはすでにOSが確保してしまっているので)空き領域の先頭から50MBほどのはずで、3倍余分にかかっていることになる。ちょっとおかしい気がするが、すでにページテーブルが入れ替わっているとすればあり得る。
psを見てみると
localhost:/ root: ps PID TT STAT TIME COMMAND 2 ?? Ss 0:00.07 -sh 6 ?? S 0:42.99 ./a.out 7 ?? R+ 0:00.01 ps localhost:/ root:でまだ生きていて1年間スリープに入っている。とうとう成功したか!?
いちおう確認のためもういちど走らせる。こんどは前回のが問題ページをロックしているはずなので、エラーを起こすメモリは見つからなくなっているはず。
localhost:/ root: ./a.out & *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************found FFFFFF80 got a bad page and will go to sleepありゃあ???psで確認すると
localhost:/ root: ps PID TT STAT TIME COMMAND 2 ?? Ss 0:00.07 -sh 6 ?? S 0:42.99 ./a.out 8 ?? S 0:43.01 ./a.out 9 ?? R+ 0:00.01 ps localhost:/ root:おっかしいなあ。mlock()ができてないのかなあ。しょうがないのでもういちどまえやったmemtestを動かしてみると
..... Allocated memory: 1187MB (1244761152 bytes) at local address 0x03008000 Attempting memory lock... locked successfully Partitioning memory into 2 comparison buffers... Buffer A: 593MB (622380576 bytes) starts at local address 0x03008000 Buffer B: 593MB (622380576 bytes) starts at local address 0x28194620 Running 1 test sequence... (CTRL-C to quit) Test sequence 1 of 1: Running tests on full 1187MB region... Stuck Address : setting 1 of 16testing 1 of 16 FAILURE! Data mismatch at local address 0x05dbc090 Actual Data: 0x059bc090 .....(省略)で、やっぱりエラーバイトが見つかる。おかしいなあ。でもちょっとまてよ、前回やったのと比較して
localhost:/ root: diff result.txt r2.txt > /diff.txt localhost:/ root: more /diff.txtとして一部だけ取り出してみると
..... 37,38c40,41 < FAILURE! Data mismatch at local BUFA address 0x05cb3090, BUFB address 0x2aec9ed0 < BUFA Data: 0x7fb816e6, BUFB Data: 0x7ff816e6 --- > FAILURE! Data mismatch at local BUFA address 0x05dbc090, BUFB address 0x2af486b0 > BUFA Data: 0x1dbce352, BUFB Data: 0x1d3ce352 .....ありゃ?アドレスが違ってる。しかも微妙に。どういうこと???逃げ水のようなエラー。
なにか根本的に考え方が間違ってるのかなあ?おっかしいなあ。これがうまく行ったらSystem DomainのLaunchDaemonsに登録してブートのときにこいつを立ち上げてロックしてしまおう、そのためにlaunchdのdaemonの*.plistの書き方でも勉強しようと思っていたのに....
がっかり。くやしい。これはメモリのひとつのセルが壊れた、とかいう問題じゃないのかなあ。セルだとしたら物理アドレスが変わるなんてことは無いよなあ。物理アドレスって何かの拍子に変わるのか? んなわけないよなあ。
しかしこれ、仕事でやってたら費やした工数でメモリモジュールなんかあっさり買えるな。残るは最後の手段かなあ。ひょっとしたらそれでは解決しなかったりして。
コメント 0