【问题标题】:How does Linux determine the order of module init calls?Linux如何确定模块init调用的顺序?
【发布时间】:2012-05-09 06:37:57
【问题描述】:

我有一个带有 SPI 闪存的设备,我想在该闪存设备上使用 UBIFS 文件系统作为我的 rootfs。我面临的问题是 UBI 模块在 SPI 模块初始化之前初始化。因此,当 UBI 加载时,它无法连接到我告诉它的 UBI 设备(通过内核命令行),因此没有 rootfs。下面的控制台输出说明了这一点。

我已经深入研究了源代码,发现init/main.c 有一个do_initcalls() 函数,它只是调用函数指针列表。这些函数指针指向内核内置模块的所有module_init() 函数。这些函数指针被放置在内核二进制文件的一个特殊部分,所以这个顺序是在编译时选择的。但是,我还没有弄清楚这个顺序是如何确定的。

    [    0.482500] UBI error: ubi_init: UBI error: cannot initialize UBI, error -19
    [    0.492500] atmel_spi atmel_spi.0: Using dma0chan0 (tx) and  dma0chan1 (rx) for DMA transfers
    [    0.500000] atmel_spi atmel_spi.0: Atmel SPI Controller at 0xf0000000 (irq 13)
    [    0.507500] m25p80 spi0.1: mx25l25635e (32768 Kbytes)
    [    0.512500] Creating 7 MTD partitions on "jedec_flash":
    [    0.520000] 0x000000000000-0x000000020000 : "loader"
    [    0.527500] 0x000000020000-0x000000060000 : "u-boot"
    [    0.537500] 0x000000060000-0x000000080000 : "u-boot-env"
    [    0.547500] 0x000000080000-0x000000280000 : "kernel0"
    [    0.557500] 0x000000280000-0x000000480000 : "kernel1"
    [    0.567500] 0x000000480000-0x000001240000 : "fs"
    [    0.575000] 0x000001240000-0x000002000000 : "play"
    [    0.590000] AT91SAM9 Watchdog enabled (heartbeat=15 sec, nowayout=0)
    [    0.607500] TCP cubic registered
    [    0.615000] VFS: Cannot open root device "ubi0:root0" or unknown-block(0,0)
    [    0.622500] Please append a correct "root=" boot option; here are the available partitions:
    [    0.630000] 1f00             128 mtdblock0  (driver?)
    [    0.635000] 1f01             256 mtdblock1  (driver?)
    [    0.640000] 1f02             128 mtdblock2  (driver?)
    [    0.645000] 1f03            2048 mtdblock3  (driver?)
    [    0.650000] 1f04            2048 mtdblock4  (driver?)
    [    0.655000] 1f05           14080 mtdblock5  (driver?)
    [    0.660000] 1f06           14080 mtdblock6  (driver?)
    [    0.665000] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

【问题讨论】:

  • 我已经标记为迁移到Stack Overflow,因为即使这可能不需要修改源代码,但它至少需要 Kbuild 技巧。 Stack Overflow 也是专家所在的地方。我怀疑您不应该依赖特定的命令,并且 UBI 驱动程序不应该尝试访问任何设备,直到它被告知要挂载某些东西。
  • LINUX: order of statically linked module loading 的可能重复项,这表明您需要确保模块以所需的初始化顺序出现在 makefile(树)中。
  • 使用EPROBE_DEFER 可能有解决问题的替代方案;我会检查的。

标签: linux-kernel embedded ubifs


【解决方案1】:

@Tim Bird 已经回答了 - 我想展示如何更改模块的顺序:-

pure_initcall(fn)         --> Loaded first
core_initcall(fn)         
core_initcall_sync(fn)    
postcore_initcall(fn)     
postcore_initcall_sync(fn)
arch_initcall(fn)         
arch_initcall_sync(fn)    
subsys_initcall(fn)       
subsys_initcall_sync(fn)  
fs_initcall(fn)           
fs_initcall_sync(fn)      
rootfs_initcall(fn)       
device_initcall(fn)       
device_initcall_sync(fn)  
late_initcall(fn)         
late_initcall_sync(fn)    --> Loaded last

Usage - Replace fn by the module init function pointer, example for i2c core driver:
.......
postcore_initcall(i2c_init);  // To delay i2c core loading use subsys_initcall(i2c_init)                
module_exit(i2c_exit);
.......

【讨论】:

    【解决方案2】:

    由内核初始化的模块的 init 例程(当它们被 静态链接到内核中)被包装在一个 initcall() 宏中,该宏指示 当在启动序列中时,它们应该被运行。

    查看包含文件:include/linux/init.h 以获取宏列表及其顺序。

    那里指定的顺序是:

    • early_initcall
    • pure_initcall
    • core_initcall
    • postcore_initcall
    • arch_initcall
    • subsys_initcall
    • fs_initcall
    • rootfs_initcall
    • device_initcall
    • late_initcall

    其中大多数都有一个“initcall_sync() 阶段,用于等待完成 该阶段内的所有模块初始化例程。宏用于构建 每个阶段的函数指针表,按顺序调用 do_initcalls().

    如果使用“module_init()”来封装初始化函数,那么 默认情况下,initcall() 将调用置于初始化的“设备”阶段。 在该阶段中,项目按链接顺序排序。这意味着 该表是按遇到的函数的顺序创建的 由链接器。

    您可以将初始化移到较早的阶段,方法是更改 initcall 宏包装了模块初始化函数,但要小心,因为 各个模块之间存在顺序依赖关系。另一种方法 更改初始化顺序(在一个阶段内)将是调整链接 内核中模块的顺序。

    【讨论】:

      【解决方案3】:

      我可能是错的,所以请检查这是否正确。
      尝试将您需要的所有驱动程序编译为模块(M),并将要加载的模块按正确的顺序放入/etc/modules,这样可以解决您的问题。 准确地说,因为您是在安装 rootfs 之前执行此操作,所以上述步骤应该在 initram 磁盘中完成。 (我有类似的场景,我需要以正确的顺序加载一些模块,才能解密 fs)

      希望这会有所帮助
      咻咻
      塞尔吉奥

      【讨论】:

      • 将它们编译为单独的模块是行不通的,因为它会将模块放在根文件系统上。我所说的这些模块是用于挂载根文件系统的模块。
      • @ShawnJ.Goff:我编辑了这篇文章,因为我意识到我忘记提及一个重要的细节。 initramfs 部分。 :)
      • 一个 initramfs 不是一个选项 - 它使我的构建的大小增加了一个不可接受的数量。
      • 太糟糕了:(此时我会看一下depmod的代码。严格来说这不是你的场景,但depmod工具能够扫描内核文件夹并计算模块依赖关系。什么我不知道它使用/读取什么样的信息来确定模块依赖关系。也许你会在那里找到一些提示......
      猜你喜欢
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 1970-01-01
      • 2012-03-11
      • 1970-01-01
      • 1970-01-01
      • 2015-10-01
      相关资源
      最近更新 更多