dump解析(1) 二の巻
さて、前回、buffer_headを特定したものの、なぜこのbuffer_headがロックされたままとなっているのか分かりません。
さらに調べを進めていきたいと思います。
__wait_on_buffer()でなぜ待ちつづけるかというと、__wait_on_buffer()内のsync_buffer()でバッファのロックが解除されないからです。
では、sync_buffer()を調べてみましょう。
-----
fs/buffer.c
static void sync_buffer(struct buffer_head *bh)
{
struct block_device *bd;
smp_mb();
bd = bh->b_bdev;
if (bd)
blk_run_address_space(bd->bd_inode->i_mapping);
}
-----
ここで、b_bdevは、前回、0xf7f10a80が入っていましたので、blk_run_address_space()が実行されるはずです。そこで、bd->bd_inode->i_mappingを調べてみます。
----
crash> struct block_device 0xf7f10a80
struct block_device {
bd_dev = 9437185,
bd_inode = 0xf7f10af4,
bd_openers = 1,
-----
さらにbd_inodeを調べます。
------
crash> struct inode 0xf7f10af4
struct inode {
i_hash = {
next = 0x0,
pprev = 0xf54527f4
},
...略 ...
i_op = 0xc046cae0,
i_fop = 0xc046cb40,
i_sb = 0xf7f47200,
i_flock = 0x0,
i_mapping = 0xf7f10ba4,
i_data = {
host = 0xf7f10af4,
page_tree = {
height = 4,
gfp_mask = 544,
rnode = 0xf620be38
},
--------
i_mapping=0xf7f10ba4が入っていますので、さらに進んで
-----
static inline void blk_run_address_space(struct address_space *mapping)
{
if (mapping)
blk_run_backing_dev(mapping->backing_dev_info, NULL);
}
------
ということになります。mapping->backing_dev_infoを調べてみます。
-----
crash> struct address_space 0xf7f10ba4
host = 0xf7f10af4,
...
backing_dev_info = 0xf74acec8,
...
-----
このbacking_dev_infoを使うのは、blk_run_backing_dev()です。
-----
static inline void blk_run_backing_dev(struct backing_dev_info *bdi,
struct page *page)
{
if (bdi && bdi->unplug_io_fn)
bdi->unplug_io_fn(bdi, page);
}
----
どこまでも地道な作業が進みます...。
----
crash> struct backing_dev_info 0xf74acec8
struct backing_dev_info {
ra_pages = 32,
state = 0,
memory_backed = 0,
congested_fn = 0,
congested_data = 0x0,
unplug_io_fn = 0xc022446f <blk_backing_dev_unplug>,
unplug_io_data = 0xf74acd80
}
-----
ようやくデバイスのリクエストキューの部分まで来ました。ちなみにここで、*pageはNULLです。
------
static void blk_backing_dev_unplug(struct backing_dev_info *bdi,
struct page *page)
{
request_queue_t *q = bdi->unplug_io_data;
/*
* devices don't necessarily have an ->unplug_fn defined
*/
if (q->unplug_fn)
q->unplug_fn(q);
}
------
上記関数内の
-----
request_queue_t *q = bdi->unplug_io_data;
-----
これがI/Oリクエストキューであることが判明しました。
----
unplug_io_data = 0xf74acd80
-----
それならば、リクエストキューの中身を確認します。
-----
crash> struct request_queue_t 0xf74acd80
struct request_queue_t No struct type named request_queue_t.
----
エ、エラーでした。
気を取り直して、
-----
$ cd include/linux
$ grep request_queue_t *
blkdev.h:typedef struct request_queue request_queue_t;
-----
ということで、request_queue型が正しいようなので、改めて、
-----
crash> struct request_queue 0xf74acd80
struct request_queue {
queue_head = {
next = 0x0,
prev = 0x0
},
lasstruct request_queue {
queue_head = {
next = 0x0,
prev = 0x0
},
last_merge = 0x0,
elevator = {
t_merge = 0x0,
elevator = {
... 略 ...
request_fn = 0,
back_merge_fn = 0,
front_merge_fn = 0,
merge_requests_fn = 0,
make_request_fn = 0xf883992e,
prep_rq_fn = 0,
unplug_fn = 0xf88396ef,
merge_bvec_fn = 0,
activity_fn = 0,
issue_flush_fn = 0xc026e939 <md_flush_all>,
unplug_timer = {
entry = {
next = 0x0,
prev = 0x0
},
expires = 0,
lock = {
lock = 1,
magic = 3735899821
},
magic = 1267182958,
function = 0xc0224488 <blk_unplug_timeout>,
data = 4148874624,
base = 0x0
},
unplug_thresh = 4,
unplug_delay = 3,
unplug_work = {
pending = 0,
entry = {
next = 0xf74ace90,
prev = 0xf74ace90
},
func = 0xc022447f <blk_unplug_work>,
...以下略。
-------
となっています。
-----
unplug_fn = 0xf88396ef
-----
が設定されているので、
------
if (q->unplug_fn)
q->unplug_fn(q);
------
は実行されているはずです。
------
crash> sym 0xf88396ef
f88396ef (t) raid1_unplug
------
これでようやくsync_buffer()したときに、今対象としているbuffer_headに対しては、raid1_unplug()という処理が行われるんだなぁ〜というところまでたどり着きました。
------
static void raid1_unplug(request_queue_t *q)
{
unplug_slaves(q->queuedata);
}
----
q->queuedataが必要みたいなので、再度request_queueの中身に戻って、
----
queuedata = 0xf7f2e400,
----
を得ます。
unplug_slaves()は、各RAIDレベルごとに用意されている関数なので、raid1.cのunplug_slaves()を確認します。
-----
static void unplug_slaves(mddev_t *mddev)
{
conf_t *conf = mddev_to_conf(mddev);
int i;
unsigned long flags;
spin_lock_irqsave(&conf->device_lock, flags);
for (i=0; i<mddev->raid_disks; i++) {
mdk_rdev_t *rdev = conf->mirrors[i].rdev;
if (rdev && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
spin_unlock_irqrestore(&conf->device_lock, flags);
if (r_queue->unplug_fn)
r_queue->unplug_fn(r_queue);
spin_lock_irqsave(&conf->device_lock, flags);
rdev_dec_pending(rdev, mddev);
}
}
spin_unlock_irqrestore(&conf->device_lock, flags);
}
-------
まず、*confを導くために、mddev_to_conf()を確認してみます。
------
typedef struct r1_private_data_s conf_t;
#define mddev_to_conf(mddev) ((conf_t *) mddev->private)
------
ということなので、
------
crash> struct conf_t 0xf7f2e400
struct: cannot handle "conf_t": try "gdb whatis" or "gdb ptype"
------
そういえば、さきほどconf_tはtypedefされていたので...
-----
crash> struct r1_private_data_s 0xf7f2e400
struct: cannot handle "r1_private_data_s": try "gdb whatis" or "gdb ptype"
------
まだだめです。そういえば、raid1.koをロードしていないので、structが判別できないんですね。
-----
crash> mod
MODULE NAME SIZE OBJECT FILE
f8825e80 sd_mod 20480 (not loaded) [CONFIG_KALLSYMS]
f883cb00 raid1 19584 (not loaded) [CONFIG_KALLSYMS]
.....
-----
そこで、raid1.koをロードします。
-----
crash> mod -s raid1 raid1.ko
MODULE NAME SIZE OBJECT FILE
f883cb00 raid1 19584 raid1.ko
-----
再度、confを調べます。
-----
crash> struct r1_private_data_s 0xf7f2e400
struct: cannot handle "r1_private_data_s": try "gdb whatis" or "gdb ptype"
-----
やっぱりだめです。
注: これは実はkernel-debuginfoに含まれるraid1.ko.debugをロードすれば問題なくstructコマンドで解析できることに後で気づきました。
とにかく、うまくいかなかったので、
----
crash> rd 0xf7f2e400 100
f7f2e400: f7e5d800 f883ca80 00900001 00000001 ................
f7f2e410: f7e5d880 f7e5d880 00000000 00000000 ................
-----
*mddev = f7e5d800 ということがメモリダンプから分かります。
include/linux/raid/md_k.hから
-----
typedef struct mddev_s mddev_t;
-----
となっているので、
-----
crash> struct mddev_s f7e5d800
struct mddev_s {
private = 0xf7f2e400,
pers = 0xf74a2f80,
unit = 2,
md_minor = 1,
-----
*conf = 0xf7f2e400 ということが分かります。
さらに次のルーチンで、raidのディスクごとの処理をしているので、raid_disksの
数値を探します。
-----
for (i=0; i<mddev->raid_disks; i++) {
-----
すると、
-----
layout = -135931836,
raid_disks = -135931836,
max_disks = 1,
-----
と、異常な数値になっています。
その結果、raid_disksの数値が負のため、各ディスクに対するI/O発行処理のループが実行されず、バッファのステータスが変わらなかったために、ストールが発生したと思われます。
最後は非常にあっさりしたものでしたが、そこまでにたどり着くまでは非常に地道にデータとソースを確認する作業が続くのでした。

コメント