Introduction

Lors de la conception de notre rack Oxide, nous nous sommes posé la question de savoir quels composants devraient être accessibles et par quels moyens. Le rack Oxide est conçu pour vivre dans un centre de données avec un accès exclusif via le réseau. La seule raison pour laquelle un ingénieur devrait visiter physiquement un rack est pour remplacer une pièce défectueuse, telle qu'un disque. Notre Service Processor (SP) est accessible via le réseau de gestion.

Contexte Technique

Lors de nos premières tentatives pour intégrer notre nouvelle génération de sled Cosmo dans un rack Oxide, nous avons constaté que le Service Processor disparaissait du réseau. Cette situation est difficile à déboguer, car sans accès au réseau, nous avons une visibilité limitée sur l'état du SP lui-même. Le débogage a commencé en fonction de l'état du reste du système. Le processeur hôte AMD était toujours actif, ce qui signifie que le système lui-même avait toujours de l'alimentation. Le SP ne diffusait pas sur le réseau de gestion qu'il était actif. Il n'y avait pas d'augmentation des compteurs de données réseau provenant du SP. Les ventilateurs tournaient à une vitesse élevée constante.

Le Service Processor exécute notre système d'exploitation personnalisé, Hubris. Chaque partie du système (réseau, contrôle thermique, mise à jour, etc.) est écrite comme une tâche distincte. Hubris n'est pas un véritable système d'exploitation temps réel avec des garanties de délai, mais il a la notion de priorités de tâche. L'une de nos théories de travail était que nous avions un bogue logiciel qui provoquait une famine de tâche. Si la tâche de réseau était incapable de s'exécuter en raison d'une autre tâche qui consommait tout le temps CPU, elle ne pourrait pas répondre sur le réseau.

Analyse et Implications

Nous avons ajusté le temps de redémarrage de la tâche pour avoir un délai plus long pour attraper ce cas. Nous voulions également être en mesure d'observer si le SP faisait toujours des progrès, même si nous n'avions pas accès au réseau, et nous avons donc commuté notre LED de chassis de « toujours allumé » à « clignotant ». Nous avons eu de la chance de pouvoir reproduire le problème avec ces modifications de débogage, mais les résultats étaient toujours confus. Dans certains cas, nous voyions la LED bloquée sur, et dans d'autres cas, la LED était bloquée sur éteint.

Une des nombreuses avantages de l'écriture de Hubris en Rust est d'éliminer les classes de bogues tels que les débordements de tampon. Une catégorie de problèmes auxquels Hubris est toujours particulièrement sensible est les débordements de pile. Cela est dû au fait que Hubris nécessite un dimensionnement manuel des piles pour les tâches et que le calcul de la taille de pile maximale s'est avéré difficile.

Perspective

Notre capacité à détecter les piles sous-dimensionnées a été améliorée avec l'ajout de la fonctionnalité d'émission de tailles de pile, mais nous pouvons toujours rencontrer certains cas limites. Lorsqu'un débordement de pile se produit, la tâche redémarre en toute sécurité. Un débordement de pile dans le noyau pourrait potentiellement produire un comportement similaire à celui d'un système qui semble ne pas faire de progrès.

Nous avons finalement identifié le problème comme étant lié à la communication entre le processeur et la mémoire via le contrôleur de mémoire flexible (FMC). Nous avons créé une image de test FPGA avec un registre qui, lorsqu'il est lu, intentionnellement bloque le bus FMC. Cela a produit un comportement très similaire à ce que nous avons observé et a été un indicateur fort que nous regardions la bonne partie du système pour trouver le problème.