Подтвердить что ты не робот

Как Linux определяет порядок вызовов init-модулей?

У меня есть устройство с флэш-памятью SPI. Я бы хотел использовать файловую систему UBIFS на этом флеш-устройстве в качестве моих корневых файлов. Проблема, с которой я сталкиваюсь, заключается в том, что модуль 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)
4b9b3361

Ответ 1

Процедуры инициализации для модуля, инициализированного ядром (когда они статически связанные с ядром) завернуты в макрос initcall(), который указывает когда в последовательности запуска они должны быть запущены.

См. файл include: 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 macro обертывает функцию инициализации модулей, но будьте осторожны, потому что существуют зависимости между различными модулями. Другой метод изменение порядка инициализации (в фазе) было бы отрегулировать ссылку порядок для модуля в ядре.

Ответ 2

Возможно, я ошибаюсь, поэтому, пожалуйста, проверьте, правильно ли это.
Попробуйте собрать все необходимые вам драйверы в качестве модулей (M) и поместите модули для загрузки в /etc/modules в правильном порядке, это может решить вашу проблему. Чтобы быть точным, потому что вы делаете это до того, как ваши rootfs смонтированы, вышеупомянутый шаг shoudl будет выполнен на диске initram. (У меня есть аналогичный сценарий, и мне нужно загрузить некоторые модули в правильном порядке, чтобы иметь возможность расшифровать файл fs)

Надеюсь, что это поможет
CiaoCiao
Sergio

Ответ 3

@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);
.......