前两天把内核关于内核启动参数的一些知识彻底地分析了一遍
《Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)》,发现了一些以前没有注意的细节问题,这里总结如下:
一、2.6.32以后的内核不再对cmdline中的未知参数输出警告信息
以前在移植内核的时候,如果cmdline中有未知的参数,内核一般会打印如下警告:
- Unknown boot option `**********': ignoring
但是这次我在uboot的bootargs中添加了内核未知的参数,比如“hello_linux.tekkaman=ninja”,但是在内核启动信息和dmesg中一点错误信息都没有,我感觉很奇怪,然后我又在同事的板子上试了下,一样没有任何错误信息。我查了下代码,按照逻辑,是不会有错误信息输出。哪以前怎么会有错误信息?
后来我通过Git查找了内核针对这方面的修改,发现了如下提交:
- commit f066a4f6df68f03b565dfe867dde54dfeb26576e
- Author: Rusty Russell
- Date: Tue Dec 1 14:56:44 2009 +1030
- param: don't complain about unused module parameters.
- 参数:不抱怨未使用的模块参数。
- Jon confirms that recent modprobe will look in /proc/cmdline, so these
- cmdline options can still be used.
- 乔恩证实:新的modprobe会读取/proc/cmdline,所以这些
- 命令行选项仍然可能被使用。
- See
- Reported-by: Adam Williamson
- Cc: stable@kernel.org
- Signed-off-by: Rusty Russell
- Signed-off-by: Linus Torvalds
也就是说由于新版本的module-init-tool中的modprobe可以在挂外部.ko模块的时候读取/proc/cmdline(也就是内核启动参数cmdline的备份)中的参数,所有在内核启动的时候还暂时未知的参数可能在系统运行起来,挂载模块的时候被使用。所以在启动的时候提出警告实属不必要。所有这个警信代码被删除了。
这个提交的补丁如下:
- $ git diff f066a4f6df^..f066a4f6df
- diff --git a/init/main.c b/init/main.c
- index 5988deb..4051d75 100644
- --- a/init/main.c
- +++ b/init/main.c
- @@ -251,7 +251,7 @@ early_param("loglevel", loglevel);
- /*
- * Unknown boot options get handed to init, unless they look like
- - * failed parameters
- + * unused parameters (modprobe will find them in /proc/cmdline).
- */
- static int __init unknown_bootoption(char *param, char *val)
- {
- @@ -272,14 +272,9 @@ static int __init unknown_bootoption(char *param, char *val)
- if (obsolete_checksetup(param))
- return 0;
- - /*
- - * Preemptive maintenance for "why didn't my misspelled command
- - * line work?"
- - */
- - if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
- - printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
- + /* Unused module parameter. */
- + if (strchr(param, '.') && (!val || strchr(param, '.') < val))
- return 0;
- - }
- if (panic_later)
- return 0;
这个提交在2.6.32发布前被并入主线:
- $ git tag --contains f066a4f6df
- v2.6.32
- v2.6.33
- v2.6.33-rc1
- v2.6.33-rc2
- v2.6.33-rc3
- v2.6.33-rc4
- v2.6.33-rc5
- v2.6.33-rc6
- v2.6.33-rc7
- v2.6.33-rc8
就这个问题在:
- From 2009-09-11 16:28:54
- When passing a kernel parameter of the type:
- radeon.modeset=0
- the kernel will throw a warning message that says "Unknown boot option
- 'radeon.modeset=0'. Ignoring..." However, the parameter is not ignored, it is
- passed to (and parsed by) the radeon module.
- We (Fedora QA/BugZappers) find people are often confused or worried by this
- message when we ask them to use such a parameter, and worry that it is not
- being applied correctly. The kernel should not print this warning/error message
- when the parameter is of a format that will cause it to be passed to a kernel
- module.
- Comment From 2009-09-22 02:50:17
- Is this because modern modprobe is scraping these options from /proc/cmdline?
- If so, yes, we should suppress those messages altogether.
- CC'd Jon, he'd know.
- Comment From 2009-09-22 04:51:52
- I don't know how it's implemented, exactly, that may well be how it works. I
- just know that you can pass any module parameter as a kernel command line
- parameter in that format (modulename.moduleparameter=value) and it gets passed
- on somehow.
- Comment From 2009-11-26 17:43:30
- ping? this still regularly causes confusion for users when we're trying to
- debug various issues, see
- for a recent example: it's a 'cosmetic' bug but with unfortunate effects.
- Comment From 2010-03-21 12:03:01
- Yea, exactly that's what happens. Modprobe pulls out those arguments and
- processes them.
- I don't know why I missed this bug, but that should be fixed now. I even have
- daily reminders setup and should get CC'd on every module issue from now on.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
二、使用modprobe挂载.ko模块可以从cmdline中获取参数
从上面的发现又牵出了一个新的发现,原来单独编译的内核模块参数是可以用modprobe挂载的时候从内核的cmdline中获得的。这个是我以前没有注意到的。于是我做了个实验:写一个简单的模块(仅在init函数中打印模块参数),然后在内核启动参数中增加这个参数的初始化。经几次实验,证实了这个功能。
其实通过模块挂载的原理和模块的二进制结构的了解(详见《深入Linux内核构件》 第七章 模块),可以知道:其实这个功能是modprobe实现的。所以实现这个功能的必要条件是modprobe工具必须支持从/proc/cmdline读取字符串,并通过格式(模块名).(变量名)=(值)过滤出参数。
这个大家特别注意一下参数的格式 :
在嵌入式中,高版本的busybox是支持的,现在最新的肯定支持,但是注意了,要配置busybox的时候不能选择"简化版的挂载工具",要配置为编译全功能的modprobe。
在PC系统下也是支持的,在grub的内核启动参数中添加 hello_linux.tekkaman=ninja ,再用modprobe挂载模块。用dmesg看内核信息就可以看到实验结果。实验用的PC信息如下:
Linux Amethyst 3.2.12-gentoo #1 SMP Mon Apr 16 14:16:04 CST 2012 i686 AMD Athlon(tm) 64 X2 Dual Core Processor 4800+ AuthenticAMD GNU/Linux
module-init-tools version 3.16 | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
嵌入式实验现象如下:
- # busybox modprobe hello_linux
- Hello, Linux !
- (0) Hello, ninja
- # cat /proc/cmdline
- console=ttyO2,115200n8 root=/dev/nfsroot nfsroot=10.10.10.2:/media/6a55c5a3-f467-4b31-a56a-73b57c5cd2a2/C6A816x/development/targetfs,nolock rw mem=176M@0x80000000 mem=39M@0x9BD00000 vram=90M notifyk.vpssm3_sva=0xBF900000 ip=10.10.10.10:10.10.10.2:0.0.1:255.255.255.0::eth0:off noinitrd earlyprink hello_linux.tekkaman=ninja
实验代码如下:
test_module_i686.zip
阅读(2277) | 评论(0) | 转发(0) |