ダンプ内のSPINLOCK
あるカーネルダンプのスタックが次のようになっているとします。
-----
#2 [f7fedde0] call_usermodehelper at c0130dc4
[RA: c01c0a37 SP: f7fedde4 FP: f7fede7c SIZE: 156]
f7fedde4: f66a3d80 c011e39b 00000001 f7b8bc6c
f7feddf4: f7ed4010 c0130cb6 f7fede2c f7ed4000
f7fede04: 00000000 00000000 00000000 00000001
f7fede14: dead4ead 4b87ad6e 00000000 00000000
f7fede24: 00000000 f7fff080 f7fede4c c0327c80
f7fede34: f7fede90 f66a3d80 00000000 00000000
f7fede44: 00000000 ffffffff 00000000 00000001
f7fede54: dead4ead f7feddbc f7feddbc f72ad819
f7fede64: c03430c0 c01c2d63 c03430b0 f66a3d80
f7fede74: f72ad83c c03430c0 c01c0a37
-------------
これは先日の説明したcall_usermodehelper()のスタックです。
上のスタック中に気になる数値 "dead4ead"が出てきます。
気になったときは、とりあえずカーネルソースをgrepです。
--------
asm-i386/spinlock.h:# SPINLOCK_MAGIC 0xdead4ead
asm-x86_64/spinlock.h:#define SPINLOCK_MAGIC 0xdead4ead
--------
どうやらspinlockに関連する数値のようです。
そこで、kernel/include/asm-i386/spinlock.hを覗いてみます。
----------
typedef struct {
volatile unsigned int lock;
#ifdef CONFIG_DEBUG_SPINLOCK
unsinged magic;
#endif
}
#define SPINLOCK_MAGIC 0xdead4ead
#ifdef CONFIG_DEBUG_SPINLOCK
#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC
#else
#define SPINLOCK_MAGIC_INIT /* */
#endif
#define SPIN_LOCK_UNLOCKED (spinlock_t) {1 SPINLOCK_MAGIC_INIT }
#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
------------
以上の定義になっています。
SPIN_LOCK_UNLOCKEDを分解すると、
#define SPIN_LOCK_UNLOCKED (spinlock_t) {1 , SPINLOCK_MAGIC(0xdead4ead)}
となります。
さらにスピンロックを初期化するspin_lock_init()は、次のように定義されています。
#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
つまり、カーネルでCONFIG_DEBUG_SPINLOCKが定義されているとき、スピンロックで使われるspinlock_tの構造体は、(1, dead4ead)という数値で初期化されることがわかります。
したがって、カーネルダンプ中にdead4eadという数値が出てくれば、そこは初期化されたスピンロックを表す変数のメモリ領域であることがわかります。
このdead4eadという数値は、OS稼動中に変更されることはありませんので、ダンプファイルを見る際に、そこにスピンロックの構造があることにすぐ気づくようになります。
何か探し物をする手がかりになると思いますので、dead4eadをキーワードとして覚えておきましょう。
もちろんMIRACLE V4.0のカーネルはCONFIG_DEBUG_SPINLOCKがONになっていますので、ダンプを調査する際の大きな手がかりとなります。
みなさんもカーネルダンプ内をdead4eadで探し回って見てはいかがでしょうか。

質問です。dead4eadがあると、spinlock()でシステムがハングしているという兆候になるのでしょうか?
dead4eadが見つかってから、それをどう解釈するか、どーゆー問題があるのか、みたいな解剖の方法についての解説を期待しています。
投稿: hyoshiok | 2006年7月12日 (水) 08:08
spinlock_tは
typedef struct {
volatile unsigned int lock;
unsinged magic;
}
という形式なので、メモリ上では、
f7fede10: 00000001 <-- ロックの値
f7fede14: dead4ead <-- マジックナンバー
となります。
ロック値は、初期値が1で、誰かがspinlock()に成功すると0になるため、マジック番号の直前のアドレスの値を見ると、誰かがロックを取っているかどうかは分かります。
ただ、それがデッドロックの検出にすぐに役立つわけではないと思います。
spinlockの実装については、ひらメソッドのここら辺が良いかと思います。
http://hira.main.jp/wiki/pukiwiki.php?_raw_spin_lock%28%29%2Flinux2.6
投稿: やすま | 2006年7月12日 (水) 09:37
MIRACLE LINUX V4.0 ではなく 2.6.16.18 を見ていると
#ifdef CONFIG_DEBUG_SPINLOCK
# define SPIN_LOCK_UNLOCKED \
(spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \
.magic = SPINLOCK_MAGIC, \
.owner = SPINLOCK_OWNER_INIT, \
.owner_cpu = -1 }
かつ
static inline void debug_spin_lock_after(spinlock_t *lock)
{
lock->owner_cpu = raw_smp_processor_id();
lock->owner = current;
}
となっています。
なもんで、マジックナンバーの直後を見ればロックを掴んでるタスクが特定できるので、デッドロックを探す頼りにはなります。
しかし、コストの高いロックになっちゃってますね。
http://blog.miraclelinux.com/ctd/2006/06/post_05f1.html に書いとくべきでした。
投稿: いからし | 2006年7月12日 (水) 23:53
カーネルの障害の2大パターンはクラッシュとハングだとすると、クラッシュの方はクラッシュダンプから地道にバグを解析するわけですが、ハングの場合は、誰がロックを握っているかわかれば道半ばというか8合目位までは到着しちゃったようなものではないでしょうか?その意味でこのマジックナンバーからハングの原因を特定できるというのはすごいヒントだと思います。
投稿: hyoshiok | 2006年7月13日 (木) 16:35