SVX日記
2008-07-03(Thu) Fedora9、SSDチューン
……というのがネックである。特にチョットずつアチコチに書き込む、という処理が苦手で、これは避けがたい事実である。一方でSLCタイプのフラッシュは、ほとんどHDDと遜色ない性能を発揮するので、連続書き込みのアドバンテージが際だつことから、あらゆる面でHDDを圧倒、という印象になる。
近年のOSには、もれなくディスクへの書き出しを遅延する機能が備わっている。例えば、文書を保存、とかやって、保存完了、と画面に出ても、その時点ではディスクには書き込まれていないのだ。OSは、書き込まなければならない内容をメモリ上に覚えておいて、ワザと、しばらく放置しておくのであった。
この動作は、保存した直後に、誤字に気づいて修正し、再保存されるような状況に効果を発揮する。修正後の内容を一度だけ書き込みば済むからだ。また、ファイルが削除される場合にも有効だ。書き込み自体をやめてしまうことができる。
つまり「ドカンと書き込むと、30秒後に、実際にドカンと書き込まれる」ということだ。書き込み能力の低いメディアにドカンと書くと、長時間、書き込み以外の仕事ができなくなってしまい、結果として、読みたい人が待たされてしまうことになる。書くのと違って、読めないと処理が先に進まない。これが、レスポンスの低下として表面化する。
ここで、スルドいLinuxマスターは「そんなコトできたっけ?」と思うだろうが、普通はそんなコトはできない。しかし、オープンソースなら、改造してしまえばいいのだ。つまりは、オリジナルカーネルをビルドしてしまうのである。
具体的には「mm/page-writeback.c」の改造である。dirty(ディスクに未書き出し)ページをゆっくりwriteback(書き出し)するようにする。一度にwritebackするページ数はMAX_WRITEBACK_PAGESという定数で1024に設定されているが、これをprocファイルシステムから可変化してしまう。
それ以外にも、dirtyページのメモリに占める割合が一定(dirty_ratio:デフォルト10%)を超えた状態を契機にwritebackを開始するものもある。この処理はbalance_dirty_pages関数で行われるので、以後、この動作をbalanceモードと呼ぶ。
各々、MAX_WRITEBACK_PAGESを最大処理ページ数としてwritebackするが、dirtyページが多い場合は即座にwritebackが繰り返される。書き込みが混雑している(congestion)と判断された場合、繰り返しごとに(HZ/10:0.1秒)ずつ、ウェイトが入るものの、これだけではジョロジョロとした書き込みにはならず、やはりドカンという感じになってしまう。
dirty_writeback_centisecs(500): kupdate, bdflushモードの起動周期(1/100sec)
dirty_expire_centisecs(3000): dirtyページの存在時間(1/100sec)(kupdateの動作契機)
dirty_background_ratio(5): bdflushモードの動作契機(%)
dirty_ratio(10): balanceモードの動作契機(%)
kupdate_max_writeback_pages(1024): kupdateモードの最大処理数(Page)(MAX_WRITEBACK_PAGESの可変化)
bdflush_max_writeback_pages(1024): bdflushモードの最大処理数(Page)(MAX_WRITEBACK_PAGESの可変化)
kupdate_writeback_once(0): kupdateモードの連続writeback抑制(Boolean)
bdflush_writeback_once(0): bdflushモードの連続writeback抑制(Boolean)
kupdate_congestion_wait(100): kupdateモードの書き込み混雑時のウェイト(ms)
bdflush_congestion_wait(100): bdflushモードの書き込み混雑時のウェイト(ms)
balance_congestion_wait(100): balanceモードの書き込み混雑時のウェイト(ms)
kupdate_call_count: kupdateモードの起動回数
bdflush_call_count: bdflushモードの起動回数
balance_call_count: balanceモードの起動回数
kupdate_writeback_count: kupdateモードのwriteback処理回数
bdflush_writeback_count: bdflushモードのwriteback処理回数
balance_writeback_count: balanceモードのwriteback処理回数
この機能を追加するのが以下のパッチ。一応、kernel-2.6.25.6-55.fc9.src.rpm用。linux-2.6-add-writeback-throttle.patchというパッチ名で保存しておこう。
diff -U 3 -r linux-2.6.25.i386.org/drivers/mmc/core/mmc.c linux-2.6.25.i386/drivers/mmc/core/mmc.c
--- linux-2.6.25.i386.org/drivers/mmc/core/mmc.c 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/drivers/mmc/core/mmc.c 2008-07-03 12:31:22.000000000 +0900
@@ -509,6 +509,7 @@
mmc_claim_host(host);
if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
+ printk(KERN_INFO "mmc_core: deselected mmc card for suspend.\n");
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -527,7 +528,9 @@
BUG_ON(!host->card);
mmc_claim_host(host);
+/* msleep(1000); */
err = mmc_init_card(host, host->ocr, host->card);
+ printk(KERN_INFO "mmc_core: reinitialised mmc card for resume. state=%d.\n", err);
mmc_release_host(host);
if (err) {
diff -U 3 -r linux-2.6.25.i386.org/drivers/mmc/core/sd.c linux-2.6.25.i386/drivers/mmc/core/sd.c
--- linux-2.6.25.i386.org/drivers/mmc/core/sd.c 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/drivers/mmc/core/sd.c 2008-07-03 12:31:08.000000000 +0900
@@ -571,6 +571,7 @@
mmc_claim_host(host);
if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
+ printk(KERN_INFO "mmc_core: deselected sd card for suspend.\n");
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -589,7 +590,9 @@
BUG_ON(!host->card);
mmc_claim_host(host);
+/* msleep(1000); */
err = mmc_sd_init_card(host, host->ocr, host->card);
+ printk(KERN_INFO "mmc_core: reinitialised sd card for resume. state=%d.\n", err);
mmc_release_host(host);
if (err) {
diff -U 3 -r linux-2.6.25.i386.org/drivers/mmc/host/sdhci.c linux-2.6.25.i386/drivers/mmc/host/sdhci.c
--- linux-2.6.25.i386.org/drivers/mmc/host/sdhci.c 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/drivers/mmc/host/sdhci.c 2008-07-03 07:46:09.000000000 +0900
@@ -1184,7 +1184,7 @@
if (!chip)
return 0;
- DBG("Suspending...\n");
+ printk(KERN_INFO DRIVER_NAME ": Suspending...\n");
for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i])
@@ -1221,7 +1221,7 @@
if (!chip)
return 0;
- DBG("Resuming...\n");
+ printk(KERN_INFO DRIVER_NAME ": Resuming...\n");
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
diff -U 3 -r linux-2.6.25.i386.org/include/linux/sysctl.h linux-2.6.25.i386/include/linux/sysctl.h
--- linux-2.6.25.i386.org/include/linux/sysctl.h 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/include/linux/sysctl.h 2008-07-03 08:02:36.000000000 +0900
@@ -205,6 +205,25 @@
VM_PANIC_ON_OOM=33, /* panic at out-of-memory */
VM_VDSO_ENABLED=34, /* map VDSO into new processes? */
VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */
+
+ VM_BDFLUSH_MAX_WRITEBACK_PAGES=36,
+ VM_KUPDATE_MAX_WRITEBACK_PAGES=37,
+
+ VM_BALANCE_CALL_COUNT=38,
+ VM_BDFLUSH_CALL_COUNT=39,
+ VM_KUPDATE_CALL_COUNT=40,
+
+ VM_BALANCE_WRITEBACK_COUNT=41,
+ VM_BDFLUSH_WRITEBACK_COUNT=42,
+ VM_KUPDATE_WRITEBACK_COUNT=43,
+
+ VM_BALANCE_CONGESTION_WAIT=44,
+ VM_BDFLUSH_CONGESTION_WAIT=45,
+ VM_KUPDATE_CONGESTION_WAIT=46,
+
+ VM_BDFLUSH_WRITEBACK_ONCE=47,
+ VM_KUPDATE_WRITEBACK_ONCE=48,
+ VM_KUPDATE_SYNC_SUPERS=49,
};
diff -U 3 -r linux-2.6.25.i386.org/include/linux/writeback.h linux-2.6.25.i386/include/linux/writeback.h
--- linux-2.6.25.i386.org/include/linux/writeback.h 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/include/linux/writeback.h 2008-07-03 08:02:29.000000000 +0900
@@ -105,6 +105,25 @@
extern int block_dump;
extern int laptop_mode;
+extern int bdflush_max_writeback_pages;
+extern int kupdate_max_writeback_pages;
+
+extern int balance_call_count;
+extern int bdflush_call_count;
+extern int kupdate_call_count;
+
+extern int balance_writeback_count;
+extern int bdflush_writeback_count;
+extern int kupdate_writeback_count;
+
+extern int balance_congestion_wait;
+extern int bdflush_congestion_wait;
+extern int kupdate_congestion_wait;
+
+extern int bdflush_writeback_once;
+extern int kupdate_writeback_once;
+extern int kupdate_sync_supers;
+
extern int dirty_ratio_handler(struct ctl_table *table, int write,
struct file *filp, void __user *buffer, size_t *lenp,
loff_t *ppos);
diff -U 3 -r linux-2.6.25.i386.org/kernel/sysctl.c linux-2.6.25.i386/kernel/sysctl.c
--- linux-2.6.25.i386.org/kernel/sysctl.c 2008-07-02 15:58:31.000000000 +0900
+++ linux-2.6.25.i386/kernel/sysctl.c 2008-07-03 08:06:14.000000000 +0900
@@ -951,6 +951,118 @@
.proc_handler = &proc_dointvec_userhz_jiffies,
},
{
+ .ctl_name = VM_BDFLUSH_MAX_WRITEBACK_PAGES,
+ .procname = "bdflush_max_writeback_pages",
+ .data = &bdflush_max_writeback_pages,
+ .maxlen = sizeof(bdflush_max_writeback_pages),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_MAX_WRITEBACK_PAGES,
+ .procname = "kupdate_max_writeback_pages",
+ .data = &kupdate_max_writeback_pages,
+ .maxlen = sizeof(kupdate_max_writeback_pages),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BALANCE_CALL_COUNT,
+ .procname = "balance_call_count",
+ .data = &balance_call_count,
+ .maxlen = sizeof(balance_call_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BDFLUSH_CALL_COUNT,
+ .procname = "bdflush_call_count",
+ .data = &bdflush_call_count,
+ .maxlen = sizeof(bdflush_call_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_CALL_COUNT,
+ .procname = "kupdate_call_count",
+ .data = &kupdate_call_count,
+ .maxlen = sizeof(kupdate_call_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BALANCE_WRITEBACK_COUNT,
+ .procname = "balance_writeback_count",
+ .data = &balance_writeback_count,
+ .maxlen = sizeof(balance_writeback_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BDFLUSH_WRITEBACK_COUNT,
+ .procname = "bdflush_writeback_count",
+ .data = &bdflush_writeback_count,
+ .maxlen = sizeof(bdflush_writeback_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_WRITEBACK_COUNT,
+ .procname = "kupdate_writeback_count",
+ .data = &kupdate_writeback_count,
+ .maxlen = sizeof(kupdate_writeback_count),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BALANCE_CONGESTION_WAIT,
+ .procname = "balance_congestion_wait",
+ .data = &balance_congestion_wait,
+ .maxlen = sizeof(balance_congestion_wait),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BDFLUSH_CONGESTION_WAIT,
+ .procname = "bdflush_congestion_wait",
+ .data = &bdflush_congestion_wait,
+ .maxlen = sizeof(bdflush_congestion_wait),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_CONGESTION_WAIT,
+ .procname = "kupdate_congestion_wait",
+ .data = &kupdate_congestion_wait,
+ .maxlen = sizeof(kupdate_congestion_wait),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_BDFLUSH_WRITEBACK_ONCE,
+ .procname = "bdflush_writeback_once",
+ .data = &bdflush_writeback_once,
+ .maxlen = sizeof(bdflush_writeback_once),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_WRITEBACK_ONCE,
+ .procname = "kupdate_writeback_once",
+ .data = &kupdate_writeback_once,
+ .maxlen = sizeof(kupdate_writeback_once),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = VM_KUPDATE_SYNC_SUPERS,
+ .procname = "kupdate_sync_supers",
+ .data = &kupdate_sync_supers,
+ .maxlen = sizeof(kupdate_sync_supers),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = VM_NR_PDFLUSH_THREADS,
.procname = "nr_pdflush_threads",
.data = &nr_pdflush_threads,
diff -U 3 -r linux-2.6.25.i386.org/kernel/sysctl_check.c linux-2.6.25.i386/kernel/sysctl_check.c
--- linux-2.6.25.i386.org/kernel/sysctl_check.c 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/kernel/sysctl_check.c 2008-07-03 08:07:24.000000000 +0900
@@ -136,6 +136,25 @@
{ VM_VDSO_ENABLED, "vdso_enabled" },
{ VM_MIN_SLAB, "min_slab_ratio" },
+ { VM_BDFLUSH_MAX_WRITEBACK_PAGES, "bdflush_max_writeback_pages" },
+ { VM_KUPDATE_MAX_WRITEBACK_PAGES, "kupdate_max_writeback_pages" },
+
+ { VM_BALANCE_CALL_COUNT, "balance_call_count" },
+ { VM_BDFLUSH_CALL_COUNT, "bdflush_call_count" },
+ { VM_KUPDATE_CALL_COUNT, "kupdate_call_count" },
+
+ { VM_BALANCE_WRITEBACK_COUNT, "balance_writeback_count" },
+ { VM_BDFLUSH_WRITEBACK_COUNT, "bdflush_writeback_count" },
+ { VM_KUPDATE_WRITEBACK_COUNT, "kupdate_writeback_count" },
+
+ { VM_BALANCE_CONGESTION_WAIT, "balance_congestion_wait" },
+ { VM_BDFLUSH_CONGESTION_WAIT, "bdflush_congestion_wait" },
+ { VM_KUPDATE_CONGESTION_WAIT, "kupdate_congestion_wait" },
+
+ { VM_BDFLUSH_WRITEBACK_ONCE, "bdflush_writeback_once" },
+ { VM_KUPDATE_WRITEBACK_ONCE, "kupdate_writeback_once" },
+ { VM_KUPDATE_SYNC_SUPERS, "kupdate_sync_supers" },
+
{}
};
diff -U 3 -r linux-2.6.25.i386.org/mm/page-writeback.c linux-2.6.25.i386/mm/page-writeback.c
--- linux-2.6.25.i386.org/mm/page-writeback.c 2008-04-17 11:49:44.000000000 +0900
+++ linux-2.6.25.i386/mm/page-writeback.c 2008-07-03 08:18:33.000000000 +0900
@@ -44,6 +44,25 @@
*/
#define MAX_WRITEBACK_PAGES 1024
+int bdflush_max_writeback_pages = 1024;
+int kupdate_max_writeback_pages = 1024;
+
+int balance_call_count = 0;
+int bdflush_call_count = 0;
+int kupdate_call_count = 0;
+
+int balance_writeback_count = 0;
+int bdflush_writeback_count = 0;
+int kupdate_writeback_count = 0;
+
+int balance_congestion_wait = HZ/10;
+int bdflush_congestion_wait = HZ/10;
+int kupdate_congestion_wait = HZ/10;
+
+int bdflush_writeback_once = 0;
+int kupdate_writeback_once = 0;
+int kupdate_sync_supers = 1;
+
/*
* After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
* will look to see if it needs to force writeback or throttling.
@@ -366,6 +385,8 @@
struct backing_dev_info *bdi = mapping->backing_dev_info;
+ balance_call_count++;
+
for (;;) {
struct writeback_control wbc = {
.bdi = bdi,
@@ -408,6 +429,7 @@
*/
if (bdi_nr_reclaimable) {
writeback_inodes(&wbc);
+ balance_writeback_count++;
pages_written += write_chunk - wbc.nr_to_write;
get_dirty_limits(&background_thresh, &dirty_thresh,
&bdi_thresh, bdi);
@@ -436,7 +458,7 @@
if (pages_written >= write_chunk)
break; /* We've done our duty */
- congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, balance_congestion_wait);
}
if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh &&
@@ -558,6 +580,8 @@
.range_cyclic = 1,
};
+ bdflush_call_count++;
+
for ( ; ; ) {
long background_thresh;
long dirty_thresh;
@@ -569,14 +593,17 @@
break;
wbc.more_io = 0;
wbc.encountered_congestion = 0;
- wbc.nr_to_write = MAX_WRITEBACK_PAGES;
+ wbc.nr_to_write = bdflush_max_writeback_pages;
wbc.pages_skipped = 0;
writeback_inodes(&wbc);
- min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+ bdflush_writeback_count++;
+ if (bdflush_writeback_once)
+ break;
+ min_pages -= bdflush_max_writeback_pages - wbc.nr_to_write;
if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
/* Wrote less than expected */
if (wbc.encountered_congestion || wbc.more_io)
- congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, bdflush_congestion_wait);
else
break;
}
@@ -633,7 +660,10 @@
.range_cyclic = 1,
};
- sync_supers();
+ kupdate_call_count++;
+
+ if(kupdate_sync_supers)
+ sync_supers();
oldest_jif = jiffies - dirty_expire_interval;
start_jif = jiffies;
@@ -644,15 +674,18 @@
while (nr_to_write > 0) {
wbc.more_io = 0;
wbc.encountered_congestion = 0;
- wbc.nr_to_write = MAX_WRITEBACK_PAGES;
+ wbc.nr_to_write = kupdate_max_writeback_pages;
writeback_inodes(&wbc);
+ kupdate_writeback_count++;
+ if (kupdate_writeback_once)
+ break;
if (wbc.nr_to_write > 0) {
if (wbc.encountered_congestion || wbc.more_io)
- congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, kupdate_congestion_wait);
else
break; /* All the old data is written */
}
- nr_to_write -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+ nr_to_write -= kupdate_max_writeback_pages - wbc.nr_to_write;
}
if (time_before(next_jif, jiffies + HZ))
next_jif = jiffies + HZ;
raven.itline.jp:/usr/src # rpm -ivh kernel-2.6.25.6-55.fc9.src.rpm
raven.itline.jp:/usr/src # cp linux-2.6-add-writeback-throttle.patch redhat/SOURCES/
raven.itline.jp:/usr/src/redhat/SPECS # diff -c kernel.spec kernel.my56.spec
*** kernel.spec 2008-06-10 21:54:24.000000000 +0900
--- kernel.my56.spec 2008-07-01 21:30:12.000000000 +0900
***************
*** 21,27 ****
# works out to the offset from the rebase, so it doesn't get too ginormous.
#
%define fedora_cvs_origin 619
! %define fedora_build %(R="$Revision: 1.674 $"; R="${R%% \$}"; R="${R##: 1.}"; expr $R - %{fedora_cvs_origin})
# base_sublevel is the kernel version we're starting with and patching
# on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base,
--- 21,27 ----
# works out to the offset from the rebase, so it doesn't get too ginormous.
#
%define fedora_cvs_origin 619
! %define fedora_build %(R="$Revision: 1.675 $"; R="${R%% \$}"; R="${R##: 1.}"; expr $R - %{fedora_cvs_origin})
# base_sublevel is the kernel version we're starting with and patching
# on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base,
***************
*** 689,694 ****
--- 689,696 ----
# get rid of imacfb and make efifb work everywhere it was used
Patch2600: linux-2.6-merge-efifb-imacfb.patch
+ Patch3000: linux-2.6-add-writeback-throttle.patch
+
%endif
BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
***************
*** 1254,1259 ****
--- 1256,1263 ----
# get rid of imacfb and make efifb work everywhere it was used
ApplyPatch linux-2.6-merge-efifb-imacfb.patch
+ ApplyPatch linux-2.6-add-writeback-throttle.patch
+
# ---------- below all scheduled for 2.6.24 -----------------
# END OF PATCH APPLICATIONS
raven.itline.jp:/usr/src # vi redhat/SOURCES/config-generic
raven.itline.jp:/usr/src/redhat/SOURCES # diff -c config-generic.org config-generic
*** config-generic.org 2008-05-20 17:19:52.000000000 +0900
--- config-generic 2008-07-03 12:47:22.000000000 +0900
***************
*** 104,110 ****
CONFIG_MMC_BLOCK_BOUNCE=y
CONFIG_SDIO_UART=m
# CONFIG_MMC_DEBUG is not set
! # CONFIG_MMC_UNSAFE_RESUME is not set
CONFIG_MMC_BLOCK=m
CONFIG_MMC_RICOH_MMC=m
CONFIG_MMC_SDHCI=m
--- 104,110 ----
CONFIG_MMC_BLOCK_BOUNCE=y
CONFIG_SDIO_UART=m
# CONFIG_MMC_DEBUG is not set
! CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_BLOCK=m
CONFIG_MMC_RICOH_MMC=m
CONFIG_MMC_SDHCI=m
ちなみに、冒頭の「エラくハマっていた」のは、ここでスケベ心を出して、このconfig-genericの修正も、パッチファイルに含めてしまおうとした結果であった。パッチは「config-generic等を元に、最終的なconfigが生成された『後』で当たる」のである。つまり、どんなにガンバってもCONFIG_MMC_UNSAFE_RESUMEはセットされないのである。
よって、config-genericは「直接に書き換える」こと。オイラはこれに気づくまで、何度もSDカードのパーティションテーブルをぶっ壊しては、復旧しては、mmcドライバにデバッグ行を追加しては、カーネルのコンパイルを繰り返しては……と、地獄を這い回りまくっていた。おかげで、ファイルシステムに詳しくなり、mmcドライバの処理の大半が頭に入ってしまったぞ。
raven.itline.jp:/usr/src # time rpmbuild -ba --target=i686 --with baseonly --without debuginfo /usr/src/redhat/SPECS/kernel.my56.spec