IT技术博客大学习 共学习 共进步

内核编译升级失败了以后的处理方案

扶凯 2010-03-24 22:29:20 浏览 3,866 次

相信有无数的人,有编译内核失败的记录, 99% 的原因就是和文件系统,硬件驱动有关,比如没有找到 SCSI 卡.但对这些问题大家都无从下手,都是乱测试.
下面我要教大家一些技巧,来帮助大家少失败些.

内核常识

我们先要了解一点.一个内核有哪些东西.

比如我们:

rpm -ql kernel

可以见到如下的信息

/boot/System.map-2.6.24.4
/boot/config-2.6.24.4
/boot/vmlinuz-2.6.24.4
/lib/modules
/lib/modules/2.6.24.4
/lib/modules/2.6.24.4/build
/lib/modules/2.6.24.4/kernel

见到没,其实没有什么东西,主要就上面几个在 boot 下的文件 ,和在 /lib/modules 下的模块文件.
System.map 内核符号映射表,顾名思义就是将内核中的符号(也就是内核中的函数)和它的地址能联系起来的一个列表。
config     内核编译的配置文件,make oldconfig 就需要使用这个文件.
vmlinuz   这就是真实的可引导的、压缩的内核。

好了,由上面我们知道,这个和系统其它东西没有关系了,所以删除一个内核也就是删除这几文件.

大家可以参考一下前些日子我写的 [Linux]编译一个 RHEL 定制的内核 rpm 包 .

Initrd 的了解和检查

我今天要讲的是最影响启动的东西 initrd .大家会想,这是什么,内核中都没有,其它这个是内核包安装完后根据每个不同的硬件生成的.硬件不一样这个不一样.下面这个是很官方的介绍:
initrd是“initial ramdisk”的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。图中的initrd- 2.4.7-10.img主要是用于加载ext3等文件系统及scsi设备的驱动。

比如,使用的是scsi硬盘,而内核vmlinuz中并没有这个scsi硬件的驱动,那么在装入scsi模块之前,内核不能加载根文件系统,但scsi模块存储在根文件系统的/lib/modules下。为了解决这个问题,可以引导一个能够读实际内核的initrd内核并用initrd修正scsi引导问题。initrd-2.4.7-10.img是用gzip压缩的文件,initrd实现加载一些模块和安装文件系统等功能。

所以我们现在知道了,如果是一个奇怪的硬件,但是不能正常使用,就是 initrd 默认没有加载,要不就是内核没有加进去.

内核启动失败后: 使用 modprobe 和 lsmod 来确认需要加载的模块

我们知道了 initrd  影响启动,那我们要怎么样来确认是不是加载全了硬件啦. initrd 很大程度上是靠 lsmod 出来的模块,还有 /etc/modprobe 的指示来做的.当然 也可以用 lspci 之类来确认.
如下

cat /etc/modprobe.conf
alias scsi_hostadapter mptbase
alias scsi_hostadapter1 mptscsi
alias scsi_hostadapter2 mptspi
alias scsi_hostadapter3 mptsas
alias scsi_hostadapter4 mptscsih
alias scsi_hostadapter5 ata_piix
# lsmod
Module                  Size  Used by
iptable_filter          7300  1
ip_tables              18132  1 iptable_filter
xt_tcpudp               7680  1
x_tables               19204  2 ip_tables,xt_tcpudp
ipv6                  245092  32

我们发现,这台机器有一些别的机器上没有的硬件,就是 mpt 的相关内容.如果在上面重新编译内核,没有加载这几个模块,就一定会启动失败.

使用原因系统本身可以正常启动的 initrd 来确认加载的模块

好了.上面还是我们看得见的,要是我们看不见,但启动失败怎么办
我们可以解开 initrd.img 来看原始加载那些模块.

cd /boot/
mkdir tmp
cp initrd*****.img tmp
cd /tmp
zcat intrd**img | cpio -id
cat  init

好了,我们主要注意下面这些内容

echo "Loading scsi_mod.ko module"
insmod /lib/scsi_mod.ko
echo "Loading sd_mod.ko module"
insmod /lib/sd_mod.ko
echo "Loading mptbase.ko module"
insmod /lib/mptbase.ko
echo "Loading mptscsi.ko module"
insmod /lib/mptscsi.ko
echo "Loading mptspi.ko module"
insmod /lib/mptspi.ko
echo "Loading mptsas.ko module"
insmod /lib/mptsas.ko
echo "Loading mptscsih.ko module"
insmod /lib/mptscsih.ko
echo "Loading jbd.ko module"
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko

根据上面这些,和你原来的,看看你是不是没有这些信息中提到的模块.没有,就快点加上吧,用这些方法处理后,99% 是能启动的,在不能启动我也帮不到你了

编译内核你可以知道的东西

为新核心重命名
我们在编译内核之前, 可以先修改Makefile中的版本信息,打开/usr/src/Linux/Makefile。在开始部分有一个变量EXTRAVERSION可以自行定义。修改这个变量,比如改成 “EXTRAVERSION=-ChinaCache”后,编译出的核心版本号就会显示成2.6.24-ChinaCache。
但实际上, 从2.6.8的版本起可在内核版本号后面添加个性化字符串. 所以也就没有必要修改Makefile了: ()  Local version - append to kernel release
如果你即修改了Makefile中的EXTRAVERSION, 又在配置时定义了local version. 那么local version所定义的字符串将位于末尾, 紧跟在EXTRAVERSION的值之后.

depmod
功能:分析可加载模块的依赖性,生成modules.dep文件和映射文件。
用法:depmod [-b basedir] [-e] [-F System.map] [-n] [-v] [version] [-A]
        depmod [-e] [-F System.map] [-n] [-v] [version] [filename...]
描述:
    Linux内核模块可以为其它模块提供提供服务(在代码中使用EXPORT_SYMBOL),这种服务被称作"symbols"。若第二个模块使用了这个symbol,则该模块很明显依赖于第一个模块。这些依赖关系是非常繁杂的。

    depmod读取在/lib/modules/version 目录下的所有模块,并检查每个模块导出的symbol和需要的symbol,然后创建一个依赖关系列表。默认地,该列表写入到/lib/moudules /version目录下的modules.dep文件中。若命令中的filename有指定的话,则仅检查这些指定的模块(不是很有用)。

    若命令中提供了version参数,则会使用version所指定的目录生成依赖,而不是当前内核的版本(uname -r 返回的)。
 

mkinitrd 命令的使用
功能:建立要载入ramdisk的映像文件。
用法:mkinitrd [-fv][--omit-scsi-modules][--version][--preload=<模块名称>][--with=& lt;模块名称>][映像文件][Kernel 版本]

描述:mkinitrd可建立映像文件,以供Linux开机时载入ramdisk。

参数:
   -f    若指定的映像问家名称与现有文件重复,则覆盖现有的文件。
-v  执行时显示详细的信息。
   -omit-scsi-modules    不要载入SCSI模块。
   -preload=<模块名称>    指定要载入的模块。
   -with=<模块名称>    指定要载入的模块。
   -version    显示版本信息。

-builtin=<module> :跳过该模块,让 mkinitrd 认为该模块已经是 builtin 的了,就不会再查找该模块了。

-f :覆盖现有文件

-fstab <file> :使用 <file> 来判断来自动判断 / 设备的文件系统类型。默认是 /etc/fstab

-nocompress :不使用 gzip -9 压缩。

-omit-lvm-modules :跳过 lvm 模块,即使 /etc/fstab 指出它们需要

-omit-raid-modules :跳过 software-raid 模块

例如 : mkinitrd /boot/initrd-2.6.24.img 2.6.24

加速编译过程
可以使用 $ make -j . 其中n = 2 * cpu的个数. 对于一般的单CPU系统, 通常用 make -j2一般这个选项可以将速度提高10%左右.
make -j8  #编译
make modules_install && make install  #安装,好了一个内核编译完成,下面是一些细节方面.

建议继续学习

  1. linux内核研究笔记(一)内存管理 – page介绍 (阅读 10,323)
  2. 关于PHP的编译和执行分离 (阅读 8,205)
  3. 从C语言的Hello World说起 (阅读 7,523)
  4. PHP内核介绍及扩展开发指南―Extensions 的编写 (阅读 5,423)
  5. Linux内核协议栈对于timewait状态的处理 (阅读 4,765)
  6. PHP内核介绍及扩展开发指南―基础知识 (阅读 4,703)
  7. 我的内核配置文件 (阅读 4,682)
  8. 如何在Windows下编译或调试MySQL (阅读 4,584)
  9. PHP内核介绍及扩展开发指南―高级主题 (阅读 4,584)
  10. Linux内核模块开发(笔记) (阅读 4,305)