make localmodconfig && make localyesconfig
o número de parâmetros diminuiu para 1285. Tornou-se interessante para mim tentar jogar fora todas as coisas desnecessárias do kernel e ver o que acontece.
Estarei compilando o kernel vanilla 5.4.0 porque essa é a versão usada na minha instalação do gentoo. Para acelerar o processo, eu compilo o kernel na minha máquina de trabalho (i7, 8 núcleos, 64 Gb RAM, tmpfs). Copio o kernel finalizado para a máquina em nuvem oracle. Você precisa iniciar o processo com o comando:
make tinyconfig
Isso lhe dará um arquivo .config para o núcleo mínimo da arquitetura atual. No meu caso, este arquivo contém 284 linhas não em branco que não são comentários.
Vamos compilá-lo e ver o tamanho do kernel:
$ yes ""|make -j$(nproc)
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 441872 Jan 31 18:09 arch/x86/boot/bzImage
284
$
Este kernel é completamente inútil. Não apenas não inicializa, como também não tem a capacidade de relatar problemas. Vamos consertar isso. Para ativar os parâmetros, usarei o comando:
script/config -e config_parameter_name
Portanto, nosso kernel será de 64 bits, ativamos a saída de diagnóstico do kernel, habilitamos o suporte ao terminal, configuramos a porta serial e o console nele:
./scripts/config -e CONFIG_64BIT -e CONFIG_PRINTK -e CONFIG_TTY -e CONFIG_SERIAL_8250 -e CONFIG_SERIAL_8250_CONSOLE
Uma máquina em nuvem oracle não será capaz de inicializar com este kernel, não haverá saída para o console. Como se viu, você precisa adicionar suporte para EFI e ACPI, que é sua dependência. O script ./scripts/config não implementa a lógica para adicionar dependências reversas, ou seja, se você adicionar apenas CONFIG_EFI, make irá remover este parâmetro da configuração. Também é importante notar que as opções de ativação geralmente incluem as opções abaixo. Portanto, no caso de habilitar CONFIG_ACPI, ele é habilitado automaticamente, por exemplo, suporte para o botão liga / desliga.
./scripts/config -e CONFIG_ACPI -e CONFIG_EFI -e CONFIG_EFI_STUB
Juntando o núcleo:
$ yes ""|make -j$(nproc)
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 1036960 Jan 31 18:13 arch/x86/boot/bzImage
409
$
Este kernel ainda não pode completar o processo de inicialização, mas pelo menos é capaz de relatá-lo:
Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance.
Kernel Offset: 0x22000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
---[ end Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance. ]---
Vamos adicionar os parâmetros necessários:
# virtual guest support and pci
./scripts/config -e CONFIG_PCI -e CONFIG_VIRTIO_PCI -e CONFIG_VIRTIO -e CONFIG_VIRTIO_MENU -e CONFIG_PARAVIRT -e CONFIG_HYPERVISOR_GUEST
# disk support
./scripts/config -e CONFIG_BLOCK -e CONFIG_SCSI -e CONFIG_BLK_DEV_SD -e CONFIG_SCSI_VIRTIO
# filesystems
./scripts/config -e CONFIG_EXT4_FS -e CONFIG_PROC_FS -e CONFIG_SYSFS -e CONFIG_DEVTMPFS -e CONFIG_DEVTMPFS_MOUNT
# executable formats
./scripts/config -e CONFIG_BINFMT_ELF -e CONFIG_BINFMT_SCRIPT
# network
./scripts/config -e CONFIG_NET -e CONFIG_VIRTIO_NET -e CONFIG_PACKET -e CONFIG_UNIX -e CONFIG_INET -e CONFIG_NET_CORE -e CONFIG_NETDEVICES -e CONFIG_VIRTIO_NET
Juntando o núcleo:
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 1950368 Jan 31 18:18 arch/x86/boot/bzImage
616
$
E estamos carregados. Desta vez, o kernel encontra com sucesso o disco raiz, mas vemos erros no console:
The futex facility returned an unexpected error code. ... * Call to flock failed: Function not implemented
Estamos tentando fazer login:
(none) login: root
process 182 (login) attempted a POSIX timer syscall while CONFIG_POSIX_TIMERS is not set
Password:
setgid: Function not implemented
Também não funciona, mas somos indagados de forma inequívoca sobre qual parâmetro adicionar. Adicione-o e outros parâmetros necessários:
./scripts/config -e CONFIG_POSIX_TIMERS -e CONFIG_FUTEX -e CONFIG_FILE_LOCKING -e CONFIG_MULTIUSER
Juntando o núcleo:
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 1979040 Jan 31 18:25 arch/x86/boot/bzImage
623
$
Desta vez, conseguimos fazer o login:
instance-20210124-1735 login: root
Password:
Last login: Mon Feb 1 02:25:10 UTC 2021 from 73.239.106.74 on ssh
root@instance-20210124-1735:~#
Hooray! Ssh também funciona. No entanto, existem erros no console novamente:
* Some local filesystem failed to mount
...
hwclock: Cannot access the Hardware Clock via any known method.
hwclock: Use the --verbose option to see the details of our search for an access method.
* Failed to set the system clock
E no dmesg também encontramos:
[ 2.910198] udevd[360]: inotify_init failed: Function not implemented
Adicionamos suporte para relógio em tempo real, sistema de arquivos vfat e inotify:
./scripts/config -e CONFIG_RTC_CLASS -e CONFIG_DNOTIFY -e CONFIG_INOTIFY_USER -e CONFIG_VFAT_FS
Juntando o núcleo:
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 2015904 Jan 31 18:36 arch/x86/boot/bzImage
643
$
Hmmm, a unidade vfat ainda não consegue montar:
* Some local filesystem failed to mount
E aqui está a resposta por que em dmesg junto com mais um erro:
[ 3.782884] udevd[527]: error creating signalfd [ 4.107698] FAT-fs (sda15): codepage cp437 not found
Adicione parâmetros:
./scripts/config -e CONFIG_SIGNALFD -e CONFIG_NLS_CODEPAGE_437 -e CONFIG_NLS_ISO8859_1
Juntando o núcleo:
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 2015904 Jan 31 18:41 arch/x86/boot/bzImage
646
$
Nós carregamos, não há erros no console, mas um novo erro apareceu no dmesg:
[ 2.756136] udevd[360]: error creating epoll fd: Function not implemented
Nós consertamos:
./scripts/config -e CONFIG_EPOLL
Juntando o núcleo:
$ ll arch/x86/boot/bzImage && grep -v ^# .config|grep -c .
-rw-rw-r-- 1 kvt kvt 2020000 Jan 31 19:13 arch/x86/boot/bzImage
647
$
Reinicializamos e desta vez não vemos novos erros!
Na minha máquina de trabalho (i7, 8 núcleos, 64 gb RAM, tmpfs), a configuração final é construída em 1m 16s. Na nuvem oracle com dois núcleos e em um disco normal, o mesmo processo leva 19m 51s.
O kernel resultante não é absolutamente mínimo. Assim, por exemplo, habilitar o suporte à rede adiciona vários adaptadores de rede diferentes. Não me envolvi no perfeccionismo e limpei absolutamente tudo o que não é necessário. Além disso, quero avisá-lo que, embora o carregamento e o teste rápido não revelem problemas com a ausência de outros componentes importantes do kernel, eles provavelmente existem. Então, se de repente você decidir reutilizar minha configuração por favor, teste o kernel completamente para o seu caso particular e adicione os parâmetros de kernel necessários, se necessário.