gitでカーネルの変更点を追う

カーネルの変更を追っかけるには,カーネル開発者たちが使っているgitを使うと便利 です(gitが導入される前,2.6.11以前のコードを追うことはできませんが,本ブログの目的では問題ありません).ディストリビューションによって はパッケージが用意されていると思いますが,今回はソースからビルドしました.マニュアルをコンパイルするには,AsciiDocが必要でした.(gitのインストールについては省略)

まず,下準備として,メインラインのカーネルを手元に持ってきます.次のように実行すると,カレントディレクトリにlinux-2.6というディレクトリが作られ,最新のリポジトリがコピーされます.

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6
remote: Generating pack...
remote: Done counting 398007 objects.
remote: Deltifying 398007 objects.
remote: 100% (398007/398007) done
Indexing 398007 objects.
remote: Total 398007, written 398007 (delta 316750), reused 397174 (delta 316095)
100% (398007/398007) done
Resolving 316750 deltas.
100% (316750/316750) done
Checking files out...

100% (21275/21275) done

今回は,2.6.15から2.6.19の間に起こったcontext_switch関数の変更を追っていこうと思います.
まずは,context_switch関数はkernel/sched.cにあるとわかっているので,git diffコマンドで差分を見てみます.カーネルの各リリースには,v2.6.15のようにタグが振られています(ちなみに最新のタグはv2.6.20- rc4です).このタグを参照して,「v2.6.15..v2.6.19」と指定すれば,この間の差分を得ることができます.また, 「v2.6.15..」と指定すれば,最新版との比較になります.便利!

$ git diff v2.6.15..v2.6.19 kernel/sched.c
diff --git a/kernel/sched.c b/kernel/sched.c
index 6f46c94..3399701 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
(省略)
@@ -1660,24 +1815,34 @@ asmlinkage void schedule_tail(task_t *pr
* context_switch - switch to the new MM and the new
* thread's register state.
*/
-static inline
-task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)
+static inline struct task_struct *
+context_switch(struct rq *rq, struct task_struct *prev,
+ struct task_struct *next)
{
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;

- if (unlikely(!mm)) {
+ if (!mm) {
next->active_mm = oldmm;
atomic_inc(&oldmm->mm_count);
enter_lazy_tlb(oldmm, next);
} else
switch_mm(oldmm, mm, next);

- if (unlikely(!prev->mm)) {
+ if (!prev->mm) {
prev->active_mm = NULL;
WARN_ON(rq->prev_mm);
rq->prev_mm = oldmm;
}
+ /*
+ * Since the runqueue lock will be released by the next
+ * task (which is an invalid locking op but in the case
+ * of the scheduler it's an obvious special-case), so we
+ * do an early lockdep release here:
+ */
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
+ spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
+#endif

/* Here we just switch the register state and the stack. */
switch_to(prev, next, prev);
(省略)

差分はわかったけど,なぜこのような変更を行ったか,意図がわかりません.そこで,git logコマンドを使って,コミットログを見てみましょう.Nick Pigginさんの「sched: likely profiling」パッチとIngo Molnarさんの「lockdep: core, fix rq-lock handling on __ARCH_WANT_UNLOCKED_CTXSW」パッチがコミットされてました.

$ git log v2.6.15..v2.6.19 -p kernel/sched.c
(省略)
commit beed33a816204cb402c69266475b6a60a2433ceb
Author: Nick Piggin
Date: Wed Oct 11 01:21:52 2006 -0700

[PATCH] sched: likely profiling

This likely profiling is pretty fun. I found a few possible problems
in sched.c.

This patch may be not measurable, but when I did measure long ago,
nooping (un)likely cost a couple of % on scheduler heavy benchmarks, so
it all adds up.

Tweak some branch hints:

- the 2nd 64 bits in the bitmask is likely to be populated, because it
contains the first 28 bits (nearly 3/4) of the normal priorities.
(ratio of 669669:691 ~= 1000:1).

- it isn't unlikely that context switching switches to another process. it
might be very rapidly switching to and from the idle process (ratio of
475815:419004 and 471330:423544). Let the branch predictor decide.

- preempt_enable seems to be very often called in a nested preempt_disable
or with interrupts disabled (ratio of 3567760:87965 ~= 40:1)

Signed-off-by: Nick Piggin
Acked-by: Ingo Molnar
Cc: Daniel Walker
Cc: Hua Zhong
Signed-off-by: Andrew Morton
Signed-off-by: Linus Torvalds

diff --git a/kernel/sched.c b/kernel/sched.c
index 53608a5..094b568 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1822,14 +1822,14 @@ context_switch(struct rq *rq, struct tas
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;

- if (unlikely(!mm)) {
+ if (!mm) {
(省略)

「commit beed33a816204cb402c69266475b6a60a2433ceb」の「beed…」はコミットIDです.一つのパッチが複数の ファイルに影響をあたえることはよくあります.この値を引数にgit log コマンドを実行すれば,このパッチがinclude/asm-generic/bitops/sched.hとkernel/sched.cに対するパッ チだということがわかります.本ブログでは,変更点に対してできるだけコミットIDを併記していこうと考えています.

$ git log -p beed33a816204cb402c69266475b6a60a2433ceb
(省略)

ちなみに,2.6.15から2.6.19の間で,kernel/sched.cには102個のパッチが当たっています.Linuxカーネルは進化し続けているんですねぇ.

$ git log v2.6.15..v2.6.19 -p kernel/sched.c | grep ^commit | wc
102 204 4896

定期的にgit pullすることで,常にLinux開発の最先端を追いかけることができますが,特定のバージョンに腰を落ち着けて調べたい場合があります.今回は2.6.19ですね.このような場合には,git branchでブランチを作ります.

git pullしたてのブランチは次のようになっているはずです.先頭に「*」マークが付いているものが,作業ディレクトリのブランチです.

$ git branch
* master
origin


では,v2.6.19というブランチを作りましょう.

$ git branch v2.6.19
$ git branch
* master
origin
v2.6.19

ブランチができましたが,まだ作業ディレクトリの状態は変わっていません.git checkoutでブランチを切替えることができます.

$ git checkout v2.6.19
$ git branch
master
origin
* v2.6.19

次回は実際に変更の内容を追っていこうと思います.

最後にgitに関して参考にしたページを挙げておきます.

記事を見てコメントする | 友だちに紹介する

Tags: ,

Leave a comment