Differenza nell'esecuzione di init con initramfs integrati o esterni?


10

Sto costruendo un sistema Linux molto minimale che consiste solo nel kernel (v4.1-rc5) e in un initramfs popolato con busybox (v1.23.2). Funziona bene per la maggior parte, ma osservo una differenza nel comportamento dell'esecuzione del comando in / init se sto usando un initramfs incorporato rispetto a uno esterno.

Lo script / init è:

#!/bin/sh

dmesg -n 1

mount -t devtmpfs none /dev
mount -t sysfs none /sys
mount -t proc none /proc
echo "Welcome"
while true
do
    setsid cttyhack /bin/sh
done

Quindi ho impostato l'opzione CONFIG_INITRAMFS_SOURCE nel file .config del kernel sulla directory contenente tutte le cartelle per initramfs, oppure corro

find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz

per costruirlo.

Quando compilo quindi il kernel, con o senza il set CONFIG_INITRAMFS_SOURCE, finisco con due varianti del mio sistema:

  1. bzImage con initramfs incorporato

  2. bzImage + rootfs.cpio.gz (initramfs esterni)

quando inizio ora quelli che usano qemu

qemu-system-x86_64 -enable-kvm -kernel bzImage

o

qemu-system-x86_64 -enable-kvm -kernel bzImage -initrd rootfs.cpio.gz

Ottengo la seguente differenza di comportamento:

con la versione 2 (initramfs esterno) tutto funziona bene, viene visualizzato "Welcome" e viene visualizzato un messaggio. Tuttavia, con la versione 1 (initramfs incorporato) ricevo l'avviso

unable to open an initial console

"Benvenuto" non viene visualizzato e viene visualizzato il messaggio.

Per quanto ho capito il processo, quelle due versioni di initramfs dovrebbero contenere gli stessi file, dal momento che lo costruisco (o lo faccio compilare dal kernel) da una cartella identica.

Mi chiedo se qualcuno mi può aiutare con una spiegazione per questo comportamento?

* AGGIORNARE *

come ha detto mikeserv nei commenti, Il kernel include un initramfs incorporato minimo per impostazione predefinita. Questo è ancora presente quando si utilizza uno esterno, ma viene sovrascritto se si incorpora il proprio. Ho scoperto che contrariamente alle specifiche, questo non è in realtà vuoto, ma contiene una cartella dev, una cartella radice e il dispositivo / dev / console. Questo dispositivo viene quindi utilizzato quando si utilizza un initramfs esterno, ma sovrascritto se si incorpora il proprio. Quindi devi includere il dispositivo / dev / console nel tuo sorgente initramfs mknod -m 622 initramfs_src/dev/console c 5 1quando ne incorpori il tuo.

Grazie mille a Mikeserv, Frostschutz e JdeBP per avermi aiutato a risolvere il problema!


Quali sono le autorizzazioni impostate su /dev/consolesu quella integrata? Penso che la differenza potrebbe riguardare chi fa i bagagli nei due casi.
Mikeserv,

Una domanda simile è ovviamente stackoverflow.com/questions/10437995 .
JdeBP,

@mikeserv il dispositivo console ha autorizzazioni e proprietà identiche in entrambe le build.
clw

@JdeBP Non sono sicuro che sia così simile, poiché in entrambi i casi avvio, ricevo un prompt e ho un dispositivo console. Solo che in un init esegue l'eco e nell'altro non può.
clw

1
In che modo i permessi sarebbero stati gli stessi in initramfs se non lo avessi nemmeno avuto?
Mikeserv,

Risposte:


2

Sono davvero identici?

Quello integrato che puoi trovare /usr/src/linux/usr/initramfs_data.cpio.gzo estrarre dal bzImage come descritto qui: https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

Se usi quello incorporato e lo usi come esterno, funziona?

Se è ancora diverso, il kernel stesso è identico? (confronta /proc/config.gzper entrambi)

Dovrebbe esserci qualche differenza. Non sono a conoscenza del fatto che il kernel si preoccupi della provenienza di initramfs. Presto sospetterei qemudi usare impostazioni diverse quando passavo il -initrdparametro ...

Su un sidenote, il tuo /initsembra che stia generando infinite conchiglie per me. setsidnon lo è exec. Ho sbagliato?


1
Questa risposta sembra essere tutte le domande.
JdeBP,

1
@JdeBP: non stai pensando in quarta dimensione!
frostschutz,

1
@frostschutz Grazie mille per la tua risposta! Quando uso initramfs che il kernel costruisce (usr / initramfs_data.cpio.gz) come esterno funziona pure! Inoltre, quando fornisco il kernel che è stato compilato con gli initramfs integrati con uno esterno, appare l'avvertimento, anche se l'esterno dovrebbe sovrascrivere l'embedded ( kernel.org/doc/Documentation/filesystems/… ). Quindi probabilmente non è anche qemu -initrd ma qualcosa all'interno del kernel stesso. Non ho cambiato altro che CONFIG_INITRAMFS_SOURCE però ..
clw

@frostschutz Rispondere a On a sidenote, your /init looks like its spawning infinite shells to me. setsid is not exec. Am I wrong?: Il loop imita getty o strumenti simili, poiché chiama i shblocchi fino a quando quella shell non esce.
stefanjunker,

@stefanjunker e andrebbe bene, tranne setsid non blocca affatto ...
frostschutz

1

Potresti anche essere interessato a come Buildroot 2018.02 gestisce questo.

Ogni volta che usi initramfs ( BR2_TARGET_ROOTFS_INITRAMFS=y) o initrd ( BR2_TARGET_ROOTFS_CPIO=n), aggiunge quanto segue /initai tuoi rootfs https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/init

#!/bin/sh
# devtmpfs does not get automounted for initramfs
/bin/mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
exec /sbin/init "$@"

La copia è fatta da https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/cpio.mk :

# devtmpfs does not get automounted when initramfs is used.
# Add a pre-init script to mount it before running init
define ROOTFS_CPIO_ADD_INIT
    if [ ! -e $(TARGET_DIR)/init ]; then \
        $(INSTALL) -m 0755 fs/cpio/init $(TARGET_DIR)/init; \
    fi
endef

È anche utile sapere che il percorso di init è /initper initramfs, diversamente dal /sbin/initcontrario: cosa può far passare il programma init = / path / to / program al kernel non avviare il programma come init?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.