Riavviare Linux con kexec
Introduzione
Su sistemi Linux alcuni dei pochi motivi per cui è necessario riavviare il sistema dipendono principalmente da: a) aggiornamento del kernel, b) crash dello stesso.
Personalmente ho sempre odiato il continuo bisogno di riavvio (spesso immotivato) in seguito ad un qualsiasi aggiornamento di software su sistemi Windows, è stata quindi una bella sorpresa per me scoprire che, come già detto, su Linux i riavvii sono molto rari.
Con l’aumentare della mia esperienza nell’uso di Linux, uno dei “lidi” su cui la mia curiosità si è posata è stato proprio il kernel. Dopo i miei primi e incerti tentativi di ricompilazione, credo di poter dire di aver raggiunto un ragguardevole livello di esperienza (per quanto un normale utente senza, ancora, nessuna istruzione accademica in materia possa raggiungere). Come a molti utenti Linux a me piace sperimentare, mi sono perciò spesso trovato a ricompilare uno stesso kernel diverse volte prima di raggiungere una configurazione che soddisfacesse pienamente le mie aspettative, e ovviamente a queste ricompilazioni seguivano necessariamente altrettanti riavvii del sistema. Questo fino a scoprire una interessante funzione del kernel Linux (entrata nel ramo principale di sviluppo già da diverso tempo): kexec.
Kexec permette, in poche parole, di riavviare un kernel da uno già in esecuzione senza dover necessariamente riavviare il sistema fisico.
Linux e il suo boot
Prima di partire però è necessario fare una piccola parentesi sul sistema di booting di Linux, questo per meglio comprendere come kexec funziona.
Il processo di boot ha due fasi principali, la fase del bootloader e quella del kernel, le quali possono essere suddivise a loro volta in diversi stadi.
La prima delle due, la fase bootloader, inizia quando un computer viene acceso fisicamente. Dopo qualche inizializzazioni, il controllo dell’avvio viene passato al BIOS (o firmware che dir si voglia), che ha il compito di determinare le varie periferiche connesse (memorie, dischi, ecc…). Il BIOS si occupa anche di avviare il bootloader dal master boot record (MBR), che, in base alla configurazione, farà decidere all’utente quale kernel avviare (la cosa è un pò più complicata, ma spiegare nei dettaglia il boot di Linux non è lo scopo di questo articolo). Ed è a questo pounto che si passa alla fase del kernel.
Dopo aver preso il controllo del boot, il kernel si occupa di esaminare le periferiche, caricare i driver necessari e inizializzarle. A questo punto vengono avviati i servizi di sistema che si occupano del resto (montare i filesystem, avviare i termiali, ecc…).
Per la fase di riavvio, prima di ritornare alla fase del bootloader, vengono prima terminati tutti i processi, smontati i filesystem e scaricati i driver (con conseguente spegnimento delle periferiche).
Cos’è kexec?
Kexec non è altro che una funzione del kernel Linux che permette di avviare un kernel da uno già avviato, saltando completamente la fase del bootloader sopra descritta, rendendo quindi la fase di riavvio molto più veloce. Si occupa, in altre parole, di caricare un nuovo kernel in memoria, terminare quello già in esecuzione e sostituirlo con quello caricato in precedenza.
Kexec si divide in due parti, la parte kernel, compilata direttamente con il kernel, che consiste in una serie di system call, e una parte user-space, chiamata kexec-tools (sono ovviamente necessarie entrambe).
Per verificare che il proprio kernel sia compilato con kexec, è sufficiente cercare nel file .config se la chiave CONFIG_KEXEC è impostata a ‘y’:
$ zgrep CONFIG_KEXEC /proc/config.gz
oppure
$ grep CONFIG_KEXEC /boot/config-`uname -r`
Mentre per la parte userspace è sufficiente installare kexec-tools
# apt-get install kexec-tools
oppure usando il proprio package manager preferito.
Come funziona?
Prima di procedere con la parte pratica, vediamo più in dettaglio come funziona kexec. Innanzitutto è necessario sapere che il kernel Linux deve essere avviato da una posizione predefinita della memoria, perciò per avviare un nuovo kernel è necessario sovrascrivere quello precedente. Questo è eseguito in 4 passaggi:
- Caricare il nuovo kernel in memoria
- Spostare il kernel nella memoria dinamica del kernel
- Sostituire fisicamente il kernel caricato
- Avviare il nuovo kernel
I primi due passaggi sono effettuati durante il caricamento del kernel. Una volta caricato nella memoria utente, il kernel viene spostato nella memoria dinamica del kernel grazie all’uso della chiamata di sistema ’sys_kexec’.
Insieme ad esso viene allocato in memoria del codice assembly chiamato ‘reboot_code_buffer’, che si dovrà occupare di sovrascrivere il kernel in funzione con quello caricato in memoria, e poi farlo partire (terzo e quarto passaggio).
kexec-tools
Dopo aver verificato che kexec sia correttamente compilato, e aver installato kexec-tools, vediamo ora come usare nella pratica questi strumenti.
Come già detto il primo passo è caricare il kernel in memoria (i primi due passaggi visti prima).
# kexec -l [nuovo-kernel] [args]
dove [nuovo-kernel] sta per l’immagine del kernel da caricare. I formati supportati sono: Beoboot-x86, elf-x86, bzImage-x86, multiboot-x86. Mentre [args] sta per gli argomenti specifici per i formati. Un esempio, utilizzando un kernel in formato bzImage, potrebbe essere:
# kexec -l /usr/src/linux/arch/i386/boot/bzImage --append="root=/dev/hdX"
Dove /dev/hdX sta per il filesystem di root. È possibile usare anche initrd:
# kexec -l /usr/src/linux/arch/i386/boot/bzImage --append="root=/dev/hdX" --initrd=/boot/initrd.img
Se siete indecisi su che argomenti passare al kernel potete dare un’occhiata al file ‘/proc/cmdline’ che indica i parametri dell’attuale kernel.
Per una lista di tutte le opzioni invece basta digitare:
$ man kexec
Ora non resta altro da fare che avviare il nuovo kernel.
# kexec -e
kexec avvia “alla brutta” il nuovo kernel senza fare lo shutdown correttamente, perciò consiglio di usare semplicemente il comando
# reboot
Che dovrebbe funzionare ugualmente (ad un certo punto, dovrebbe spuntare un scritta del tipo “rebooting with kexec” o qualcosa del genere).
Dopodichè il nuovo kernel dovrebbe partire, come se fosse un normale avvio del sistema.
Conclusione
Grazie a kexec, è possibile ridurre notevolmente i tempi di riavvio di un sistema, questo non solo beneficia uno sviluppatore che si trova a dover riavviare numerose volte, ma si applica molto bene anche a tutti quei sistemi in cui il downtime deve essere ridotto al minimo (la maggior parte dei sistemi enterprise quindi). Oltre che ovviamente a tutti quelli che come me vogliono solo imparare qualcosa di nuovo.
AlexBio's Blog

No Comments Yet