Primera tanda de los ADR 0017/0018, con las mediciones que la corrigieron. ADR 0018 §3 — install-image-efi.sh y takana-live-install.sh escriben el kernel en \EFI\takana\takanax64.efi ADEMAS de la ruta fallback, con un guardián de capacidad que comprueba ANTES y con los números a la vista (duplicar el kernel cuesta, y el costo se dice). En el live-install la verificación es por TAMAÑO, no por presencia: un cp truncado en FAT32 deja el fichero ahí y test -e diría que todo salió bien. Verificado con imagen real en OVMF: las dos copias dan el mismo sha256 que el bzImage del store, y la imagen arranca hasta arje-zero PID1. CONTROL NEGATIVO: pisando la fallback con 4K de basura el firmware dice "No bootable option or device was found" y no aparece HAMMER-EFI ni una vez ⇒ el escenario de Windows, reproducido. Y lo que NO se pudo verificar cambia el alcance, así que va en el ADR: sin entrada NVRAM el firmware NO busca el vendor path. La copia vendor es hoy un seguro que no se cobra solo — el §3 es necesario y NO suficiente sin el §1. Eso asciende la receta efibootmgr a bloqueante. ADR 0017 §4 — store-gc.sh suma como raíz el kernel EN EJECUCIÓN, identificado por .config byte a byte. Sin esto el artefacto del kernel vivo cae en "superados" cuando la receta se movió, y se borra: el sistema sigue andando perfecto hasta el día que hace falta volver atrás. Probado en los tres sentidos, incluido el control que TIENE que seguir condenado. Además, dos bugs preexistentes que aparecieron al ir a medir: - install-image-efi.sh abortaba con "ROOTFS sin /sbin/init" en TODO rootfs sano: /sbin/init es un symlink ABSOLUTO (→/usr/bin/arje-zero) y [ -e ] lo sigue contra la raíz del HOST. Un chequeo que validaba algo distinto de lo que creía validar. Arreglado resolviendo el destino dentro del rootfs. - (no arreglado, es del entorno) el cp -al del staging da EXDEV si ROOTFS y STAGE no están en el MISMO MOUNT — y el bind-mount del store cuenta como otro mount aunque sea el mismo /dev/sdb. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHAKWoBqof9XvsYCvDicEj
10 KiB
ADR 0017 — Ciclo de vida del kernel: cambiarlo sin pagar el reboot
- Estado: PROPUESTO — dos decisiones abiertas (ver §Lo que no decide este ADR). No implementar los verbos antes de cerrar la primera.
- Fecha: 2026-09-11
- Frontera:
recipes/linux-*.toml,crates/takana-cli/src/kernel_cmd.rs, el GC del store. - Hermano: ADR 0018 — arrancar el kernel nuevo es otro problema y tiene su propio fichero. Relacionado: SDD 22 (el armador), SDD 25.
Contexto
El problema de actualizar kernels en una distro normal no es técnico: es que el kernel es un
nombre mutable. /boot/vmlinuz-6.16.12 es un fichero que se sobreescribe, y conservar los N
anteriores es una convención que se rompe sola cuando /boot se llena. De ahí sale todo lo demás —
el rollback deja de ser una operación y pasa a ser un procedimiento con pasos que hay que recordar
bajo presión.
En takana el kernel es un artefacto de contenido: el viejo y el nuevo coexisten sin disputarse un nombre. La mitad de este problema está resuelta por construcción y sin haberlo buscado. Esto importa porque cambia dónde conviene invertir:
Una distro no se hace fuerte logrando que la actualización no falle. Se hace fuerte logrando que fallar no cueste nada.
Lo medido (2026-09-11)
Sobre los .config sellados en ./store, no sobre las recetas — el .config producido es la
identidad del artefacto (SDD 22 §1) y es lo único que dice qué kernel hay de verdad.
| kernel (store) | KEXEC |
KEXEC_FILE |
LIVEPATCH |
MODULES |
EFI_STUB |
CMDLINE_BOOL |
|---|---|---|---|---|---|---|
linux d2a03c29 |
✅ | — | — | ✅ | ✅ | — |
linux-generic 23f1cc43 |
✅ | — | — | — | ✅ | ✅ |
linux-metal 2ed8f54a |
✅ | — | — | — | ✅ | ✅ |
linux-metal-dual 714f46d6 |
✅ | — | — | — | ✅ | ✅ |
linux-gioser 8ffd5710, b026fe14 |
✅ | — | — | — | ✅ | ✅ |
Cuatro consecuencias, y ninguna es opinión:
CONFIG_KEXEC=yen los 6. La primitiva para cambiar de kernel sin pasar por el firmware ya está pagada en todo el corpus, gratis, heredada deldefconfigde x86. No hay que re-hashear nada para empezar a usarla.CONFIG_LIVEPATCHen ninguno. Lo que sí aparece esCONFIG_HAVE_LIVEPATCH=y, que es capacidad de la arquitectura, no el feature — confundirlos es exactamente el modo de error que este repo ya tiene nombrado: la etiqueta no es el hecho.CONFIG_MODULESsólo enlinux. Los cinco kernels que arrancan máquinas son monolíticos (recipes/linux-metal.toml:108lo apaga a propósito). Un livepatch es un.ko⇒ en esos cinco kernels el livepatch está cerrado por construcción, no por falta de trabajo.CONFIG_KEXEC_FILEen ninguno. Sólo existe el syscall viejokexec_load. Con lockdown activo (lo que trae Secure Boot) el kernel rechazakexec_loady sólo aceptakexec_file_loadcon imagen firmada. ⇒ kexec y Secure Boot no coexisten hoy, y eso ata este ADR con el 0018 §Secure Boot.
Y el estado de la herramienta: takana kernel tiene hoy nueve subcomandos —closure, probe,
bundles, plan, diff-back, gate, hw, contract, stats— y ninguno escribe nada. SDD 22
construyó deliberadamente un armador que sólo analiza. Los verbos que propone este ADR serían los
primeros del namespace que actúan sobre la máquina, y esa frontera merece cruzarse a propósito.
No existen en el catálogo kexec-tools, efibootmgr, sbsigntool, shim, mokutil ni efivar.
Decisión
1. Tres verbos, nombrados por lo que cuestan
Casi toda la industria vende «live kernel update» y entrega una de tres cosas distintas. Takana nombra las tres por separado y no llama a ninguna lo que no es:
| verbo | qué hace | downtime | alcance | perfil |
|---|---|---|---|---|
takana kernel stage <hash> |
deja el kernel listo; entra en el próximo reboot natural | cero | total | escritorio |
takana kernel kexec <hash> |
reboot suave: salta firmware y gestor de arranque | ~2 s, mata el userspace | total | servidor |
| (livepatch) | parchea funciones del kernel vivo | cero real | una función | CVE en producción |
kexec no es «sin rebootear» y la ayuda del comando tiene que decirlo con esas palabras. Lo que
ahorra son los 20–30 s de POST/UEFI, que en un servidor remoto es la mitad del downtime y en un
portátil no es nada. Ser la distro que no confunde las tres ya es una posición: la confusión es
la norma del mercado.
2. A/B con vuelta atrás automática — esto es lo que vale
kexec solo no hace fuerte a nadie: hace rápido. Lo que hace fuerte es que si el kernel nuevo
no llega a “sistema sano” en T segundos, la máquina vuelve sola al anterior.
- systemd-boot aproxima esto con contadores en el nombre del fichero (
+3-0). Takana puede hacerlo mejor porque el estado al que volver es un hash, no un fichero que puede no estar. - Qué es «sano» lo declara el perfil, no el kernel: para
perfil.servidores que arje-zero levantó sus servicios supervisados; para un escritorio, que el compositor pintó. - Sin esto, actualizar el kernel de una máquina remota da miedo, y con razón. Es la única entrada de esta lista que yo pondría primero.
3. El kernel corriendo se identifica por hash, no por uname -r
uname -r dice 6.16.12 y no dice qué .config, qué parches ni qué toolchain. Eso es el bug
clásico de los livepatches y los módulos fuera de árbol: se construyen contra el kernel equivocado y
el síntoma aparece meses después. Con el hash del artefacto viajando en el kernel vivo —el cmdline
embebido ya lo permite en 5 de los 6— la pregunta «¿esto corresponde a este kernel?» pasa de
heurística a comparación exacta.
Es un cierre de invariante, no una comodidad.
4. El kernel EN EJECUCIÓN es raíz del GC
No el de la entrada de arranque: el que está corriendo. Si el GC poda el artefacto del kernel vivo, se pierden el rollback y la capacidad de diagnosticar, y se pierden en silencio — el sistema sigue andando perfecto hasta el día que lo necesitás. Es el mismo patrón que ya costó caro en el CAS: lo que no es alcanzable desde una raíz desaparece sin avisar.
⇒ scripts/store-gc.sh y cualquier GC nuevo leen el hash del kernel vivo y lo tratan como raíz.
Guardián con rotura a propósito y control que tiene que pasar, no sólo con el caso feliz.
ENMIENDA 2026-09-11 — el §4 está implementado en
scripts/store-gc.shy probado en los tres sentidos. El GC suma ahora una raíz: el artefacto de kernel cuyoboot/config-*coincide byte a byte con el.configdel kernel vivo (/proc/config.gz, o/boot/config-$(uname -r)).
caso esperado resultado store de juguete con el kernel vivo marcado «superado» se rescata ✅ movido a vigentes, y lo dice: «1 estaban marcados para BORRAR y se rescataron» control: un kernel con .configdistinto, también marcadosigue condenado ✅ no protege de más store real, en el hub (kernel ajeno de Artix) no protege nada, y lo explica ✅ «NINGUN artefacto del store lo tiene» El control del medio es el que importa: sin él, una función que devolviera «protegido» siempre pasaría la primera prueba y volvería inútil al GC sin que nadie lo notara.
Identifica por contenido del
.config, no por hash de artefacto: dos artefactos con el mismo.configy distinta toolchain se protegen los dos. Es el lado correcto para un GC, y se vuelve exacto el día que el §3 ponga el hash en el kernel vivo.
5. Si alguna vez hace falta livepatch, es una variante, no un flag
La salida correcta no es encender MODULES en el kernel general —eso revierte una decisión de
reproducibilidad y superficie de ataque para todo el mundo—. Es una variante
linux-servidor-livepatch con su propio hash, para el perfil que la pida. En takana las variantes
son baratas; lo caro es descubrir dentro de dos años que la puerta se cerró sin que nadie supiera
que la estaba cerrando.
6. El límite que este ADR no cruza, dicho en voz alta
Para «actualizar sin interrumpir el trabajo» la respuesta no está en el kernel: es CRIU o drenar
la carga a otra máquina. Ninguna distro resuelve eso, y prometerlo es donde empiezan las
mentiras de la categoría. stage + kexec + rollback automático es el techo honesto.
Lo que no decide este ADR
-
¿El perfil servidor quiere livepatch? ⛔ ABIERTA. Si sí: hay que prever la variante con
MODULESahora y aceptar su costo (superficie de módulos cargables,vermagic, firma de módulos si además hay Secure Boot). Si no: hay que escribirlo como decisión explícita, para que dentro de un año nadie lo «arregle» encendiendo módulos en el kernel general creyendo que fue un olvido. -
¿
kexeces compatible con el destino de Secure Boot? ⛔ ABIERTA, y depende del 0018. Hoy no lo es: faltaKEXEC_FILEy sobra elkexec_loadviejo. Si el 0018 decide firmar, este ADR necesitaCONFIG_KEXEC_FILE=y+KEXEC_SIG, que re-hashea los seis kernels. Si el 0018 decide no firmar,kexecfunciona como está y esto se cierra sin costo.
Riesgos conocidos
- El cmdline está embebido (
CONFIG_CMDLINE_BOOL,linux-metal.toml:150) porque el arranque normal es por EFI-STUB.kexecno usa el stub: carga por el protocolo de boot de Linux, así que initrd y cmdline hay que pasárselos explícitos. El traspaso de la EFI memmap porsetup_dataconefi=novamappuesto es el punto a probar en QEMU antes de tocar metal — no está verificado y no debe darse por bueno. - El monolítico es una ventaja acá: sin módulos no hay
vermagicni/lib/modulesque se desincronicen. El modo de fallo clásico de «actualicé el kernel y no rebooteé» —enchufás un USB y no pasa nada porque el módulo ya no está en disco— no existe en takana. Vale anotarlo del lado del haber cuando se discuta el punto 1.