KERNEL
Transcripción
KERNEL
Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux KERNEL 2.1 LINUX ES UN KERNEL El kernel es la parte central, el corazón de un sistema operativo, que se carga primero y permanece en memoria principal todo el tiempo, administrando el uso del hardware. Mínimamente, el kernel es responsable de administrar la memoria principal, los procesos (scheduling) y la comunicación entre ellos (IPC). Linux es, precisamente, un kernel. Es capaz de cargar módulos en tiempo de ejecución, permitiendo así extender su funcionalidad a discreción, y por otra parte, manteniendo la cantidad de código ejecutándose en el “espacio del kernel” (en memoria primaria) en el mínimo posible. En el kernel de Linux deben estar incluidos los controladores (drivers) de los dispositivos que vayan a utilizarse. Por ejemplo, si se desea instalar un dispositivo SCSI en el sistema, el kernel debe soportarlo (esto es, tener la opción de “entenderse” con el dispositivo), y tener incorporados los drivers correspondientes estáticamente, o cargarlos dinámicamente (desde un módulo). De no ser así, habrá que crear un kernel que tenga los drivers necesarios. Lo mismo sucede con todas y cada una de las características atribuibles a Linux, como ser NAT, filtrado de paquetes con iptables o ipchains, sistemas de archivo (NTFS, ext2, ext3), lenguajes soportados, etc. 2.2 CUANDO ES NECESARIO COMPILAR UN KERNEL En general, configurar, compilar e instalar un nuevo kernel es una tarea que requiere mucho cuidado, puesto que un error en la configuración o en el proceso de instalación puede llevar a la pérdida del acceso a la máquina. Consideremos por ejemplo, una máquina que se encuentra en algún lugar remoto del planeta, a la que accedemos gracias a que esta se conecta a Internet de manera automática usando PPPoE. Si recompilamos un nuevo kernel y no incluimos el soporte para PPPoE, la máquina no podrá conectarse a Internet, y de no contar con un mecanismo remoto alternativo para acceder a ella, alguien tendrá que ir en persona a solucionar ese problema. Por eso es bueno siempre preguntarse antes de instalar un nuevo kernel si realmente hace falta. Es necesario compilar un nuevo kernel ante los siguientes casos: Módulo II: Kernel 1 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux a. Es preciso aplicar actualizaciones de seguridad y bugfixes en el código del kernel. b. Se necesitan actualizaciones de drivers existentes. c. Se necesitan nuevas funcionalidades y drivers. Por ejemplo, ciertas aplicaciones sólo funcionan con kernels superiores a cierta versión, no se encuentran drivers para Serial ATA en kernels 2.2.x, etc. d. Se requiere cierta característica al inicio del sistema que antes no era necesaria (ej., se migra el sistema de archivo del dispositivo raíz de reiserfs a ext3) y no se desea hacer un Disco RAM inicial (initial RAMdisk). e. Se desea reducir el tamaño del kernel sacando todo el código que pueda ser cargado como módulo. Esto es muchas veces necesario para hacer entrar el kernel en un disquete y hacer así un disco de arranque. Del listado anterior, los casos a, b y c suponen la instalación de una nueva versión del kernel. Si no es necesaria una nueva versión de Linux, el caso d enuncia probablemente la única situación en la cual es obligatorio compilar un nuevo kernel. Esto sucede más que nada cuando se hacen cambios relativos al sistema de archivos raíz, puesto que en la secuencia de arranque, primero debe ser montada la raíz para que luego puedan ser accedidos los módulos del kernel. Un recurso disponible para evitar la compilación de un nuevo kernel en estos casos es utilizar un disco RAM inicial (initial RAMdisk). Este es una imagen de un disco, que contiene un sistema de archivos raíz que se carga en memoria al iniciar el sistema, y en él se incluyen los módulos necesarios para montar posteriormente la raíz real del sistema (ej.: SCSI, LVM, ext3). El manejo del disco RAM inicial está asignado al cargador de arranque (bootloader), por ende es preciso indicarle a este su existencia y ubicación en su archivo de configuración. Luego de su utilización, al montar la raíz real del sistema, la memoria es liberada para su posterior utilización. Finalmente, en los casos restantes no es necesario compilar un nuevo kernel. Por ejemplo, para agregar NAT o el driver de cierto adaptador SCSI que ya esté incluido en el código fuente de Linux (de la misma versión en ejecución) basta con compilar e instalar un módulo, y ni siquiera hace falta reiniciar el equipo para comenzar a utilizar la nueva funcionalidad. Esta es una práctica que posee varias ventajas (menor tiempo de compilación, menor riesgo de perder el control del sistema y otras que serán evidentes cuando veamos los módulos con mayor detalle) y debe utilizarse siempre que sea posible. Módulo II: Kernel 2 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux 2.3 REQUISITOS Para compilar un kernel reciente (versión 2.4.x o 2.6.x) se necesitan aproximadamente 300 MB de espacio en disco. Es un proceso que requiere gran capacidad de procesamiento, por lo que puede tardar horas en máquinas de pocos recursos. Además, es preciso tener el compilador de C (gcc) y las librerías (libc) de versiones indicadas en el archivo README que está junto con el código fuente del kernel. 2.4 OBTENCIÓN DEL KERNEL SuSE presenta un método sencillo para actualizar el kernel de la distribución, mediante YOU (YaST Online Updater) o los CDs de actualización. Una vez realizada la instalación, el próximo reinicio cargará el nuevo kernel. Estos kernels vienen optimizados para la familia de procesadores utilizados por el equipo (Athlon, P4, PIII, etc.) y con la más amplia gama de drivers posibles, compilados como módulos. Además, corrigen errores de versiones previas y fallas de seguridad. No hace falta compilar estos kernels, aunque en caso de estar instalado el código fuente del kernel, también se bajará e instalará el código fuente del nuevo kernel, sin borrar el anterior, en /usr/src/: srvlinux:/usr/src # dir total 804 drwxr-xr-x 12 root root drwxr-xr-x 12 root root lrwxrwxrwx 1 root root drwxr-xr-x 18 root root drwxr-xr-x 8 root root drwxr-xr-x 18 root root drwxrwxr-x 22 root root lrwxrwxrwx 1 root root 2.4.21-260-include drwxr-xr-x 7 root root 4096 Dec 2 4096 Jan 13 16 Dec 1 4096 Dec 2 4096 Dec 1 4096 Dec 1 4096 Nov 28 24 Dec 4096 Jan 13 08:35 . 2003 .. 13:27 linux -> linux-2.4.21-260 08:25 linux-2.4.21-260 13:27 linux-2.4.21-260-include 13:30 linux-2.4.21-99 04:54 linux-2.6.9 1 13:28 linux-include -> linux2003 packages Podemos ver en este listado de directorio 3 versiones de kernel. La 2.4.21-99 es la que viene con SuSE 9.0, una actualización online hecha en Diciembre de 2004 instaló la 2.4.21-260, y finalmente una versión que no viene con el sistema original de SuSE, la 2.6.9. El vínculo simbólico “linux” es apuntado directamente a la versión actualizada del kernel de manera automática. Este vínculo sirve para que ciertos programas que necesitan para su compilación el código fuente del kernel (iptables, por ejemplo) puedan encontrar la versión adecuada. Saliendo ya del kernel distribuido y respaldado por SuSE, tanto la última versión del código fuente del kernel de Linux como las anteriores, se pueden encontrar en www.kernel.org (The Linux Kernel Archives, LKA) y sus sitios espejos. Módulo II: Kernel 3 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Los archivos con el código fuente vienen “empaquetados” en formato tar, y comprimidos en ambos formatos gzip y bzip2. Por lo tanto, encontraremos en este sitio archivos tales como linux2.6.7.tar.bz2 y linux-2.6.7.tar.gz, que son el mismo código fuente comprimido con bzip2 y gzip respectivamente. 2.4.1 Verificación de autenticidad Es indispensable para la seguridad del sistema verificar la autenticidad del kernel que vamos a instalar. Un kernel adulterado implica un riesgo de seguridad muy alto. Los archivos puestos en www.kernel.org son automáticamente firmados con OpenPGP. Esta firma puede ser usada para probar que el archivo, que puede haber sido obtenido desde uno de los sitios espejos u otra ubicación, realmente es copia del archivo publicado por LKA. La llave pública OpenPGP de LKA siempre estará en http://www.kernel.org/signature.html, junto con cualquier certificado de revocación pertinente. Esta firma, sin embargo, no garantiza que el sitio maestro de LKA no haya sido comprometido. De todos modos, en caso de sufrir alguna intrusión, la clave pública será revocada e se publicará información tan rápido como sea posible en la página mencionada. Se recomienda no usar versiones de GnuPG anteriores a 1.0.6, dado que se recibieron reportes de que estas versiones dieron por válida una firma incorrecta. SuSE instala por defecto GnuPG, y el procedimiento para verificar una firma del kernel es el siguiente: 1. Importar la clave pública de LKA: gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517D0F0E 2. Verificar: gpg --verify linux-2.6.9.tar.gz.sign linux-2.6.9.tar.gz En caso de que la firma sea buena, se presentará el siguiente mensaje: gpg: Signature made Mon Oct 18 19:19:21 2004 GMT+3 using DSA key ID 517D0F0E gpg: Good signature from "Linux Kernel Archives Verification Key <[email protected]>" gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Módulo II: Kernel 4 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Se lee Good signature from “Linux Kernel Archives Verification Key [email protected]”, lo que confirma la autenticidad. La advertencia (“WARNING:…”) indica que si bien tenemos la clave pública, no hay certificación de que la clave pertenezca a LKA. Para tener esa certeza, habría que hacer un camino de confianza (“trusted path”) hasta el que firmó la clave pública de LKA, lo que queda a criterio de cada administrador. 2.5 CONFIGURACIÓN Se procede a descomprimir y desempacar el código fuente (que está en formato .tar.gz o .tar.bz2), preferentemente en /usr/src, con lo que se crea un subdirectorio con la versión del kernel, por ejemplo, linux-2.6.9. El paso siguiente es configurar el kernel. Para ello se puede usar make config (no recomendado, porque pregunta secuencialmente por cada una de las características posibles), make menuconfig (bastante amigable, recomendado, puesto que utiliza un sistema de menús en la consola) o make xconfig (desde entorno X). Nos basaremos en menuconfig de aquí en más. Ahí se presentarán todas las opciones con las que se puede armar un kernel, junto con ayuda (en inglés) de la mayoría de ellas. Estas opciones presentarán una casilla de verificación representada por corchetes [ ], y las que vayan a ser incluidas llevarán un asterisco en la casilla [*]; en los casos en los que la opción pueda ser compilada como módulo, la tendrá este formato: < > que podrá estar vacío, llevar un asterisco o una M cuando se seleccione la opción de módulo. Para alternar entre las opciones se puede usar la barra espaciadora, o directamente Y (para incluir la opción estáticamente en el kernel), N (para deshabilitar la opción) y M (para incluirla como módulo). Presionando el signo de cierre de interrogación (“?”) se presenta la ayuda correspondiente al ítem resaltado. Esta interfaz crea un archivo que contiene todas las opciones elegidas, y permite guardarlo con un nombre diferente al predeterminado (que es “.config”), en la opcion “Save Configuration to an Alternate File”. También permite cargar un archivo distinto al predeterminado, mediante “Load an Alternate Configuration File”. Al salir nos pregunta si deben guardarse los cambios y se genera este archivo, que nos permitirá realizar la compilación. Si se desea configurar un kernel exactamente como el que se está ejecutando, se puede utilizar make cloneconfig, que obtiene la configuración de /proc/config.gz y la pone en el archivo .config. Esta es una característica de SuSE, no necesariamente presente en otras distribuciones ni en el kernel de LKA. Para ver esa configuración, se puede ejecutar zcat /proc/config.gz | less, ya no sólo en SuSE sino en cualquier kernel que soporte /proc/config.gz. Módulo II: Kernel 5 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux 2.5.1 Módulos Son partes del código del kernel que pueden ser cargados y descargados de la memoria en función de la necesidad. Por ejemplo, un tipo de módulo son los drivers de dispositivo, que permiten al kernel acceder al hardware conectado al sistema. Como se dijo anteriormente, los módulos tienen la ventaja de extender la funcionalidad del kernel sin que esto implique tener un kernel gigante, y sobre todo, sin necesidad de recompilar el kernel y reiniciar la máquina cada vez que se quiera agregar un driver por ejemplo. Los módulos pueden compilarse separadamente del resto del kernel, y ser cargados dinámicamente, siempre y cuando la opción correspondiente (automatic kernel module loading, activa por defecto) esté compilada en el kernel. La tendencia actual es compilar como módulos todo lo que no sea indispensable para el arranque. Consideremos tener por ejemplo una partición root de tipo ext3, y un CDROM atapi. No es recomendable configurar el sistema de archivos ext3 como módulo, pues hasta que kmod comience a ejecutar, no podrá ser cargado; sin embargo, sería bueno que el controlador del CDROM fuera un módulo. Sin embargo, hay que considerar el siguiente escenario como un contraejemplo de lo anteriormente expuesto. SuSE, RedHat, Mandrake, etc. deben preparar sus kernels para hacer arrancar la más variada gama de configuraciones de hardware. Por lo tanto, las funciones compiladas necesarias para cubrir todos los casos harían un kernel muy grande, o serían necesarias varias (demasiadas) versiones de kernels. Este problema es resuelto creando un kernel genérico mínimo y un initial RAMdisk con todos los controladores posibles. 2.5.2 Parches Son fragmentos de código fuente destinados a agregar funciones o reparar errores en un programa. Sólo se especifican los fragmentos relevantes, que deben ser agregados, eliminados o reemplazados, por lo que el tamaño de los parches es óptimo. Se aplican sobre el código fuente, por ejemplo, de la siguiente manera: srvlinux:/usr/src # cd linux-2.4.21-260 srvlinux:/usr/src/linux-2.4.21-260 # patch -p1 -i ../linux-2.4.21-imq1.diff.ernesto patching file Documentation/Configure.help Hunk #1 succeeded at 9520 (offset 699 lines). patching file drivers/net/Config.in patching file drivers/net/imq.c Módulo II: Kernel 6 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux patching file drivers/net/Makefile Hunk #1 succeeded at 192 with fuzz 1 (offset 33 lines). patching file include/linux/imq.h patching file include/linux/netfilter_ipv4/ipt_IMQ.h patching file include/linux/skbuff.h Hunk #2 succeeded at 185 (offset 4 lines). Hunk #3 succeeded at 222 (offset 4 lines). patching file net/core/skbuff.c Hunk #2 succeeded at 254 (offset 1 line). Hunk #3 succeeded at 408 (offset 2 lines). Hunk #4 succeeded at 456 (offset 3 lines). patching file net/ipv4/netfilter/Config.in Hunk #1 succeeded at 106 with fuzz 2 (offset 3 lines). patching file net/ipv4/netfilter/Makefile Hunk #1 succeeded at 94 (offset 3 lines). patching file net/ipv4/netfilter/ipt_IMQ.c patching file net/sched/sch_generic.c Para más información sobre el comando patch, ver man patch. Un parche puede ser revertido, esto es, dejar todo como estaba antes, con el parámetro -R: srvlinux:/usr/src/linux-2.4.21-260 # patch -R -p1 -i ../linux-2.4.21-imq1.diff.ernesto patching file Documentation/Configure.help Hunk #1 succeeded at 9520 (offset 699 lines). patching file drivers/net/Config.in patching file drivers/net/imq.c patching file drivers/net/Makefile Hunk #1 succeeded at 192 with fuzz 1 (offset 33 lines). patching file include/linux/imq.h patching file include/linux/netfilter_ipv4/ipt_IMQ.h patching file include/linux/skbuff.h Hunk #2 succeeded at 182 (offset 4 lines). Hunk #3 succeeded at 219 (offset 4 lines). patching file net/core/skbuff.c Hunk #2 succeeded at 250 (offset 1 line). Hunk #3 succeeded at 400 (offset 2 lines). Hunk #4 succeeded at 444 (offset 3 lines). patching file net/ipv4/netfilter/Config.in Hunk #1 succeeded at 106 with fuzz 2 (offset 3 lines). patching file net/ipv4/netfilter/Makefile Hunk #1 succeeded at 94 (offset 3 lines). patching file net/ipv4/netfilter/ipt_IMQ.c patching file net/sched/sch_generic.c 2.5.3 El archivo .config Módulo II: Kernel 7 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Como dijimos anteriormente, este archivo contiene toda la información referida a la configuración de un kernel. Se lo puede editar normalmente con cualquier editor de texto. Un fragmento de este archivo podría ser: # # Automatically generated make config: don't edit # CONFIG_X86=y # CONFIG_SBUS is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y # # Loadable module support # CONFIG_MODULES=y CONFIG_MODVERSIONS=y CONFIG_KMOD=y # # Processor type and features # # CONFIG_M386 is not set # CONFIG_M486 is not set # CONFIG_M586 is not set # CONFIG_M586TSC is not set # CONFIG_M586MMX is not set # CONFIG_M686 is not set # CONFIG_MPENTIUMIII is not set # CONFIG_MPENTIUM4 is not set # CONFIG_MK6 is not set CONFIG_MK7=y # CONFIG_MK8 is not set # CONFIG_MELAN is not set # CONFIG_MCRUSOE is not set # CONFIG_MWINCHIPC6 is not set # CONFIG_MWINCHIP2 is not set # CONFIG_MWINCHIP3D is not set # CONFIG_MCYRIXIII is not set # CONFIG_MVIAC3_2 is not set # CONFIG_M586NOCX8 is not set Más allá de la advertencia, con un poco de cuidado se puede editar el archivo en caso de ser necesario. Módulo II: Kernel 8 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Podemos observar que es un sistema basado en x86 y que habilita la compilación de características experimentales. Respecto a los módulos, están habilitados, así como el soporte para “versioning” y el cargador de módulos automático del kernel, kmod, ambas características que veremos más adelante. En la sección de tipo de procesador, vemos que es de la familia K7 (Athlon, Duron) y vemos muchas opciones comentadas (con un # al comienzo), que están a modo de ayuda. El archivo .config no necesita de ellas para cumplir su función. Este archivo es útil para hacer respaldos de un kernel configurado. Para reproducirlo, basta con tener el código fuente y este archivo. Cabe remarcar que para obtener la configuración actual de un kernel ejecutándose, si éste soporta /proc/config.gz, ni siquiera hace falta tener el código fuente, basta con ejecutar zcat /proc/config.gz > .config. Si el kernel no soporta /proc/config.gz, puede aún contener el archivo .config dentro de sí mismo. Para extraerlo, se puede emplear una utilidad que viene con el código fuente de Linux, ubicado en scripts/extract-ikconfig. 2.6 COMPILACIÓN E INSTALACIÓN El paso siguiente sería make dep, que genera dependencias necesarias para el resto de la compilación. Sin embargo, en los kernels más recientes (2.6.x) este paso ya no es necesario. Luego, make clean bzImage modules modules_install. Esta única linea realiza el resto, que es limpiar archivos objeto que quedaron de la compilación anterior, hacer la imagen comprimida del kernel (bzImage), compilar los módulos (modules) e instalarlos (modules_install). Cada uno de estos pasos puede ser realizado por separado según la situación y el gusto. Si se desea crear una imagen del kernel para un disquete, se puede emplear make bzimage, y si el disco está en la unidad, con make bzdisk no sólo se hará la imagen sino que será grabada en el disco automáticamente. Esto último es una buena idea, sobre todo al compilar kernels de prueba, porque si el sistema no arranca como se espera, simplemente hay que sacar el disquete y reiniciar para que todo quede como antes. Adicionalmente, estos discos de arranque pueden ser utilizados cuando no sea posible arrancar desde el disco duro por alguna falla (no en reemplazo de los discos de rescate, pues éstos tienen Módulo II: Kernel 9 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux mucha más funcionalidad, pero podrían ayudar en casos simples) o para replicar sistemas Linux con sólo copiar los discos rígidos. 2.7 EL ARCHIVO SYSTEM .MAP Este archivo es una tabla que sirve para relacionar las direcciones de los símbolos (variables y funciones) utilizadas por el kernel, con sus nombres. Un fragmento de un archivo System.map es el siguiente: 00476f82 0052a73f 0060e766 00801678 008750fe 00ce9819 00ed1eba 01075bf0 01139ffc 01498f36 014f912d 0184a565 01a4e45c 01b5241f A A A A A A A A A A A A A A __crc_put_filp __crc_ide_add_proc_entries __crc_tty_termios_baud_rate __crc_flush_scheduled_work __crc___scm_destroy __crc_make_8023_client __crc_prepare_binprm __crc_panic __crc_max_mapnr __crc_posix_unblock_lock __crc_pci_release_regions __crc_xfrm_alloc_spi __crc_sb_min_blocksize __crc_ide_auto_reduce_xfer Podemos observar que la variable crc_tty_termios_baud_rate está en la dirección 0060e766 del kernel. El kernel no utiliza nombres de símbolos internamente, y los seres humanos no utilizamos las direcciones preferentemente. Al compilar, estos nombres son traducidos en las direcciones que el kernel usa. Sin embargo, a veces es necesario encontrar el nombre para una dirección o viceversa. Entonces se usa el archivo System.map, que se genera precisamente en la compilación y que refleja la traducción mencionada. La merecida extensión .map hace referencia a que es un mapa de los símbolos del kernel. Por lo tanto, cada vez que un kernel se compila, se genera un nuevo mapa que refleja los símbolos y las direcciones. Toda vez que es necesario consultar el mapa, es buscado en la ubicación /boot/System.mapversión. Por ejemplo, veamos un listado del directorio /boot en un sistema con varios kernels compilados: srvlinux:/boot # dir total 8952 drwxr-xr-x 3 root drwxr-xr-x 24 root Módulo II: Kernel root root 4096 Dec 4096 Dec 1 13:27 . 2 08:40 .. 10 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux -rw-r--r-lrwxrwxrwx IMQ -rw-r--r--rw-r--r--rw-r--r--rw-r--r-lrwxrwxrwx -rw-r--r--rw-r--r--rw-r--r-drwxr-xr-x lrwxrwxrwx -rw-r--r--rw-r--r--rw-r--r-lrwxrwxrwx athlon -rw-r--r-- 1 root 1 root root root 134460 Nov 17 17:54 Kerntypes-2.4.21-260-athlon 24 Jul 3 15:36 System.map -> System.map-2.4.21-99- 1 root 1 root 1 root 1 root 1 root 1 root 1 root 1 root 2 root 1 root 1 root 1 root 1 root 1 root root 631451 Nov 17 17:58 System.map-2.4.21-260-athlon root 650151 Jul 3 15:35 System.map-2.4.21-99-IMQ root 922226 Nov 27 20:46 System.map-2.6.9-Ernesto-18112004 root 512 Jan 13 2003 backup_mbr root 1 Jan 13 2003 boot -> . root 1257372 Jul 3 15:35 bzImage-2.4.21-99-IMQ root 1654917 Nov 27 20:46 bzImage-2.6.9-Ernesto-18112004 root 52392 Nov 17 17:53 config-2.4.21-260-athlon root 4096 Dec 1 13:40 grub root 24 Dec 1 13:26 initrd -> initrd-2.4.21-260-athlon root 977554 Dec 1 13:26 initrd-2.4.21-260-athlon root 80324 Sep 23 2003 memtest.bin root 64824 Sep 23 2003 message root 25 Dec 1 13:26 vmlinuz -> vmlinuz-2.4.21-260- 1 root root 1214206 Nov 17 17:58 vmlinuz-2.4.21-260-athlon Se puede observar que hay tantos System.map-versión como kernels (los kernels son los bzImage y también el vmlinux). Es importante destacar el vínculo dinámico de System.map -> System.map-2.4.21-99-IMQ, y el caso de que actualmente el sistema está utilizando el kernel vmlinuz-2.4.21-260-athlon. Lo que sucede en este caso es que los procesos que necesitan System.map buscan primero /boot/System.map, y detectan que la versión no corresponde, por lo que a continuación buscan /boot/System.map-versión, y la encuentran. Esta inteligencia hace posible un entorno multiboot con diferentes kernels. Algunos procesos también buscan /System.map y finalmente en el código fuente, /usr/src/linux/System.map. Pero es mejor y más ordenado no confiarse de esto, por lo que el paso siguiente, luego de haber compilado, será copiar el archivo System.map en /boot/System.map-versión. Hay que tener en cuenta que este mapa es estático, y por lo tanto sirve sólo para el código estático del kernel. Los símbolos de los módulos, por su naturaleza dinámica, no pueden ser incluidos en System.map y por lo tanto no tienen relación alguna con este archivo. Finalmente, sobre la importancia de este mapa se puede decir que pocos procesos lo utilizan, principalmente klogd, que es el demonio de registro del kernel, toda vez que se produce un error, para incluir el nombre del símbolo en ese registro. Process Status (ps) también lo utiliza. No contar con un System.map adecuado (que es lo mismo que no tenerlo) no presenta un error fatal, sino más que nada una molestia (mensajes como “System.map does not match actual kernel”), y la imposibilidad de depurar el kernel. Dosemu puede no funcionar correctamente también en estos casos. Módulo II: Kernel 11 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux 2.8 EL KERNEL Y SUS PARÁM ETROS Ahora vamos a encontrar la versión comprimida del kernel en /usr/src/arch /i386/boot/bzImage (descontando que la arquitectura del sistema es x86). Veamos un poco de nomenclatura, y de historia. Tradicionalmente, el nombre del archivo que contiene el kernel se llama vmlinux; vm significa Virtual Memory (memoria virtual), y es representativo de que este kernel está hecho para manejarla. Poco después, se desarrolló un método para comprimir la mayor parte de la imagen del kernel y descomprimirla durante el arranque, de modo que vmlinux pasó a ser vmlinuz, la z por gzip, que es el formato en el cual (aún hoy) se comprime el kernel. Antes de bzImage, estaba zImage, hecha para cargarse en la memoria baja de la PC (low memory), y con la consiguiente restricción en tamaño, que resulta ser inferior a 580kB. Aun hoy puede hacerse esta imagen, con make zImage. El nombre del archivo con el kernel que generamos, bzImage, responde a Big zImage, y está diseñado para cargarse en la memoria alta, permitiendo tamaños mucho mayores. No está relacionado con el formato de compresión bzip, como el nombre parece sugerir. A fin de cuentas, el nombre que tenga el kernel no es importante mientras esté correctamente reflejado en el cargador de arranque (en caso de usar uno). Para seguir la tradición se puede copiar el archivo usando cp bzImage /boot/vmlinuz-versión. Ahora debemos preocuparnos por el comportamiento del kernel durante el arranque. Por defecto, el kernel compilado buscará el sistema de archivos raíz (root filesystem) donde se encuentra el actual, por ejemplo, /dev/hdb1. Por lo tanto, si estamos compilando un kernel para el sistema actual, no habrá problema alguno. Sin embargo, en caso de estar compilando para otro sistema donde el sistema de archivos raíz tenga otra ubicación, tenemos 2 opciones para evitar el error (kernel panic) que se producirá como consecuencia de la búsqueda del root donde no está: la primera es usar el comando rdev para establecer en el mismo kernel el valor correcto para este parámetro, por ejemplo, rdev /boot/bzImage-2.6.9 /dev/hda7. Para mayor información, consultar la página del manual de rdev (man rdev). Si estamos preparando un disquete booteable que contiene el kernel, esta es la solución a emplear. Si se cuenta con un cargador de arranque como GrUB o LILO, se presenta la segunda opción, que es especificar la ubicación del sistema de archivos raíz en la definición del kernel. Por ejemplo, en GrUB, esto quedaría así: title Linux kernel (hd0,0)/boot/vmlinuz root=/dev/hda1 vga=0x317 splash=silent desktop showopts Módulo II: Kernel 12 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Acá tenemos la oportunidad de observar otros parámetros del kernel, por ejemplo, vga=0x317 establece el modo de presentación del monitor. Con vga=ask se presenta una lista de los modos disponibles. Más información sobre los modos de video se encuentra en /usr/src/linuxversión/Documentation/svga.txt. muestra la imagen que enmarca a GrUB y la primera consola sin mostrar los mensajes previos a la presentación de la imagen. desktop es un agregado de SuSE que ajusta el comportamiento del kernel al indicar que la máquina es de escritorio (en lugar de un servidor). showopts hace que GrUB muestre las opciones de booteo, pero estos tres últimos no son parámetros del kernel propiamente dichos, sino más bien, parámetros del proceso de arranque. splash=silent La lista completa de parámetros del kernel se puede encontrar en el código fuente, en /usr/src/Linux-versión/Documentation/kernel-parameters.txt. Sin embargo, vamos a destacar algunos de los más útiles. La consola en general es la primera terminal virtual, esto es, los mensajes de arranque se muestran en el monitor a través de la placa VGA. A veces puede ser útil tener otro dispositivo para la presentación de estos mensajes, y para la interacción con el sistema. Por ejemplo, un puerto serie, o incluso una impresora. Para ello viene el parámetro console, que permite especificar este dispositivo, por ejemplo, console=/dev/ttyS1,9600, para elegir el segundo puerto serie a 9600 bps. Pueden incluso especificarse varias consolas simultáneas para visualizar los mensajes del kernel, hasta una por cada tipo (una serie, una paralelo, una VGA) Es bueno tener en cuenta que para que todo esto sea posible, los controladores del puerto serie deben estar compilados en el kernel. Otra de las opciones importantes es el runlevel, que se puede especificar como un número. Por ejemplo, si escribimos un 1, el sistema iniciará en modo monousuario. Lo mismo sucede con S o single. Esto es especialmente útil cuando el proceso de arranque se detiene en alguna de las etapas de init. Veremos un tercer parámetro, con lo que se consigue algo similar al anterior. Por defecto, el kernel ejecuta el comando /sbin/init una vez que terminó de cargarse. El parámetro init permite establecer un comando diferente. Por ejemplo, configurando init=/bin/sh, al terminar de cargarse el kernel quedaríamos en el shell, desde donde se pueden realizar tareas de reparación. 2.9 AJUSTE DE GRUB PARA EL ARRANQUE CON EL NUEVO KERNEL Conociendo todo esto, configurar un gestor de arranque para que utilice el nuevo kernel será sencillo. Basta con modificar una entrada existente o crear una nueva para el nuevo kernel, y establecer a gusto los parámetros adecuados. Módulo II: Kernel 13 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Una de las funciones más interesantes de GrUB para el control de máquinas de difícil acceso o simplemente sin monitor ni teclado es la posibilidad de especificar (similarmente a lo que sucede con el kernel) una consola serie. Para lograr esto, los pasos son sencillos. Primero, hay que asegurarse de no haber establecido la opción --disable-serial cuando se compilaron las imágenes de GrUB. Luego, en el archivo de configuración (típicamente /boot/grub/menu.lst), incluir las líneas: serial --unit=1 --speed=9600 terminal --timeout=10 serial console Siendo consistentes con el ejemplo dado para “console” del kernel, esto configura el COM2 a 9600 bps. La instrucción terminal indica que puede ser tanto serie como la tradicional, en la que primero se presione una tecla. Un archivo típico de configuración de GrUB en un sistema SuSE sería: # Modified by YaST2. Last modification on Mon Jan 13 09:29:18 2003 color white/blue black/light-gray default 0 timeout 8 gfxmenu (hd0,0)/boot/message ###Don't change this comment - YaST2 identifier: Original name: linux### title Linux kernel (hd0,0)/boot/vmlinuz root=/dev/hda1 vga=0x317 splash=silent desktop showopts initrd (hd0,0)/boot/initrd ###Don't change this comment - YaST2 identifier: Original name: floppy### title Disquete root (fd0) chainloader +1 ###Don't change this comment - YaST2 identifier: Original name: failsafe### title Failsafe kernel (hd0,0)/boot/vmlinuz root=/dev/hda1 showopts ide=nodma apm=off acpi=off vga=normal nosmp noapic maxcpus=0 3 initrd (hd0,0)/boot/initrd ###Don't change this comment memtest86### title Prueba de memoria kernel (hd0,0)/boot/memtest.bin Módulo II: Kernel YaST2 identifier: Original name: 14 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Acá se pueden observar varios comandos, como color que asigna colores al menú, default que establece cuál de todas las opciones de arranque debe estar predeterminada, timeout para saber cuánto esperar antes de arrancar con la opción predeterminada y gfxmenu que indica dónde está la imagen de fondo (splash). Estos son comandos generales e independientes de la opción de arranque. Ya en las opciones de arranque se presentan los comandos kernel, que determina la ubicación del mismo y le pasa parámetros, e initrd, que indica a GrUB la posición del initial RAMdisk, puesto que como vimos anteriormente, le corresponde a GrUB el manejo de este “disco RAM”. Una mención aparte merece la opción Disquete, donde el método de arranque es diferente, y es el mismo utilizado para Windows en todas sus versiones. root especifica el sistema de archivos raíz, y luego chainloader +1 carga el sector de arranque de ese disco o partición. El comando chainloader (fd0)+1 sintetizaría los dos mencionados. Por ejemplo, podríamos arrancar un SO Windows 98 residente en la segunda partición del primer disco IDE de la siguiente manera: root (hd0,1) makeactive chainloader +1 El comando makeactive hace activa la partición raíz, dejándola lista para arrancar. GrUB tiene una línea de comandos, donde se pueden usar las instrucciones de manera interactiva, y se puede acceder a él en un sistema SuSE apretando ESC en la pantalla del cargador de arranque. Es recomendable leer el manual de GrUB, que se puede encontrar en el sitio de GNU: http://www.gnu.org/software/grub/manual/grub.html. 2.10 CÓMO SE CARGAN LOS MÓDULOS EN EL KERNEL Cuando un kernel que tiene posibilidad de cargar automáticamente los módulos necesita una característica que no posee en memoria, el demonio de los módulos del kernel kmod ejecuta modprobe con un parámetro que puede ser o bien directamente el nombre del módulo, como sería ip_tables, o bien un nombre más genérico, como eth0. En esta circunstancia, modprobe buscará en /etc/modprobe.conf esta cadena, y se encontraría con la línea: alias eth0 via-rhine que le indicará que el nombre del módulo a cargar es via-rhine. Acto seguido, modprobe busca en /lib/modules/version/modules.dep, por ejemplo, /lib/modules/2.4.21-260-athlon/modules.dep, y revisa cuales son las dependencias de Módulo II: Kernel 15 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux via-rhine, esto es, si via-rhine necesita que otros módulos sean cargados antes que él mismo. En este caso, la línea: /lib/modules/2.4.21-260-athlon/kernel/drivers/net/via-rhine.o: /lib/modules/2.4.21-260-athlon/kernel/drivers/net/mii.o nos indica que hace falta cargar mii antes. El archivo modules.dep es generado por depmod –a, que en general, no hace falta ejecutar porque de ello se encarga make modules-install. En el paso final, modprobe llama a insmod, que es el proceso que de hecho carga los módulos (pero no comprueba dependencias), de esta manera: insmod /lib/modules/2.4.21-260-athlon/kernel/drivers/net/mii.o insmod /lib/modules/2.4.21-260-athlon/kernel/drivers/net/via-rhine.o Si el kernel no soporta la carga automática, habrá que cargar el módulo correspondiente manualmente antes de poder utilizar el hardware, en este ejemplo, una placa de red. Cabe destacar que si ejecutamos el último comando insmod sin haber ejecutado el anterior, con seguridad se producirá un error de “unknown symbol”, que indica que hay funciones o variables (símbolos) que se necesitan para cargar via-rhine que no están en memoria. Los comandos para el manejo de módulos son los 2 que vimos anteriormente, modprobe e insmod más lsmod (que presenta en pantalla todos los módulos en memoria) y rmmod (que elimina un módulo de memoria, pero necesita soporte del kernel, o sea, una opción llamada “kernel module unloading” debe estar activada). Los módulos del kernel se encuentran en /lib/modules, y están separados por versiones. Esto sirve al propósito de que al instalar los módulos de un kernel de una versión diferente no se borren los de las versiones anteriores. Pero fundamentalmente, ayuda a modprobe a encontrar los módulos de la versión del kernel que se está ejecutando, debido a que en general, los módulos compilados para una versión del kernel no sirven para otra. Recientemente, una característica llamada “module versioning support” permite cargar módulos de versiones distintas al kernel en ejecución. Sin embargo, esta función no está completamente desarrollada aun, por lo que es considerada como experimental. 2.11 CONSIDERACIONES Y CONSEJOS ÚTILES. Con respecto a la compilación del kernel, es interesante en primer lugar leer el resultado del comando make help, para dominar las opciones, que se encuentra en los kernels de LKA. Módulo II: Kernel 16 Facultad de Cs. Exactas y Tecnología Depto. de Electricidad, Electrónica y Computación Ing. en Computación Curso: Administración Avanzada de Linux Si se desean agregar módulos, no hace falta recompilar el kernel, sino sólo los módulos nuevos. Esta es una de las mejores ventajas de los módulos, y fue mencionada con anterioridad. El comando make modules modules_install bastará para tener los nuevos módulos compilados e instalados. El comando make clean elimina los archivos generados por la compilación, pero conserva la configuración. Al compilar un kernel para la misma máquina, a veces es posible hacerlo sin la limpieza, lo que acelera el proceso puesto que muchos archivos objeto ya están hechos. Sin embargo, esta práctica puede causar problemas, por lo tanto, ante la primera dificultad por hacer andar el nuevo kernel, se recomienda limpiar y recompilar. Los comandos make mrproper o make distclean limpian el código fuente de todos los archivos producto de la configuración y compilación. Por ende, también borran .config. Sin embargo, los parches aplicados permanecen, puesto que ya son parte del código fuente mismo. Módulo II: Kernel 17