Virtualización

Cambiar de kernel sin apagar las cargas: qué son KHO y LUO (y qué falta para que lleguen a tu clúster)

Por Equipo Cloud Privado · · 14 min de lectura
Imagen de portada del artículo «Cambiar de kernel sin apagar las cargas: qué son KHO y LUO (y qué falta para que lleguen a tu clúster)»

Un vistazo en 30 segundos

  • KHO (Kexec HandOver) permite que ciertas regiones de memoria sobrevivan al salto de un kernel al siguiente mediante kexec. Entró en Linux 6.16, en julio de 2025.
  • LUO (Live Update Orchestrator) es la capa que coordina qué recursos se preservan y en qué orden. Se integró en Linux 6.19, en febrero de 2026, y lo firma Pasha Tatashin.
  • Detrás está Google, que ya lo usa en producción para aplicar parches de seguridad al kernel sin tirar las máquinas virtuales de encima.
  • Hoy lo que se preserva de verdad son descriptores memfd, es decir, memoria: la RAM del invitado. KVM, IOMMU y VFIO son trabajo en curso.
  • El espacio de usuario ya se está enganchando: systemd 261 (junio de 2026) preserva los FD Stores de las unidades a través de kexec con FileDescriptorStorePreserve=yes.
  • QEMU aporta su mitad desde antes, con los modos de migración CPR: cpr-reboot, cpr-transfer (QEMU 10.0) y cpr-exec (QEMU 10.2).
  • En un clúster de Proxmox VE esto no existe todavía: ni el changelog ni el roadmap mencionan nada. La forma de actualizar el kernel sin parar cargas sigue siendo migrar en vivo, reiniciar el nodo y volver.
  • No es hibernación ni magia: solo sobrevive lo que alguien ha programado para sobrevivir, y el formato de los datos preservados es explícitamente inestable.

Un kernel nuevo casi siempre significa reinicio. Si administras un nodo con cuarenta máquinas virtuales encima, eso quiere decir migrarlas a otro sitio, esperar, reiniciar y traerlas de vuelta, con lo que cada actualización de seguridad se convierte en un rato de trasiego en el que la plataforma va con menos capacidad de la que debería.

El parcheo en vivo (livepatch, kpatch, kGraft) alivia una parte, y solo una parte: sirve para arreglos pequeños y bien acotados, no para saltar de una versión de kernel a la siguiente. Para eso, hasta ahora, había que reiniciar.

KHO y LUO son el intento de arreglar exactamente eso, y desde febrero de 2026 los dos están dentro del kernel. Merece la pena entender qué hacen, porque va a marcar cómo se actualizan las plataformas de virtualización en los próximos años; y merece la pena entender qué no hacen todavía, porque hay mucho titular suelto por ahí.

TécnicaQué resuelveQué no resuelve
Livepatch / kpatchParches pequeños en caliente, sin reinicioCambiar de versión de kernel
Migración en vivo entre nodosActualizar un nodo entero vaciándolo antesNecesitas otro nodo con capacidad libre
KHO + LUOSaltar a otro kernel en el mismo host conservando memoriaAún preserva poco, y hay que programar cada pieza

KHO: que la memoria sobreviva al salto

kexec lleva desde 2004 permitiendo arrancar un kernel desde otro sin pasar por el firmware. Rápido, sí, pero con la memoria en blanco: el kernel nuevo arranca como si viniera de un apagado, y todo lo que había en RAM se pierde.

Kexec HandOver, obra sobre todo de Mike Rapoport, rompe esa suposición. Su trabajo es que determinadas regiones de memoria crucen el salto intactas. La API es corta a propósito: kho_preserve_folio() y kho_preserve_pages() marcan lo que debe sobrevivir, kho_restore_folio() lo recupera al otro lado.

Para que el kernel nuevo sepa qué se ha guardado y dónde, KHO construye un FDT propio, con el formato de un árbol de dispositivos aplanado pero sin su semántica: las propiedades van en el endianness nativo y no hay regs ni nada de lo que esperarías en un devicetree normal. La documentación avisa sin rodeos de que ese esquema es inestable y va a cambiar, así que hoy los dos kernels tienen que entenderse entre ellos.

La otra pieza es la scratch area: memoria físicamente contigua, reservada, en la que se coloca y arranca el kernel nuevo. Se declara como CMA precisamente para que ninguna página preservada acabe ahí, y se reserva por nodo NUMA más una global. En la línea de comandos son dos parámetros:

kho=on kho_scratch=16M,512M,256M

Los tres valores son memoria baja, global y por nodo NUMA. Hace falta CONFIG_KEXEC_HANDOVER en el kernel, y hay un detalle que sorprende a quien viene de usar kexec a mano: hay que cargar el kernel con kexec -s, el cargador de ficheros interno, porque las herramientas de espacio de usuario todavía no saben de KHO.

Con CONFIG_KEXEC_HANDOVER_DEBUGFS aparece /sys/kernel/debug/kho/, donde out/fdt muestra lo que se va a entregar e in/fdt lo que llegó del kernel anterior. El kernel apunta además qué versiones ha ido atravesando y cuántos arranques por kexec lleva encadenados, que para depurar un fallo raro después de tres saltos vale su peso en oro.

LUO: alguien tiene que decidir qué sobrevive y en qué orden

KHO mueve memoria. Lo que no hace es saber qué merece la pena mover, quién es su dueño ni cómo se reconstruye al otro lado. De eso se encarga el Live Update Orchestrator, la parte que firma Pasha Tatashin y que Google lleva meses empujando porque lo usa en su propia producción para meter parches de seguridad sin tocar las VM de los clientes.

El modelo es de sesiones. Un agente de espacio de usuario abre /dev/liveupdate, crea una sesión con nombre y va metiendo dentro los ficheros que deben sobrevivir. Cada tipo de fichero tiene un manejador registrado en el kernel con su juego de callbacks: can_preserve() para comprobar rápido si es viable, preserve() para el trabajo pesado de serializar, unpreserve() por si hay que abortar, freeze() justo antes del salto, retrieve() para reconstruirlo en el kernel nuevo y finish() para cerrar.

Por encima hay una máquina de estados sencilla de leer: NORMAL → PREPARED → FROZEN → UPDATED, con sus variantes de fallo. Los subsistemas se registran para recibir los eventos y hacer lo suyo en cada transición.

Las cuatro fases de un salto de kernel con LUO y KHO El salto se ordena en cuatro estados. En NORMAL, todavía sobre el kernel actual, un agente de espacio de usuario abre una sesión en /dev/liveupdate y va metiendo dentro los ficheros que deben sobrevivir. En PREPARED ese estado ya está serializado en el árbol de datos de KHO. En FROZEN se llama a freeze en cada manejador y se salta con kexec: si cualquiera falla, la actualización entera se aborta y se deshace. En UPDATED ya corre el kernel nuevo, y el agente recupera cada fichero con su token y cierra con finish. Lo único que cruza el salto es lo que KHO preservó, que hoy en la práctica es memoria: descriptores memfd. Todo lo demás, dispositivos y procesos incluidos, arranca de cero. requiere kho=on · liveupdate=on · kexec -s kernel actual kernel nuevo 1 · NORMAL la sesión recoge los ficheros que van a sobrevivir 2 · PREPARED el estado queda serializado en el árbol de KHO 3 · FROZEN congela y salta con kexec; si falla, se aborta kexec 4 · UPDATED retrieve() con el token y luego finish() al cerrar Lo único que cruza el salto es lo que KHO preservó: hoy, memoria (memfd). Dispositivos, sockets y procesos que no participan arrancan de cero.
Las cuatro fases de un salto de kernel con LUO y KHO El salto se ordena en cuatro estados. En NORMAL, todavía sobre el kernel actual, un agente de espacio de usuario abre una sesión en /dev/liveupdate y va metiendo dentro los ficheros que deben sobrevivir. En PREPARED ese estado ya está serializado en el árbol de datos de KHO. En FROZEN se llama a freeze en cada manejador y se salta con kexec: si cualquiera falla, la actualización entera se aborta y se deshace. En UPDATED ya corre el kernel nuevo, y el agente recupera cada fichero con su token y cierra con finish. Lo único que cruza el salto es lo que KHO preservó, que hoy en la práctica es memoria: descriptores memfd. Todo lo demás, dispositivos y procesos incluidos, arranca de cero. kho=on · liveupdate=on · kexec -s kernel actual 1 · NORMAL la sesión recoge lo que debe sobrevivir 2 · PREPARED el estado se serializa en el árbol de KHO 3 · FROZEN congela y salta; si algo falla, se aborta kexec kernel nuevo 4 · UPDATED retrieve() con el token y finish() al cerrar Solo cruza lo que KHO preservó: hoy, memoria (memfd). Lo demás arranca de cero.
Las tres primeras fases ocurren todavía en el kernel que se va; solo la última en el que llega. Y el punto de no retorno está en la tercera: si ahí falla algo, no hay salto y te quedas donde estabas.

El comportamiento ante errores está pensado con la cabeza fría, que es lo que uno quiere en algo así:

  • si falla el freeze() de cualquier manejador, se aborta la actualización entera y se deshace lo congelado;
  • si cierras el descriptor de la sesión antes del reinicio, se llama a unpreserve() en todo lo que había dentro;
  • la recuperación en el kernel nuevo es idempotente y puede hacerse en cualquier orden;
  • si falla el finish(), LUO se queda con la propiedad de esos ficheros en lugar de soltarlos a medias.

Se activa con liveupdate=on y su CONFIG_LIVEUPDATE; sin eso, las llamadas devuelven -EOPNOTSUPP y aquí no ha pasado nada. Y la documentación deja claro que el formato serializado es un contrato: tocar un campo de una estructura es un cambio que rompe y obliga a subir el número de versión.

En espacio de usuario, la referencia son un demonio (luod) y una herramienta de línea de comandos (luoctl) que disparan las transiciones. Nada de esto viene todavía empaquetado en una distribución de servidor.

No basta con el kernel: la cadena completa

Aquí está la parte que suele contarse mal. Que el kernel sepa preservar memoria no significa que tus cargas sobrevivan: hace falta que cada capa por encima participe. Y esa cadena está a medio montar.

PiezaQué aportaDesde
KHOPreservar regiones de memoria a través de kexecLinux 6.16 (jul 2025)
LUOOrquestar qué se preserva, con sesiones y estadosLinux 6.19 (feb 2026)
LUO en 7.2Sin límite de sesiones y ficheros, ioctls de creación y nombre de sesiónLinux 7.2 (ago 2026)
systemd 261PID 1 habla con LUO/KHO y preserva los FD Stores de las unidadesjun 2026
QEMU CPRMigrar la VM a una instancia nueva de QEMU en el mismo host10.0 y 10.2

De Linux 7.2, publicado hace dos días, salieron precisamente mejoras de LUO: se quitan los límites de sesiones y ficheros y llegan los ioctls LIVEUPDATE_IOCTL_CREATE_SESSION y LIVEUPDATE_SESSION_GET_NAME. Es un subsistema en obras, ciclo a ciclo.

systemd 261, de junio de 2026, es el primer sitio donde esto se toca sin escribir código propio: PID 1 detecta LUO y KHO si están habilitados, y los FD Stores de las unidades sobreviven al kexec si la unidad declara FileDescriptorStorePreserve=yes. Una unidad puede además crear su propia sesión LUO y guardarla en su FD Store, y systemd-nspawn puede persistir el del contenedor. Con una advertencia importante en las propias notas: de momento solo funciona con memfd.

Del lado de la virtualización, QEMU lleva su parte hecha desde antes, con la familia CPR (CheckPoint and Restart): cpr-reboot guarda la RAM del invitado y arranca una instancia nueva de QEMU; cpr-transfer, en QEMU 10.0, la deja en su sitio y transfiere los descriptores por un canal Unix con SCM_RIGHTS; y cpr-exec, en QEMU 10.2, reduce el consumo de recursos de la operación. No es gratis en configuración: la memoria del invitado tiene que estar respaldada por memoria compartida (share=on, -machine aux-ram-share=on) y hay incompatibilidades declaradas con postcopy, background-snapshot y COLO.

Junta las dos mitades y el resultado es lo que persiguen los proveedores cloud: actualizar QEMU y el kernel del host dejando la RAM del invitado donde está.

Qué sobrevive hoy de verdad

Poco, y conviene decirlo claro: memoria. Descriptores memfd, que es donde vive la RAM de un invitado si lo has montado así. Todo lo demás está en camino, y KVM, IOMMU y VFIO aparecen como los siguientes candidatos.

Todo lo que no tenga un manejador escrito para él se reinicializa como en cualquier arranque. Los dispositivos vuelven a inicializarse, los sockets del host se van al garete, los procesos que no participan en el juego mueren con el kernel viejo. Esto no es hibernar la máquina: es un arranque limpio al que se le entrega, con cuentagotas, un puñado de regiones de memoria que alguien se ha molestado en preparar.

Hay más limitaciones documentadas que conviene tener presentes:

  • la memoria pedida con vmalloc_node() no se restaura de forma fiable en el mismo nodo NUMA;
  • no se puede des-preservar un subrango arbitrario de un bloque grande;
  • el esquema del FDT es inestable por diseño y va a cambiar entre versiones;
  • kexec no pasa por el firmware, así que un salto de estos no aplica actualizaciones de BIOS/UEFI ni de firmware de dispositivos;
  • y la carga no sigue corriendo durante el salto: se congela, se salta y se recupera. Corto, pero no cero.

Ese último punto es el que más se malinterpreta. La promesa no es «cero paradas», es «una parada de milisegundos o segundos en vez de un reinicio completo con drenaje del nodo».

¿Y esto cuándo llega a un clúster de Proxmox?

Hoy, no. Ni el changelog de Proxmox VE 9.2 ni su roadmap mencionan kexec handover, live update ni CPR por ninguna parte, y eso que la versión ya va con kernel 7.0 y QEMU 11.0, o sea, con las piezas de base disponibles.

Tiene su lógica. Para que esto funcione en una plataforma real no basta con que el kernel sepa hacerlo: hace falta que el gestor de máquinas virtuales pida la memoria del invitado de la forma correcta, que alguien orqueste las sesiones, que el almacenamiento y la red del nodo aguanten el salto, y que todo eso se pueda deshacer sin dejar el sistema a medias. Es una cantidad de fontanería enorme para un beneficio que en un clúster bien montado ya tienes por otra vía.

Porque esa es la otra cara: en una plataforma con varios nodos, el problema que resuelven KHO y LUO ya está resuelto con migración en vivo. Vacías el nodo, lo reinicias con el kernel nuevo y lo vuelves a llenar, que es exactamente el procedimiento de una actualización nodo a nodo sin parada. El coste es tiempo y capacidad libre, no indisponibilidad.

Donde de verdad duele es en el otro escenario: el nodo único sin sitio a donde migrar, o el hiperescalar con millones de máquinas donde vaciar servidores para parchear cuesta una fortuna en capacidad ociosa. Ahí es donde Google ha puesto el dinero, y por eso ha salido de ahí.

Para nosotros hay un caso intermedio que sí conviene vigilar: los contenedores LXC comparten el kernel del host, así que reiniciar un nodo los para todos a la vez, y no se migran en vivo como una máquina virtual. Si algún día LUO llega a preservar más que memoria, ese es el escenario donde más se notaría en un cloud privado. Es una razón más para tener claro qué carga va en contenedor y cuál en máquina virtual.

Por qué esto importa aunque no lo vayas a usar

Un mecanismo así cambia la economía de parchear. Cuando aparece un fallo serio en el kernel, como el de bad_epoll, la conversación es siempre la misma: hay parche, hay que reiniciar, y reiniciar cuesta. Todo lo que abarate ese reinicio hace que se parchee antes y más a menudo, y eso es una mejora de seguridad aunque no aparezca en ninguna lista de funciones.

También tiene su lectura para quien compra infraestructura. Cuando un proveedor te diga que actualiza el kernel «sin impacto», la pregunta útil es cómo: si es migrando cargas entre nodos, necesita capacidad libre y te lo está cobrando en algún sitio; si es con parcheo en vivo, solo cubre arreglos pequeños; y si algún día es con KHO y LUO, pregunta qué se preserva exactamente, porque hoy la respuesta honesta es «la memoria, y poco más».

Cómo lo miramos nosotros

En las plataformas que gestionamos, la actualización del kernel se planifica con la herramienta que ya funciona: capacidad de reserva suficiente para vaciar un nodo, migración en vivo, reinicio, comprobación y vuelta a llenar. Sin heroicidades ni funciones experimentales en producción.

KHO y LUO los seguimos con interés, y el criterio para tocarlos será el de siempre: cuando lleguen empaquetados por la distribución, con soporte de la plataforma de virtualización por encima y con una forma clara de volver atrás si el salto sale mal. Un mecanismo que preserva memoria entre dos kernels es justo el tipo de cosa que no quieres estrenar tú.

Si tu plataforma no tiene hoy capacidad para vaciar un nodo y reiniciarlo sin que se note, ese es el problema que hay que resolver, y no depende de ninguna novedad del kernel. Mira nuestras páginas de alta disponibilidad y de servicios gestionados, o cuéntanos cómo lo tienes montado y te decimos qué margen te falta para poder parchear tranquilo.

Preguntas frecuentes

¿KHO y LUO permiten actualizar el kernel sin parar nada?

No exactamente. Reducen la parada de un reinicio completo a una congelación breve mientras se salta al kernel nuevo por kexec, y solo para los recursos que se hayan preparado explícitamente para sobrevivir. Hoy eso significa memoria, en la práctica descriptores memfd.

¿En qué versiones del kernel están?

KHO se integró en Linux 6.16 (julio de 2025) y LUO en Linux 6.19 (febrero de 2026). Linux 7.2, de agosto de 2026, ha seguido ampliando LUO quitando los límites de sesiones y ficheros y añadiendo ioctls nuevos.

¿Es lo mismo que el parcheo en vivo del kernel?

No. El parcheo en vivo (livepatch, kpatch) sustituye funciones concretas en un kernel que sigue corriendo, y sirve para arreglos acotados. KHO y LUO cambian el kernel entero por otro, incluida una versión distinta, conservando algunas regiones de memoria.

¿Puedo usarlo ya en Proxmox VE?

No hay soporte. Proxmox VE 9.2 lleva kernel 7.0 y QEMU 11.0, así que las piezas de base están, pero ni el changelog ni el roadmap recogen nada de kexec handover ni de los modos CPR de QEMU. La vía practicable sigue siendo la migración en vivo nodo a nodo.

¿Qué necesita una máquina virtual para que su memoria sobreviva?

Que su RAM esté respaldada por memoria compartida y que el proceso que la gestiona participe en la orquestación. En QEMU son los modos CPR, con share=on en el backend de memoria y -machine aux-ram-share=on, y con incompatibilidades declaradas como postcopy, background-snapshot y COLO.

¿Sirve para saltarse un reinicio por actualización de firmware?

No. kexec arranca el kernel nuevo sin pasar por el firmware, así que las actualizaciones de BIOS/UEFI, de microcódigo aplicado por firmware o de controladoras siguen necesitando un reinicio de verdad.

Fuentes