install-image: el store va ÚLTIMO y CRECE al disco entero en el primer arranque
Una imagen se escribe con `dd` sobre un disco casi siempre más grande que ella. La del perfil servidor son 7 G; la caja hcloud tiene 76,3 G. **Sobraban 69 G que nadie podía usar**, y la caja arrancaba perfecta con el disco a un décimo — el fallo que no falla, otra vez. Dos cambios que van juntos: 1. **El store pasa a ser la ÚLTIMA partición** (p1 bios, p2 `/`, p3 `/var/lib/hammer`, p4 `/store`). Sólo la última puede extenderse sin mover datos, y el store es justamente la que crece con el uso. Con él en el medio, la partición extensible era la de ESTADO, de 512 M, que no le sirve a nadie. El cambio es seguro porque nada referencia números de partición: `root=PARTLABEL=hammer-root` y el wrapper monta por etiqueta con `findfs`. 2. **El wrapper de `/sbin/init` la extiende en el primer arranque**, antes de montarla: `sfdisk -N <n> ', +'` → `partx -u` → `e2fsck -pf` → `resize2fs`. Idempotente: si ya llega al final, los dos últimos no hacen nada. Guardado tras `-x /sbin/sfdisk` para no romper un rootfs que no lo traiga, y el aviso va a `/dev/kmsg`, que es donde se lee. Probado en QEMU volcando la imagen de 7 G en un disco de 20 G: el arranque imprime `init: store: /dev/sda4 extendido al final de /dev/sda` y `/store` queda en **13,3 G** con 12,6 G libres, sin tocar nada a mano. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
This commit is contained in:
+54
-17
@@ -102,30 +102,67 @@ cat > "$ROOT_TREE/sbin/init" <<'INIT'
|
||||
#!/bin/sh
|
||||
# Wrapper PID1 (Etapa E/B3): el kernel montó la raíz; montamos las particiones dedicadas.
|
||||
#
|
||||
# El disco NO se cablea. Decía `/dev/vda3` y `/dev/vda4`, y eso vale sólo donde el disco es virtio-blk:
|
||||
# en una caja Hetzner Cloud la controladora es virtio-SCSI y el disco es `sda`, así que los dos
|
||||
# montajes fallaban —el sistema arrancaba igual, pero hammerd quedaba SIN /store y SIN diario, que es
|
||||
# el modo de fallo que llega hasta el final diciendo que todo fue bien—. Se deriva de dónde está
|
||||
# montada la raíz, que es la única fuente que no depende del nombre del dispositivo ni de udev.
|
||||
_root=$(/bin/busybox awk '$2=="/" {print $1; exit}' /proc/mounts)
|
||||
_disk=${_root%[0-9]}
|
||||
/bin/busybox mount -t ext4 "${_disk}3" /store || echo "init: no pude montar /store (${_disk}3)"
|
||||
/bin/busybox mount -t ext4 "${_disk}4" /var/lib/hammer || echo "init: no pude montar /var/lib/hammer (${_disk}4)"
|
||||
# Se busca por ETIQUETA, que es la que este mismo script pone con `mke2fs -L`. Las dos alternativas
|
||||
# que se probaron y NO sirven acá:
|
||||
# · `/dev/vda3` cableado — vale sólo con virtio-blk. En una caja Hetzner Cloud la controladora es
|
||||
# virtio-SCSI y el disco es `sda`, así que los montajes fallaban.
|
||||
# · derivar el disco de `/proc/mounts` — MEDIDO que no funciona: PID1 corre ANTES de que nadie
|
||||
# monte /proc, así que la lectura sale vacía. (Queda de respaldo, montando /proc primero.)
|
||||
# `findfs` sí funciona sin /proc: /dev ya está poblado por el kernel (DEVTMPFS_MOUNT=y).
|
||||
#
|
||||
# Y los avisos van a /dev/kmsg: un `echo` a stdout en PID1 se pierde antes de que haya consola —
|
||||
# por eso este wrapper falló en silencio la primera vez.
|
||||
_say() { echo "init: $*" > /dev/kmsg 2>/dev/null || echo "init: $*"; }
|
||||
_store=$(/bin/busybox findfs LABEL=hammer-store 2>/dev/null)
|
||||
_state=$(/bin/busybox findfs LABEL=hammer-state 2>/dev/null)
|
||||
if [ -z "$_store" ]; then
|
||||
_say "findfs no resolvió las etiquetas; derivo del disco de la raíz"
|
||||
/bin/busybox mount -t proc proc /proc 2>/dev/null
|
||||
_root=$(/bin/busybox awk '$2=="/" {print $1; exit}' /proc/mounts 2>/dev/null)
|
||||
_disk=${_root%[0-9]}
|
||||
[ -n "$_disk" ] && { _store="${_disk}3"; _state="${_disk}4"; }
|
||||
fi
|
||||
# ── Crecer el store al disco entero, ANTES de montarlo ──────────────────────────────────────
|
||||
# Una imagen se escribe con `dd` sobre un disco casi siempre MÁS GRANDE que ella: la del perfil
|
||||
# servidor son 7 G sobre los 76 G de una caja hcloud, o sea 69 G que nadie podía usar. Sin esto la
|
||||
# caja arranca perfecta y con el disco a un décimo — de nuevo el fallo que no falla.
|
||||
# Es idempotente: si la partición ya llega al final, `sfdisk` y `resize2fs` no hacen nada. Y sólo
|
||||
# toca la ÚLTIMA partición (por eso el store va último en el layout): extenderla no mueve datos.
|
||||
if [ -n "$_store" ] && [ -x /sbin/sfdisk ]; then
|
||||
_disk=$(echo "$_store" | /bin/busybox sed 's/[0-9]*$//; s/p$//')
|
||||
_num=$(echo "$_store" | /bin/busybox sed 's/^.*[^0-9]//')
|
||||
if [ -n "$_disk" ] && [ -n "$_num" ]; then
|
||||
if echo ', +' | /sbin/sfdisk --no-reread --force -N "$_num" "$_disk" >/dev/null 2>&1; then
|
||||
[ -x /usr/sbin/partx ] && /usr/sbin/partx -u "$_disk" >/dev/null 2>&1
|
||||
[ -x /sbin/e2fsck ] && /sbin/e2fsck -p -f "$_store" >/dev/null 2>&1
|
||||
[ -x /usr/sbin/resize2fs ] && /usr/sbin/resize2fs "$_store" >/dev/null 2>&1 \
|
||||
&& _say "store: $_store extendido al final de $_disk"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ -n "$_store" ] && /bin/busybox mount -t ext4 "$_store" /store || _say "no pude montar /store ($_store)"
|
||||
[ -n "$_state" ] && /bin/busybox mount -t ext4 "$_state" /var/lib/hammer || _say "no pude montar /var/lib/hammer ($_state)"
|
||||
exec /usr/bin/arje-zero
|
||||
INIT
|
||||
chmod +x "$ROOT_TREE/sbin/init"
|
||||
|
||||
# --- GPT: vda1=BIOS boot (ef02), vda2=/, vda3=/store, vda4=/var/lib/hammer ---
|
||||
# --- GPT: p1=BIOS boot (ef02), p2=/, p3=/var/lib/hammer, p4=/store ---
|
||||
#
|
||||
# EL STORE VA ÚLTIMO, Y ES A PROPÓSITO. Una imagen se escribe con `dd` sobre un disco que casi
|
||||
# siempre es MÁS GRANDE que ella (la del perfil servidor son 7 G sobre los 76 G de una caja hcloud),
|
||||
# y sólo la ÚLTIMA partición puede crecer sin mover nada. Con el store en el medio —como estaba— el
|
||||
# disco quedaba con 69 G inalcanzables y la partición que de verdad crece, la del store, congelada en
|
||||
# su tamaño de fábrica. El wrapper de /sbin/init la extiende en el primer arranque.
|
||||
SECT_MIB=2048
|
||||
BIOS_SECT=4096 # 2 MiB para core.img
|
||||
ROOT_SECT=$(( ROOT_SIZE * SECT_MIB ))
|
||||
STORE_SECT=$(( STORE_SIZE * SECT_MIB ))
|
||||
STATE_SECT=$(( STATE_SIZE * SECT_MIB ))
|
||||
STORE_SECT=$(( STORE_SIZE * SECT_MIB ))
|
||||
START1=2048
|
||||
START2=$(( START1 + BIOS_SECT ))
|
||||
START3=$(( START2 + ROOT_SECT ))
|
||||
START4=$(( START3 + STORE_SECT ))
|
||||
TOTAL_SECT=$(( START4 + STATE_SECT + 2048 ))
|
||||
START4=$(( START3 + STATE_SECT ))
|
||||
TOTAL_SECT=$(( START4 + STORE_SECT + 2048 ))
|
||||
BIOS_GUID="21686148-6449-6E6F-744E-656564454649" # GPT "BIOS boot partition"
|
||||
|
||||
# Target = block device (instalación in-place, Etapa E2 `takana install /dev/sdX`) o fichero imagen.
|
||||
@@ -145,8 +182,8 @@ sfdisk --quiet "$IMG" >/dev/null <<EOF
|
||||
label: gpt
|
||||
start=$START1, size=$BIOS_SECT, type=$BIOS_GUID, name="bios-boot"
|
||||
start=$START2, size=$ROOT_SECT, type=linux, name="hammer-root"
|
||||
start=$START3, size=$STORE_SECT, type=linux, name="hammer-store"
|
||||
start=$START4, size=$STATE_SECT, type=linux, name="hammer-state"
|
||||
start=$START3, size=$STATE_SECT, type=linux, name="hammer-state"
|
||||
start=$START4, size=$STORE_SECT, type=linux, name="hammer-store"
|
||||
EOF
|
||||
|
||||
# --- poblar las 3 particiones ext4 (root-owned vía unshare -r) y empalmar en su offset ---
|
||||
@@ -156,8 +193,8 @@ mke2fs -q -t ext4 -L hammer-root -E root_owner=0:0 -d "$ROOT_TREE"
|
||||
mke2fs -q -t ext4 -L hammer-store -E root_owner=0:0 -d "$ROOTFS/store" "$STORE_IMG" ${STORE_SIZE}M
|
||||
mke2fs -q -t ext4 -L hammer-state -E root_owner=0:0 -d "$ROOTFS/var/lib/hammer" "$STATE_IMG" ${STATE_SIZE}M
|
||||
dd if="$ROOT_IMG" of="$IMG" bs=512 seek=$START2 conv=sparse,notrunc status=none
|
||||
dd if="$STORE_IMG" of="$IMG" bs=512 seek=$START3 conv=sparse,notrunc status=none
|
||||
dd if="$STATE_IMG" of="$IMG" bs=512 seek=$START4 conv=sparse,notrunc status=none
|
||||
dd if="$STATE_IMG" of="$IMG" bs=512 seek=$START3 conv=sparse,notrunc status=none
|
||||
dd if="$STORE_IMG" of="$IMG" bs=512 seek=$START4 conv=sparse,notrunc status=none
|
||||
EOF
|
||||
|
||||
# --- instalar GRUB en userspace SIN root/loop: grub-mkimage arma core.img, y un patch binario
|
||||
|
||||
Reference in New Issue
Block a user