Partition de récupération personnalisée

9

Je travaille sur un projet où les mises à niveau du Raspberry PI se feront via HTTP, et le Raspberry PI ne sera pas directement accessible (ne peut pas simplement échanger des cartes).

J'aimerais avoir une configuration de partition comme ceci:

  • Partition 1- / boot (contient des noyaux pour les deux partitions)
  • Partition 2- / (partition de récupération)
  • Partition 3- / (partition principale)

Lorsqu'une mise à niveau se passe mal et que le Raspberry PI entre dans une boucle de redémarrage ou se bloque au démarrage, j'aimerais que l'utilisateur puisse appuyer sur un bouton, ce qui déclenche une ligne GPIO, ce qui entraînerait le chargeur de démarrage à démarrer dans le partition de récupération au lieu de la partition principale.

La partition de récupération ne serait jamais mise à niveau, ce serait donc sûr.

Je vois quelques options:

  1. Toujours démarrer dans la partition de récupération, vérifier GPIO, puis démarrer dans la partition principale sans bouton enfoncé
  2. GPIO est vérifié directement par le chargeur de démarrage

J'essaie essentiellement de faire quelque chose de similaire à ce que font les routeurs, où si vous maintenez la réinitialisation pendant le démarrage, vous pouvez TFTP sur une nouvelle image ou quelque chose.

Est-ce possible avec le Raspberry PI? Si oui, existe-t-il une documentation pour faire ce genre de chose?

Éditer:

J'ai trouvé cette réponse à cette question connexe: Est-il possible de faire un double démarrage à partir de la carte SD?

Un commentaire sur la question ci-dessus m'a conduit ici: http://www.berryterminal.com/doku.php/berryboot . Cela semble prometteur, mais je devrai le rechercher davantage pour voir si je peux obtenir une lecture GPIO. Si quelqu'un en a l'expérience, je serais très intéressé.

beatgammit
la source
Faites-nous savoir comment vous vous y prenez, ça a l'air intéressant :)
Jivings
1
Je pense que j'ai trouvé un moyen d'accomplir cela en écrivant un simple chargeur de démarrage de deuxième étape, donc je m'assurerai de le documenter ici si je le fais. J'espère toujours une solution simple ...
beatgammit
1
Malheureusement non, mais j'ai considérablement réduit les risques de corruption en utilisant un système de fichiers RO: /boot(RO), /(RO), /var(RW), /home(RW). Le problème initial était la corruption du système de fichiers lorsque l'alimentation est coupée au démarrage. Je voudrais quand même écrire / trouver un chargeur de démarrage de 2ème étape.
beatgammit
1
Vous pouvez voir ce que fait le chargeur de démarrage NOOBS ( raspberrypi.org/archives/4100 ) pour le Pi. Il pourrait en fait convenir à vos besoins juste pour l'utiliser, car il prévoit des partitions de récupération et l'installation.
Fred
1
Je suggère «contre» en utilisant un chargeur de démarrage personnalisé, mais utilisez des hacks qui s'exécutent après le démarrage du système. Il sera plus facile à mettre en œuvre et plus sûr à déboguer. Un chargeur de démarrage défectueux peut faire frire votre Pi.
Maxthon Chan

Réponses:

5

Si l'erreur peut se produire à tout moment après le démarrage du système, vous pouvez utiliser une horloge de surveillance et un script de démarrage.

Le principe de cette méthode est que chaque fois que le système redémarre sans s'arrêter correctement, il va à la partition de récupération.

Vous devez écrire un script qui s'exécute chaque fois que le système démarre et s'arrête correctement. Passez /boot/cmdline.txtà la partition de récupération au démarrage du système et revenez en arrière avant de vous arrêter correctement.

Configurez ensuite la minuterie du chien de garde. Vous pouvez utiliser celle intégrée dans la puce BCM2835 ou (si vous utilisez une carte de révision 2) construire la vôtre en utilisant deux broches GPIO, l'en-tête de réinitialisation P6 et une puce 555. Lorsque le programme critique est démarré, démarrez le chronomètre de surveillance et frappez régulièrement le chien si le système fonctionne correctement. Lorsque le système tombe en panne, le temporisateur de surveillance est déclenché et réinitialise le processeur et l'envoie à la partition de récupération. Cela ne nécessite pas non plus d'interaction de l'utilisateur et si vous utilisez le minuteur intégré, pas de GPIO.

En utilisant cette méthode, vous pouvez également implémenter un bouton de réinitialisation qui garantira d'envoyer le système à la récupération manuellement sur une carte Rev.2 en installant un bouton sur l'en-tête P6.

Maxthon Chan
la source
Votre première réponse est un peu plus proche de ce que je ferais probablement, mais j'aime l'idée d'utiliser des GPIO dans l'espace utilisateur et un chien de garde. Bien que je n'utilise probablement aucune des idées en gros, vous m'avez donné de bonnes idées. Merci!
beatgammit
1

J'ai un moyen de le faire sans pirater le noyau, ce qui implique de protéger le système contre un redémarrage intempestif:

  1. Téléchargez l'image de mise à niveau, vérifiez-la et développez-la dans l'espace de travail.
  2. Modifiez /boot/cmdline.txt afin que la prochaine fois que le système démarre, il utilise la partition de récupération comme périphérique de blocage racine.
  3. Installez la mise à niveau à partir de l'espace de travail et vérifiez qu'elle fonctionne.
  4. Si la mise à niveau fonctionne, modifiez /boot/cmdline.txt en arrière.
  5. Si nécessaire, redémarrez.

Une mise à niveau échouée entraînera le démarrage automatique du système dans la récupération. Aucun GPIO nécessaire.

Maxthon Chan
la source
Le seul problème ici est (selon le système) qu'un défaut peut être détecté des heures après la fin de la mise à jour, auquel cas l'utilisateur n'a pas la possibilité de revenir à la partition de récupération.
1
@DanNixon Je poste une autre réponse pour résoudre ce nouveau problème.
Maxthon Chan
1

En outre, il existe une troisième solution possible, mais il vous faudra disséquer initrdune version PC de la distribution Linux pour comprendre comment fonctionne le syscall pivot_init(). Je ne sais pas si le noyau de Pi a cet appel système. Si c'est le cas, cette méthode est possible, aucun piratage du noyau n'est également requis, et il utilise un GPIO.

Pour ce faire, vous devrez écrire un initprogramme personnalisé dans le système de production. vérifiez si le GPIO est activé. Si oui, pivot_root()à la récupération. Puis exec()l'original initpour que le système continue de démarrer. Vous pouvez, dans le système de production, trouver un moyen de faire initfonctionner côte à côte (PID = 2) avec le initPIO = 1, ce GPIO et garder un œil sur le GPIO et redémarrer pour récupérer si le bouton est enfoncé.

Maxthon Chan
la source