KERNEL

Anuncio
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
Descargar