web-dev-qa-db-fra.com

Comment Linux détermine-t-il l'ordre des appels init du module?

J'ai un périphérique avec SPI stockage flash. J'aimerais utiliser un système de fichiers UBIFS sur ce périphérique flash en tant que mon rootfs. Le problème auquel je suis confronté est que le module UBI s'initialise avant le module SPI. De ce fait, lorsque UBI est chargé, il ne peut pas se connecter au périphérique UBI auquel je l'ai dit (via la ligne de commande du noyau), il n'y a donc pas de rootfs. La sortie de la console ci-dessous illustre cela.

Je me suis suffisamment plongé dans la source pour constater que init/main.c possède une fonction do_initcalls() qui appelle simplement une liste de pointeurs de fonction. Ces pointeurs de fonction pointent vers toutes les fonctions module_init() des modules intégrés au noyau. Ces pointeurs de fonction sont placés dans une section spéciale du fichier binaire du noyau. Cet ordre est donc choisi au moment de la compilation. Cependant, je n'ai pas encore compris comment cet ordre est déterminé.

    [    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)
23
Shawn J. Goff

Les routines d'initialisation d'un module initialisé par le noyau (lorsqu'elles sont Liées statiquement au noyau) sont encapsulées dans une macro initcall () qui indique Lorsqu'elles doivent figurer dans la séquence de démarrage courir.

Voir le fichier include: include/linux/init.h pour obtenir une liste des macros et leur ordre.

L'ordre spécifié il y a:

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

La plupart d'entre eux ont une phase "initcall_sync ()", utilisée pour attendre la fin de Toutes les routines d'initialisation de module de cette phase. Les macros sont utilisées pour construire Un tableau de pointeurs de fonction pour chaque phase, qui sont appelées successivement par do_initcalls().

Si "module_init ()" est utilisé pour envelopper la fonction d'initialisation, alors Par défaut, initcall () place l'appel dans la phase d'initialisation "device". Au cours de cette phase, les éléments sont classés par ordre de lien. Cela signifie que La table est créée par l'ordre des fonctions telles qu'elles sont rencontrées Par l'éditeur de liens. 

Vous pourrez peut-être déplacer une initialisation vers une phase antérieure en modifiant la macro Initcall qui enveloppe la fonction d'initialisation des modules, mais soyez prudent, car contient des dépendances d'ordre entre les différents modules. Une autre méthode pour Changer l'ordre d'initialisation (au sein d'une phase) serait d'ajuster l'ordre de lien Pour le module dans le noyau.

36
Tim Bird

@ Tim Bird a déjà répondu à cela - je voudrais montrer comment modifier l'ordre d'un module: -

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);
.......
1
Zakir

Je me trompe peut-être, alors veuillez vérifier si cela est correct. 
Essayez de compiler tous les pilotes dont vous avez besoin en tant que modules (M) et placez les modules à charger dans/etc/modules, dans le bon ordre, cela pourrait résoudre votre problème. Précisément, parce que vous faites ceci avant votre racine est montée, l’étape ci-dessus devrait être faite sur le disque initram. (J'ai un scénario similaire et je dois charger des modules dans le bon ordre , pour pouvoir déchiffrer un fs)

J'espère que cela t'aides 
Au revoir au revoir 
Sergio

0
sergico