lundi 26 octobre 2009

Cluster Tricks: cycle reboot

Au LACAL, nous avons récemment reçu notre nouveau cluster équipé d'Infiniband, qu'il a fallu mettre en place. Pour des raisons de convenance, rien n'est installé sur les disques des noeuds (qui servent uniquement au swap et au stockage temporaire), et le boot se fait via le réseau.

Problème 1: le BIOS est idiot - si le netboot échoue, la séquence de boot continue, puis s'arrête. Autrement dit, si un noeud tente de booter alors que le serveur est indisponible, il ne réessaie pas, il s'arrête. Ce qui serait absolument sans conséquence, s'il n'y avait le:

Problème 2: suite a un glitch administratif, nos noeuds ne sont pas équipés d'IPMI. Impossible donc de les redémarrer à distance.

Solution sympathique: puisque le disque local n'est pas utilisé pour booter, installons-y un système qui va redémarrer la machine. Il ne reste alors plus qu'a ajouter le disque à la fin de la séquence de boot, et le redémarrage sera automatique. Mais comment ?

Pour une opération aussi simple qu'un reboot, inutile de charger un système complet. On sait que, pour booter sur un disque, le BIOS vérifie d'abord la validité de la table de partitions, puis charge et exécute le code situé dans le MBR, soit le premier secteur du disque. Le code est exécuté en mode réel.

Jetons un coup d'oeil rapide dans la documentation de Linux. Elle nous apprend l'existence d'une technique primitive de redémarrage, utilisée en dernier ressort: le Triple-Fault.

Wikipedia contient une page à ce propos, et mentionne son utilisation par Linux. La technique consiste en "installer une table de vecteurs d'interruption vide, puis déclencher une interruption". Quelques recherches sur google indiquent que ceci se fait via l'instruction x86 LIDT. L'argument contient a la fois un pointeur vers la base de la table, et sa longeur; une valeur constante de 0 fonctionne pour créer une table vide.

Je crée donc un fichier reboot.asm:

lidt [0]
int 3

Que j'assemble simplement avec nasm:

max@node ~$ nasm reboot.asm
max@node ~$ hexdump reboot
0000000 010f 001e cd00 0003
0000007

Merveilleux. reste à écrire ce fragment dans le MBR de mon disque:

max@node ~ $ sudo dd if=reboot count=1 conv=notrunc of=/dev/sda

Presto !

Aucun commentaire: