git 使って解析

ええと git blame して arch/arm/mm/init.c に最近入った修正を確認してみます。
順に並べかえて以下。

  • b0a2679d (Russell King 2011-01-30 11:21:05 +0000
  • cae6292b (Will Deacon 2011-02-15 12:42:57 +0100
  • b2b755b5 (David Rientjes 2011-03-24 15:18:15 -0700
  • 9eb8f674 (Grant Likely 2011-04-28 14:27:20 -0600
  • 9af386c8 (Will Deacon 2011-04-28 18:44:31 +0100
  • be20902b (Russell King 2011-05-11 15:39:00 +0100
  • 3522b5bc (Will Deacon 2011-05-19 13:21:14 +0100
  • 8b6b1712 (Rabin Vincent 2011-06-02 15:01:36 +0100
  • 941b3b13 (Russell King 2011-06-11 00:43:21 +0100

ええと上記コミットの直前コミットが分からんとマズいのか。

  • b0a2679d の直前は 5f2c1b30
  • cae6292b の直前は ad6b9c9d
  • b2b755b5 の直前は 436c3b66
  • 9eb8f674 の直前は 4c2896e8
  • 9af386c8 の直前は 557d97d5
  • be20902b の直前は 2fb3ec5c
  • 3522b5bc の直前は db82c8f7
  • 8b6b1712 の直前は 408cb075
  • 941b3b13 の直前は 5dc1a968

これ、手動で控えたんですがなんか良い方法は無いんかな。とりあえず diff を見てみます。

$ git diff 5f2c1b30 b0a2679d
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 5164069..cddd684 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -297,6 +297,12 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
        memblock_reserve(__pa(_stext), _end - _stext);
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
+       if (phys_initrd_size &&
+           memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
+               pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+                      phys_initrd_start, phys_initrd_size);
+               phys_initrd_start = phys_initrd_size = 0;
+       }
        if (phys_initrd_size) {
                memblock_reserve(phys_initrd_start, phys_initrd_size);
 
$

ええと、確認してみたんですが、どうも id は二つ渡さないとダメみたいですね。
commit なナニは

$ git log|grep ^commit

で何とかなるので大丈夫っちゃ大丈夫なのかなぁ。で、

$ git log b0a2679d

した時のメセジが以下。

commit b0a2679d27408d97ce31e5f800b44227d3388b84
Author: Russell King <rmk+kernel@arm.linux.org.uk>
Date:   Sun Jan 30 11:21:05 2011 +0000

    ARM: initrd: disable initrd if passed address overlaps reserved region
    
    Disable the initrd if the passed address already overlaps the reserved
    region.  This avoids oopses on Netwinders when NeTTrom tells the kernel
    that an initrd is located at mem+4MB, but this overlaps the BSS,
    resulting in the kernels in-use BSS being freed.
    
    This should be applied to v2.6.37-stable.
    
    Cc: <stable@kernel.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

とりあえず一つづつ見てみます。とりあえず memblock_is_region_reserved からなのですが、

int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
{
	return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;
}

手続き掘る前に memblock という変数について確認。定義はいっちゃん上。

struct memblock memblock __initdata_memblock;

struct memblock 型の定義はというと以下。関連するソレを一気に列挙。

struct memblock_region {
	phys_addr_t base;
	phys_addr_t size;
};

struct memblock_type {
	unsigned long cnt;	/* number of regions */
	unsigned long max;	/* size of the allocated array */
	struct memblock_region *regions;
};

struct memblock {
	phys_addr_t current_limit;
	phys_addr_t memory_size;	/* Updated by memblock_analyze() */
	struct memblock_type memory;
	struct memblock_type reserved;
};

extern struct memblock memblock;

extern してるな。そりゃ良いとして

  • struct memblock 型の reserved 属性使ってます
  • memblock_type 構造体の属性は以下な意味?
    • memblock_region 構造体の配列
    • 配列の最大サイズ
    • 何個格納されてるか
  • ちなみに memblock_region は先頭位置とサイズを属性として持ってる (はず)

これを前提に掘削したらなんとなく分かるはず。ええと memblock_overlaps_region 手続きの定義が以下?

long __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
{
	unsigned long i;

	for (i = 0; i < type->cnt; i++) {
		phys_addr_t rgnbase = type->regions[i].base;
		phys_addr_t rgnsize = type->regions[i].size;
		if (memblock_addrs_overlap(base, size, rgnbase, rgnsize))
			break;
	}

	return (i < type->cnt) ? i : -1;
}

なんとなく配列を手繰って overlap してるかどうかを見てるように読めます。ん、全ての要素について、memblock_addrs_overlap が偽を戻すケイスだと -1 を戻すはずなんですが、とか i が 0 の時に偽を戻したら 0 が戻るけど、とか思ってしまったのですが、一つ上の memblock_is_region_reserved 手続きで 0 以上なら真が戻る形になってますね。
ということは

  • memblock_addrs_overlap が一つでも偽を戻す場合は memblock_is_region_reserved は 0 以上の値を戻す
    • 渡された base と size な領域が overlap してたら予約されてます、という意味か
  • memblock_addrs_overlap が全部真を戻す場合は memblock_is_region_reserved は -1 を戻す
    • overlap してないので予約はされていない、ということか

謎なのは memblock な領域です。ちなみに今着目してる diff な部分ですが、arm_memblock_init という手続きですね。memblock って何なのだろう。これを操作する一連の手続き定義は arch/arm の下などではありませんね。

呼び出しもと

arch/arm/kernel/setup.c の setup_arch 手続きですね。

	arm_memblock_init(&meminfo, mdesc);

うーん、微妙な変数があるなぁ。おそらくは arch/asm/include/asm/setup.h の以下かと。

struct membank {
	phys_addr_t start;
	unsigned long size;
	unsigned int highmem;
};

struct meminfo {
	int nr_banks;
	struct membank bank[NR_BANKS];
};

extern struct meminfo meminfo;

実体はどこで定義されてるんだ。って探し回ってたら arch/asm/mm/init.c でした。
この meminfo の bank 属性に格納されてる membank 構造体の start 属性な順に並びかえられた後に memblock に格納されるのか。ということはこの meminfo の出自がポイントになってくるのかどうか。

ちょっとストップ

以下に目を通してみます。

他、何か良い材料を探してみる方向で。