Comment l'arrêt du système d'un noyau Linux fonctionne-t-il en interne?

28

J'ai en quelque sorte une idée approximative de la façon dont l'espace utilisateur et le système init (que ce soit le sysV / upstart / systemd classique init) fonctionnent à l'arrêt du système. (Essentiellement, il y a une succession d'ordres "Stop!", "S'il vous plaît, arrêtez vraiment maintenant", "Processus dont j'ai besoin pour vous tuer pour arrêter" et attendez ... que les choses se passent).

Je ne sais pas comment fonctionne l'arrêt du système dans le noyau (où il y a sûrement aussi beaucoup de choses à faire)?

J'ai essayé de consulter la documentation du noyau https://www.kernel.org/doc/htmldocs/ et j'ai même utilisé l' outil de recherche de copains de la NSA pour me donner une longueur d'avance sur la façon de savoir comment cela fonctionne.

De plus, j'ai cherché sur SE U + L et je n'ai rien trouvé (l'ai-je oublié?)

Quoi qu'il en soit, la question, bien que potentiellement un peu difficile, mériterait une réponse dans ce réseau de questions / réponses, car je suppose que plus de gens sont intéressés à obtenir un croquis de ce qui se passe dans le noyau Linux à l'arrêt.

Potentiellement, il y a aussi un changement pour établir un lien avec des explications plus détaillées.

Une réponse pourrait peut-être inclure quels appels système et quels signaux kernal sont utilisés?

https://github.com/torvalds/linux/blob/b3a3a9c441e2c8f6b6760de9331023a7906a4ac6/arch/x86/kernel/reboot.c semble être le fichier x86 utilisé lié au redémarrage (déjà proche de l'arrêt, hein?)

peut-être que l'extrait trouvé ici http://lxr.free-electrons.com/source/kernel/reboot.c#L176 peut être utilisé pour donner une explication

176 void kernel_power_off (void)
177 {
178 kernel_shutdown_prepare (SYSTEM_POWER_OFF);
179 if (pm_power_off_prepare)
180 pm_power_off_prepare ();
181 migrate_to_reboot_cpu ();
182 syscore_shutdown ();
183 pr_emerg ("Mise hors tension \ n");
184 kmsg_dump (KMSG_DUMP_POWEROFF);
185 machine_power_off ();
186}
187 EXPORT_SYMBOL_GPL (kernel_power_off);
humanANDpeace
la source
8
que la licorne soit avec vous
Kiwy
1
@Kiwy merci pour la suggestion. J'accepterai après un certain temps pour que de meilleures réponses potentielles se présentent. Mais au moins une réponse est maintenant là.
humanityANDpeace
Ne me remerciez pas, merci la Licorne!
Kiwy
Sachez qu'il y a / était une option de saut de la fenêtre pour shutdown(8)dire celle obsolète -n qui, je pense, dans la vieille documentation Unix utilisée pour lire " arrêter le système nous-mêmes - l'unité centrale est EN FEU! " laisserait / pourrait laisser des morceaux éparpillés sur le sol (ou au moins les systèmes de fichiers dans un état corrompu) - on imagine que cela serait utilisé pour un système de type cadre principal où quelqu'un vient de prendre la main dans un ventilateur de refroidissement. 🕱
SlySven

Réponses:

26

Les principales ressources pour comprendre le fonctionnement du noyau Linux sont:

  1. La documentation .
  2. Articles de Linux Weekly News .
  3. La source. Il s'agit d'une bête complexe qui est un peu plus facile à appréhender via LXR , la référence croisée Linux. La variante LXR fonctionnant sur lxr.linux.no est plus agréable que les autres, mais elle est souvent en panne.

Dans ce cas, je ne trouve rien de centralement pertinent dans la documentation ou sur LWN, donc LXR c'est le cas.

La dernière chose que fait le code userland est l'appel rebootsystème . Il faut 4 arguments, alors recherchez SYSCALL_DEFINE4(rebootsur LXR, ce qui conduit à kernel/reboot.c. Après avoir vérifié les privilèges de l' appelant et les arguments, le point d'entrée de syscall appelle une de plusieurs fonctions: kernel_restartau redémarrage, kernel_haltà l' arrêt sur une boucle serrée, kernel_poweroffà la mise hors tension du système, kernel_kexecpour remplacer le noyau par un nouveau (si compilé), ou hibernatepour sauvegarder la mémoire sur le disque avant de mettre hors tension.

kernel_restart, kernel_haltEt kernel_power_offsont assez similaires:

  1. Parcourez reboot_notifier_list, qui est une liste de hooks que les composants du noyau peuvent enregistrer pour exécuter du code à la mise hors tension. Seuls quelques pilotes ont besoin d'exécuter du code à ce stade, principalement des chiens de garde.
  2. Définissez la system_statevariable.
  3. Désactivez usermode-helper pour vous assurer qu'aucun code utilisateur ne sera plus démarré. (Il peut encore exister des processus à ce stade.)
  4. Appelez device_shutdownpour libérer ou éteindre tous les périphériques du système. Beaucoup de pilotes se connectent à cette étape.
    Notez que tous les systèmes de fichiers qui sont encore montés à ce stade sont effectivement démontés de force. L'appelant de l'appel système est responsable de tout démontage propre.
  5. Pour la mise hors tension uniquement, si ACPI est configuré dans, exécutez éventuellement du code pour préparer le passage à l' état ACPI S5 (mise hors tension progressive).
  6. Dans une machine multi-CPU, le code peut s'exécuter sur n'importe quel CPU, quel que soit l'appel système. migrate_to_reboot_cpuprend soin de basculer vers un processeur particulier et d'empêcher le planificateur de distribuer du code sur d'autres processeurs. Après ce point, un seul processeur est en cours d'exécution.
  7. syscore_shutdownappelle la shutdownméthode des opérations syscore enregistrées . Je pense qu'il s'agit principalement de désactiver les interruptions; quelques crochets ont une shutdownméthode.
  8. Enregistrez un message d'information - la chanson du cygne.
  9. Enfin, arrêtez-vous d'une manière dépendante de la machine en appelant machine_restart, machine_haltou machine_power_off.

Le code d' hibernation passe par les étapes suivantes:

  1. Parcourez les crochets de gestion de l' alimentation .
  2. Synchroniser les systèmes de fichiers.
  3. Geler tout le code utilisateur .
  4. Empêchez le branchement à chaud de l'appareil .
  5. Vider l'état du système dans l'espace de swap.
  6. Si tout a réussi, mettez le matériel en veille prolongée . Cela peut impliquer l'appel kernel_restart, kernel_haltou kernel_power_off, ou une méthode d'hibernation spécifique à la plate-forme.

Une manière différente d'arrêter le système est machine_emergency_restart. Ceci est invoqué par la clé magique SysRqB . La Oclé fonctionne différemment: elle appellekernel_power_off .

Le système peut également s'arrêter en panique , c'est-à-dire une erreur irrécupérable. La panique tente d'enregistrer un message, puis de redémarrer le système (via un chien de garde matériel ou un redémarrage d'urgence).

Gilles 'SO- arrête d'être méchant'
la source
+1 merci! @Gilles si vous vouliez implémenter du code qui effacerait / assainirait la RAM de la machine comme dernière étape, vous enregistreriez une opération syscore pour le syscore_shutdown(c'est-à-dire qui résoudrait mon autre question unix.stackexchange.com/q/122540/24394 ) . L'étape (1) et l'étape (7) permettent toutes deux d'enregistrer des choses à exécuter à l'arrêt, pas de dire ce qui est quoi + J'ai eu l'impression que l'ordre d'exécution de ces rappels en (1) et (7) ne peut pas être influencé! Je vais les documents que vous avez mentionnés, mais si vous savez! Merci!
humanityANDpeace
Je suis surpris que cette question et réponse n'ait pas plus de votes positifs.
2

Ceci n'est qu'une réponse partielle et j'invite à coup sûr d'autres réponses, qui pourraient être plus exhaustives et claires.

Le contenu de cette réponse est tiré du kernel/reboot.cfichier du noyau Linux 3.13 (qui pourrait ne pas être la première supposition car le nom n'est pas shutdown.c mais reboot.c)

Quoi qu'il en soit, nous avons essentiellement trois fonctions qui décrivent le processus de fermeture du système

  • void kernel_halt(void) // qui se termine par un système en état d'arrêt
  • void kernel_power_off(void) // qui se termine par un système hors tension
  • void kernel_restart(char *cmd) // qui termine le système pour le redémarrer

Ces fonctions sont très brèves et peuvent donc être collées ici dans leur intégralité. Leur code montre le mieux les étapes à suivre pour arrêter le noyau. (Les commentaires sont de moi et ne sont peut-être pas 100% idéaux et corrects, vérifiez-vous pour en être sûr. C'est simple à essayer.

void kernel_halt(void)

void kernel_halt (void)
{
    // La 1ère étape fait:
    // a) fonctions d'appel / rappel enregistrées pour s'exécuter au redémarrage / à l'arrêt
    // b) définissez system_sate sur SYSTEM_HALT
    // c) arrêtez l'interaction userspacetool
    // d) appel de la fonction device_shutdown ()
    kernel_shutdown_prepare (SYSTEM_HALT);

    // 2ème étape: je pense que c'est surtout une nécessité pour les systèmes multi-processeurs
    migrate_to_reboot_cpu ();

    // 3ème étape:
    // syscore_shutdown - Exécute tous les rappels d'arrêt du système enregistrés 
    syscore_shutdown ();

    // 4e messages
    pr_emerg ("Système arrêté \ n");
    kmsg_dump (KMSG_DUMP_HALT);

    // 5ème appel arch code-cpu-halt spécifique
    machine_halt ();
}

le tout est initié avec l' sys_rebootappel système qui, étant donné qu'il ne redémarre pas seulement mais aussi l'arrêt, pas la chose directe pour se connecter au processus d'arrêt de toute façon.

humanANDpeace
la source