From 6b33d1a4350577cbda0859bf23264eb8421e4d61 Mon Sep 17 00:00:00 2001 From: Sergio Date: Tue, 22 Sep 2026 02:53:58 +0000 Subject: [PATCH] =?UTF-8?q?el=20frente=20kmod=20no=20existe:=20los=20kerne?= =?UTF-8?q?ls=20de=20takana=20no=20tienen=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fui a escribir el kmod en Rust que el plan pide —la pieza más grande que quedaba— y lo primero fue buscar contra qué módulos probarlo. No hay ninguno: · 0 ficheros .ko en los artefactos sellados de los cuatro kernels (sólo boot/bzImage y el .config) · 0 recetas del corpus hacen modules_install · 0 drivers `=m` en los .config sellados (contra 1809 `=y` en linux-metal) · `# CONFIG_MODULES is not set` en los tres kernels que están en el store · nadie en el repo enciende CONFIG_MODULES Sin CONFIG_MODULES el kernel ni siquiera implementa init_module/delete_module: un insmod escrito en Rust recibiría ENOSYS. Los 6 applets de kmod no son escritura, son 6 applets a retirar. Y con ellos otros 3: DEVTMPFS_MOUNT=y hace que el kernel cree y monte /dev, no hay UEVENT_HELPER, y libudev-zero ya viaja en los 8 perfiles ⇒ mdev, makedevs y uevent tampoco tienen consumidor. De los 23 applets que el plan llamaba «el trabajo real» queda: un ADR (awk), una migración de card (getty → agetty, que ya está en los 7 perfiles), y decidir nslookup (ningún candidato publica ese nombre; su único llamador es scripts/drive-netup.py y migrarlo sale más barato que traer BIND). Y la corrección que me toca: hace dos horas escribí en la salida del vigía, como advertencia, que «el kernel llama a /sbin/modprobe por call_usermodehelper ⇒ esos applets salen libres y no lo son». Es plausible, es la forma correcta de razonar, y es falsa para este producto. La escribí sin medirla, en el mismo commit donde presumía de haber arreglado dos falsos negativos. Corregida en el script. NO se recorta ahora: editar RETIRADOS re-hashea busybox y las 24 recetas que lo declaran build-dep, y 15 de esas 24 siguen en deuda por el recorte del 21/09. El siguiente recorte junta lo ya decidido y se hace una vez: 6 de kmod + 3 de /dev + 6 alias internos de iproute2 (ipaddr iplink ipneigh iproute iprule iptunnel, que no son comandos de nadie) = 15 applets, 277 → 262, sin escribir una línea. Co-Authored-By: Claude Opus 5 (1M context) --- docs/plan-botar-busybox.md | 63 ++++++++++++++++++++++++++++++++++++++ scripts/busybox-vigia.py | 10 ++++-- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/docs/plan-botar-busybox.md b/docs/plan-botar-busybox.md index 57234d36..52236dfa 100644 --- a/docs/plan-botar-busybox.md +++ b/docs/plan-botar-busybox.md @@ -1297,3 +1297,66 @@ Las dos reglas que quitan ruido son las mismas que crean ceguera, y la diferenci equivoca cada una. En el modo original —«¿alguien llama a algo que ya retiré?»— un falso positivo cuesta un minuto y un falso negativo cuesta un boot roto. En este modo pasa igual, así que ahora busca **tres formas**: nombre desnudo, ruta absoluta y primer elemento de `argv`. + +--- + +# El frente `kmod` no existe: los kernels de takana no tienen módulos (2026-09-22) + +**Cómo salió:** al ir a escribir el `kmod` en Rust que este plan pide —la pieza más grande que +quedaba, 6 applets— lo primero fue mirar contra qué módulos probarlo. **No hay ninguno.** + +| medida | resultado | +|---|---| +| `.ko` en los artefactos sellados de los 4 kernels | **0** — sólo `boot/bzImage` y el `.config` | +| recetas del corpus que hacen `modules_install` | **0** | +| drivers `=m` en los `.config` sellados | **0** (contra 1809 `=y` en `linux-metal`) | +| `CONFIG_MODULES` en los tres kernels del store | **`# CONFIG_MODULES is not set`** | +| quién enciende `CONFIG_MODULES` en el repo | **nadie** | + +Los cuatro kernels son monolíticos por construcción: `compile = "make … bzImage"` y +`install = "cp arch/x86/boot/bzImage /out/boot/"`. Sin `CONFIG_MODULES`, el kernel **ni siquiera +implementa `init_module`/`delete_module`** — un `insmod` escrito en Rust recibiría `ENOSYS`. + +> **Los 6 applets de kmod no son trabajo de escritura: son 6 applets a RETIRAR.** Y con ellos se van +> otros 3: `CONFIG_DEVTMPFS_MOUNT=y` hace que el kernel cree y monte `/dev` con sus nodos, no hay +> `CONFIG_UEVENT_HELPER` (o sea que el kernel no llama a ningún helper de hotplug), y `libudev-zero` +> ya viaja en los 8 perfiles. `mdev`, `makedevs` y `uevent` tampoco tienen consumidor. + +## Lo que esto le hace a la cuenta del plan + +De los **23 applets** que este documento llamó «el trabajo real», queda muy poco: + +| pieza | decía | es | +|---|---|---| +| kmod (6) | escribir en Rust | **retirar** — el kernel no tiene módulos | +| gestor de /dev (3) | escribir o decidir | **retirar** — devtmpfs + libudev-zero | +| psmisc (4) | traer | ✅ hecho (3; `killall5` es de sysvinit, lo cubre arje-zero por función) | +| bc (2) | traer | ✅ hecho | +| grep (3) · sed (1) | escribir en Rust | GNU declarado como puente ✅; el Rust nativo sigue siendo deseable, no urgente | +| getty (2) | escribir | **migrar**: `agetty` de util-linux está en los 7 perfiles | +| awk (1) | decidir | sigue siendo un ADR | +| nslookup (1) | traer | **decidir**: ninguno de los candidatos (ldns→`drill`, knot→`kdig`, doggo) publica `nslookup`; el único llamador es `scripts/drive-netup.py` y migrarlo es más barato que traer BIND | + +## Y la corrección que me toca a mí + +Hace dos horas escribí en la salida de `busybox-vigia.py --uso`, como advertencia: + +> «el KERNEL — llama a `/sbin/modprobe` por `call_usermodehelper` … `modprobe lsmod depmod rmmod +> modinfo mdev uevent makedevs` salen «libres» acá y no lo son: es el frente kmod, que es escritura +> pendiente, no un borrado.» + +**Es plausible, es la forma correcta de razonar, y es falsa para este producto.** La escribí sin +medirla, en el mismo commit en el que presumía de haber arreglado dos falsos negativos. Corregida en +el script. Es [[la-etiqueta-no-es-el-hecho]] exacta: la advertencia sonaba a experiencia y era una +suposición, y lo que la desarmó fue ir a buscar contra qué probar el código que iba a escribir. + +## Qué hacer con los 9 — y por qué NO ahora + +Retirarlos es editar `RETIRADOS` en `recipes/busybox.toml`, y eso **re-hashea busybox**. Las 24 +recetas que lo declaran build-dep se invalidan, y **15 de esas 24 siguen HOY en deuda por el recorte +del 2026-09-21** (`linux`, `llama-cpp`, `protobuf`, `qdrant`, `valkey`, `zlib-ng`, los firmware…). +Recortar otra vez ahora duplica ese trabajo para la granja. + +**El siguiente recorte junta todo lo que ya está decidido y se hace UNA vez:** los 6 de kmod, los 3 +de /dev, y los 6 alias internos de iproute2 (`ipaddr iplink ipneigh iproute iprule iptunnel`, que no +son comandos de nadie) — **15 applets, 277 → 262**, sin escribir una línea y sin reemplazar nada. diff --git a/scripts/busybox-vigia.py b/scripts/busybox-vigia.py index 4291dff5..0801343d 100755 --- a/scripts/busybox-vigia.py +++ b/scripts/busybox-vigia.py @@ -193,9 +193,13 @@ def modo_uso(): print() print('\u26a0 \u00abCandidato\u00bb NO es \u00abretirable\u00bb. Un grep ve a quien INVOCA por nombre, y hay dos clases de') print(' consumidor que no aparecen NUNCA y que rompen el producto si se les quita el applet:') - print(' \u00b7 el KERNEL — llama a /sbin/modprobe por call_usermodehelper, y al gestor de /dev por') - print(' hotplug. modprobe lsmod depmod rmmod modinfo mdev uevent makedevs salen \u00ablibres\u00bb acá') - print(' y no lo son: es el frente kmod, que es escritura pendiente, no un borrado.') + print(' \u00b7 el KERNEL — puede llamar a un helper de userspace sin que ningún grep lo vea.') + print(' ⚠ Acá NO: los cuatro kernels de takana traen `# CONFIG_MODULES is not set`, CERO') + print(' drivers `=m` y ninguna receta hace `modules_install` (medido 2026-09-22). Así que') + print(' modprobe/lsmod/depmod/rmmod/modinfo NO tienen consumidor, y con DEVTMPFS_MOUNT=y y') + print(' sin UEVENT_HELPER tampoco lo tienen mdev/makedevs/uevent. La advertencia sigue') + print(' valiendo como forma —un helper del kernel no aparece en un grep—, pero en ESTE') + print(' producto esos nueve son retirables, no escritura pendiente.') print(' \u00b7 el USUARIO de la máquina — clear, reset, vi, traceroute no los invoca ningún guión del') print(' repo y son la CLI que alguien espera encontrar al entrar por ssh.') print(' Lo que esta lista sí dice es cuáles no tienen consumidor DENTRO del producto: es el primer')