之前编译过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的方式从零进行配置,我估计也能成功了吧。
此文算做是小小的总结吧。