How does Linux determine the order of module init calls?
我有一台带有SPI闪存存储的设备,我想在该闪存设备上使用UBIFS文件系统作为我的rootfs。 我面临的问题是,UBI模块在SPI模块初始化之前就已初始化。 因此,在加载UBI时,它无法连接到我已经告诉它的UBI设备(通过内核命令行),因此没有rootfs。 下面的控制台输出说明了这一点。
我一直在深入研究源代码,以了解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [ 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) |
由内核初始化的模块的初始化例程(当它们是
静态链接到内核中)包装在一个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()阶段",用于等待完成
该阶段内的所有模块初始化例程。宏用于构建
每个阶段的函数指针表,依次由
如果使用" module_init()"包装初始化函数,则
默认情况下,initcall()将调用置于初始化的"设备"阶段。
在该阶段内,按链接顺序对项目进行排序。这意味着
该表是根据遇到的功能的顺序创建的
通过链接器。
您可以通过更改哪个初始化来将初始化移至早期阶段
initcall宏包装模块的初始化函数,但是要小心,因为
各个模块之间存在顺序依赖性。另一种方法
更改初始化顺序(在一个阶段内)将是为了调整链接
内核中模块的顺序。
@Tim Bird已经回答了-我想展示如何更改模块的顺序:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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); ....... |
我可能是错的,所以请检查是否正确。
尝试将所有需要的驱动程序编译为模块(M),然后以正确的顺序将要加载的模块放入/ etc / modules中,这可以解决您的问题。
确切地说,因为您是在安装rootfs之前执行此操作的,所以上述步骤应在initram磁盘中完成。
(我有类似的情况,我需要以正确的顺序加载一些模块,以便能够解密fs)
希望这对您有帮助
CiaoCiao
塞尔吉奥