之前編譯過Linux 2.4.10版本的內核,很好編譯,中間曾經漏下了SCSI low-level drivers下的BusLogic SCSI support選項導致沒法啟動系統,後來打開該選項後就行了,隨手關閉一些沒用的選項後編譯速度非常快,30秒之內完成編譯。當初以為內核編譯也不過如此,直到這四天開始編譯更新的內核才讓我吃了大虧。
我起初的想法是編譯一個極其簡潔的內核,去掉網絡、USB、光驅、等等所有沒必要的東西,只留下核心功能,越精簡越好,於是在1月21號我就下載了linux-2.6.34.tar.gz源碼包,然後開始make menuconfig配置內核,當時只想著精簡功能以便縮短編譯時間,只關注有沒有編譯錯誤,期間由於gcc 3.4兼容版和binutils 2.20版本不匹配導致了鏈接失敗,後來更新了gcc到4.4.7版本就好了。整個過程我都在關注編譯時間是否縮短,忙活了一天,效果明顯。一路精簡下去,把便宜時間縮減到了2-3分鐘左右,當時很高興,覺得要成功了。
結果到了1月22號我開始引導系統時發現根本沒法啟動,解決一個錯誤又出一個錯誤,都是關閉了不該關閉的選項造成的,最終也沒啟動成功。我知道是有些重要選項被我關了,於是想嘗試下用CentOS 6.0當前內核的配置文件來編譯下2.6.34試試,我確實也這麼做了,結果在鏈接的最後關頭提示我硬盤空間不夠,我虛擬機只分配了5G硬盤,編譯出的文件占了3G多,還有系統和源碼包占用一部分,空間不夠用了,於是遺憾放棄。
到了22號晚上,我又下載了linux-4.3.3.tar.xz內核,這次不手動精簡了,一個個去關閉選項太麻煩,我直接make allnoconfig,先將選項全部關閉再手動打開必須的選項,結果還是莫名其妙的出現錯誤,進不了系統,無數次不斷的更改配置、打開選項重新編譯還是不行,快抓狂了。
1月23號上午折騰了很長時間,但是那些錯誤還是解決不了,於是我猜測是不是我的CentOS 6.0(kernel-2.6.32-71)不適合編譯太新的內核,就在下午下載了linux-2.6.32.69.tar.xz源碼包,make allnoconfig,先將選項全部關閉再打開必須的選項,結果同樣進不了系統。
上面所有的過程不管如何解決小錯誤,最終都有幾個錯誤邁不過去:
1、No root device found.Boot has failed.sleeping forever.
2、udevadm[2371]: error getting socket: Address family not supported by protocol
udevd[2535]: error getting socket: Address family not supported by protocol
3、telinit: Failed to open socket: Function not implemented
init: rcS post-stop process (282) terminated status 1
init: kexec-disable main process (285) terminated with status 1
這次的問題不再是SCSI驅動,而是更棘手的配置問題。
至此,我終於明白一味的精簡功能這種做法本末倒置了,我的第一要務是讓系統能夠引導啟動,在此前提下再精簡功能。
1月23號下午,我給虛擬機加了一塊10G虛擬硬盤,准備好2.6.32.69的內核源代碼。
cp /boot/config-2.6.32-71.el6.i686 .config
復制系統自帶的內核配置文件,這次硬盤管夠,我看你能不能行。
yes "" | make oldconfig
使用已存在的.config的文件內容,並對新增加的選項做出默認選擇。然後make等了半個多小時才編譯完,再安裝模塊、安裝內核,又折騰了20分鐘,啟動試試,結果成功了!
再給虛擬機加一塊10G虛擬硬盤,用此方法編譯下4.3.3試試,結果也成功進入系統了。
這一次也是折騰到晚上,不過成功進入系統也就說明系統自帶的配置文件可行。
到了1月24號,我的主要任務就是在保證內核可以正常啟動的前提下不斷的精簡功能,就拿4.3.3內核動手吧,出手就把Networking support和Virtualization整個給取消了,結果編譯完進不了系統,又出現了上面的錯誤。我這次懷疑是虛擬機使用的虛擬化的一些功能沒有打開導致的,結果看了下幫助菜單,查看了Networking support的幫助信息後才發現其實是網絡模塊導致的,以前我怎麼都不會想到會由於網絡模塊的問題導致進不了系統,我一直認為網絡模塊可以直接從內核中完全剝離,結果我錯了,幫助信息中寫道:除非你真的知道你在做什麼,否則你都應該選擇Y。這是因為許多程序需要內核網絡功能的支持,即使你是在沒有連接網絡的單機上運行內核。
此句醍醐灌頂,原來是這麼回事,立馬打開Networking support選項,結果又可以進系統了。於是我小心翼翼的先關閉了網絡裡面的Wireless選項,還有其他一些硬件驅動,然後再編譯重啟,只要能進系統,就把目前的.config備份,然後繼續關閉一部分功能,若能進入系統則再把.config備份,依次迭代下去,忙活了整整一天,光備份的配置文件就有13份,期間時間過得飛快,每編譯運行一次就要花費半個多小時到四十分鐘,等待編譯以及模塊、內核的安裝期間又看了一次《黑衣人2》和《機械公敵》,截止到今天晚上7點多吃飯,我把內核精簡到了超級小巧的程度,Networking support選項裡面只剩下TCP/IP networking和Unix domain sockets了,我又把TCP/IP選項完全關掉了也沒出現故障,於是最終確定Unix domain sockets這個東西絕對不能關閉,網絡模塊之所以關掉會導致系統無法啟動,就是因為這個東西。後來查了下,這玩意兒的作用是:“UNIX Domain Socket是在socket架構上發展起來的用於同一台主機的進程間通訊(IPC),它不需要經過網絡協議棧,不需要打包拆包、計算校驗和、維護序號和應答等,只是將應用層數據從一個進程拷貝到另一個進程。”
原來是用於進程IPC的,怪不得這麼重要,直接能導致系統無法啟動。現在4.3.3的配置文件我已經把每一個選項都詳細的檢查過了,能關閉的都關閉了,剩下的選項要是再關閉系統就不能啟動了。累死我了。現在內核從make clean後單線程重新編譯需要用8分半鐘,加上-j4參數的話要快一些。看來4.3.3內核確實是更復雜了,功能更強了,便宜速度再怎麼提升都不能達到2.4.10內核的水平,2.6.32內核雖然當初沒啟動成功,但是我估計也只是差了一個Unix domain sockets選項而已,編譯時間在2-3分鐘左右應該不會差太多,所以說隨著內核的發展,編譯內核也是越來越耗費時間。完成編譯之後,make modules_install和make install這兩步在內核未精簡前各需要1-2分鐘來完成,內核精簡後這兩步都是瞬間完成,各耗時大約3秒左右。
這次的經歷也讓我翻遍了所有的內核配置選項,搜索了大量資料,了解了很多選項是干嘛的。一開始以為栽在SCSI驅動上,一直在鼓搗SCSI驅動和File systems,結果沒成想栽在了網絡相關的功能上。
經過這次動手實踐,我算是又對內核配置加深認識了,以後就算是用make allnoconfig的方式從零進行配置,我估計也能成功了吧。
此文算做是小小的總結吧。