前两天把内核关于内核启动参数的一些知识彻底地分析了一遍
《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