看源码是件美妙的事

最近开发的一个工具调用了ipmitool来获取某些信息, 不过有些老机器和虚拟机并不支持ipmi, 加载ipmi_si模块时会在/var/log/message文件刷以下log

[1204463.682633] IPMI System Interface driver.
[1204463.683100] ipmi_si: Adding default-specified kcs state machine
[1204463.683103] ipmi_si: Trying default-specified kcs state machine at i/o address 0xca2, slave address 0x0, irq 0
[1204463.683128] ipmi_si: Interface detection failed
[1204463.683131] ipmi_si: Adding default-specified smic state machine
[1204463.683133] ipmi_si: Trying default-specified smic state machine at i/o address 0xca9, slave address 0x0, irq 0
[1204463.683141] ipmi_si: Interface detection failed
[1204463.683144] ipmi_si: Adding default-specified bt state machine
[1204463.683146] ipmi_si: Trying default-specified bt state machine at i/o address 0xe4, slave address 0x0, irq 0
[1204463.683157] ipmi_si: Interface detection failed
[1204463.683494] ipmi_si: Unable to find any System Interface(s)

找了ipmitool的手册, 没找到可以用来屏蔽的选项, 可是又不想单独对不支持的机器加上一句恶心的if. 无奈只得看看源码, 看一个完全不熟悉的东西的源码是多么痛苦的事, 特别是学过的c语言都还给老师了.

直接在线看源码(http://lxr.free-electrons.com/source/drivers/char/ipmi/ipmi_si_intf.c), 全文搜索'Unable to find any System Interface(s)', 找到以下代码段

3586         if (unload_when_empty && list_empty(&smi_infos)) {
3587                 mutex_unlock(&smi_infos_lock);
3588                 cleanup_ipmi_si();
3589                 printk(KERN_WARNING PFX
3590                        "Unable to find any System Interface(s)\n");
3591                 return -ENODEV;
3592         } else {
3593                 mutex_unlock(&smi_infos_lock);
3594                 return 0;
3595         }

其中unload_when_empty 和 list_empty(&smi_infos) 决定了是否输出"Unable to find any System Interface(s)\n"

虽然看不懂c语言了, 不过代码逻辑还是能理解的. unload_when_empty是个常量, 值为1; &smi_infos 的内容应该就是由机器是否支持ipmi来决定的

如果能修改unload_when_empty的值, 不就能跳过打印log的逻辑么, 不过修改代码不实际, 不可能每台机我都用修改过的模块来加载, 量太大了

最后我查看了ipmi_si模块的信息

$ modinfo ipmi_si
filename:       /lib/modules/3.2.0-4-amd64/kernel/drivers/char/ipmi/ipmi_si.ko
description:    Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.
author:         Corey Minyard <minyard@mvista.com>
license:        GPL
alias:          pci:v*d*sv*sd*bc0Csc07i*
alias:          pci:v0000103Cd0000121Asv*sd*bc*sc*i*
depends:        ipmi_msghandler
intree:         Y
vermagic:       3.2.0-4-amd64 SMP mod_unload modversions
...
...
...
parm:           unload_when_empty:Unload the module if no interfaces are specified or found, default is 1.  Setting to 0 is useful for hot add of devices using hotmod. (int)
parm:           kipmid_max_busy_us:Max time (in microseconds) to busy-wait for IPMI data before sleeping. 0 (default) means to wait forever. Set to 100-500 if kipmid is using up a lot of CPU time. (array of uint)

找到这个

parm:           unload_when_empty:Unload the module if no interfaces are specified or found, default is 1.  Setting to 0 is useful for hot add of devices using hotmod.

眼前一亮啊, 这不就是我想要的那个参数么, 改加载的代码为

modprobe ipmi_si unload_when_empty=0

测试后和预期一样, 不再打印log, 最后看了解释, 这个参数是设置在不支持ipmi的情况下也不卸载模块, 用于支持热插拔的. 没有其它影响, 同时也解决了我的问题.

后记: 写这文章主要是为了说明在开源界, 在你无法解决问题时, 不妨看看源代码, 不用怕看不懂, 只要能理解其中的逻辑, 也许将给你提供好的思路

2014-03-18 11:31707hardwarelinux
  • ugenehan2015-09-21 17:24

    虚拟机支持IPMI吗?

  • chenwqin2015-09-22 10:56

    据我所知, Qemu是支持的, 类似于虚拟出IPMI接口吧, 有兴趣可以看看Qemu的文档, 其它类型的虚拟机我就不清楚了