El kernel Linux 2.6

Qué es el kernel

El kernel es el encargado de interactuar con el hardware de nuestro equipo. Se encarga de que el hardware se ponga a trabajar: maneja todos los componentes, gestiona el tiempo de CPU para cada programa, administra la memoria, etc. Está en continuo desarrollo y se actualiza con bastante frecuencia. Para saber la versión de nuestro kernel ejecutaremos el comando:

$ uname -r
2.6.8-2-386
  • 2: versión. Una nueva versión implica grandes cambios en el kernel.
  • 6: actualización. Si es par, versión estable. Si es impar, versión de desarrollo.
  • 8: revisión.
  • 2: revisión Debian.
  • 386: arquitectura.

Qué son los módulos

Desde la versión 2.0 el núcleo consta de dos partes:

  1. el núcleo en sí: parte monolítica del núcleo, está activa en todo momento.
  2. los módulos: son extensiones del kernel y no están cargados en memoria todo el tiempo, únicamente se cargan cuando se hace una llamada a ese hardware.

El software que controla un dispositivo se denomina controlador, aunque en Windows se le llama driver y en Linux módulo. Para que el kernel pueda manejar un dispositivo debe tener cargado el módulo correspondiente y esto se puede hacer de dos maneras:

  1. incluir el módulo como parte del kernel: al compilar el kernel, incluiremos ese módulo en la parte monolítica del kernel ("built-in").
  2. cargar el módulo bajo demanda: al compilar el kernel, incluiremos ese módulo como "loadable module".
    • Para cargar/descargar el módulo usaremos los comandos insmod, rmmod y modprobe.
    • Para que el kernel cargue el módulo durante el arranque lo añadiremos al archivo /etc/modules, cuyo contenido es similar a:
      # /etc/modules: kernel modules to load at boot time.
      ide-cd
      ide-disk
      psmouse
    • Si cargamos/descargamos un módulo con el comando modconf (paquete modconf), frontal con interfaz de menús para insmod, rmmod y modprobe, automáticamente se añadirá/borrará el módulo al archivo /etc/modules y los parámetros en /etc/modprobe.d/<módulo>.
      # modconf

      modconf

Para ver los módulos cargados ejecutaremos:

$ lsmod
Module                  Size  Used by
parport                37320  2 lp,parport_pc
usbcore               104164  3 uhci_hcd,ohci_hcd,ehci_hcd
snd                    50660  4 snd_pcm,snd_timer
soundcore               9824  1 snd
...

Compilar el kernel Linux 2.6

Desde siempre, compilar el kernel es un rito de iniciación para todo linuxero que se precie. Además, un kernel actualizado nos permitirá disponer de nuevos drivers y características y eliminar bugs y agujeros de seguridad.

Debian tiene bien resuelto el tema del kernel: dispone de paquetes .deb que contienen un kernel ya compilado (paquete linux-image…), instalables con APT como un paquete normal, así como herramientas que permiten compilar el kernel "a lo Debian" y construir un paquete .deb para instalarlo posteriormente con APT. A pesar de ello, la mejor manera de actualizar el kernel sigue siendo compilarlo manualmente: es el método más fiable, el más divertido y te permite impresionar a tus amigos. ¡Todo ventajas!

Vamos a compilar un kernel Linux 2.6.20. El proceso tiene cinco etapas:

  1. Conseguir el código fuente del kernel

    Para conseguir las fuentes las bajaremos desde el sitio oficial del núcleo kernel.org. Descargaremos el archivo linux-2.6.20.1.tar.bz2 en el directorio /usr/src. Una vez descargado lo desempaquetamos:

    # cd /usr/src
    # tar -xvjf linux-2.6.20.1.tar.bz2

    El fichero se desempaquetará en el directorio /usr/src/linux-2.6.20.1, que contiene varios subdirectorios con todo el código necesario, incluyendo abundante información en /usr/scr/linux-2.6.20.1/Documentation.

  2. Parchear el kernel

    Si necesitamos un kernel con alguna funcionalidad especial (por ejemplo para activar Xen o LVS), tendremos que parchearlo. Los parches para el kernel deben aplicarse a kernels vanilla, los kernel de kernel.org sin modificar y no a los kernels binarios que proporcionan las distribuciones, que en muchos casos ya incorporan otros parches. Para ello, descargamos de la web del proyecto el parche correspondiente a nuestro kernel (por ejemplo patch-2.6.20.gz) y lo descomprimimos en el directorio de las fuentes del kernel (/usr/src/linux-2.6.20.1):

    # cd /usr/src/linux-2.6.20.1
    # gunzip patch-2.6.20.gz

    Y aplicamos el parche:

    # cat patch-2.6.20 | patch -Np1

    Con esto ya tenemos las fuentes listas para configurar.

  3. Configurar

    Aquí seleccionaremos las opciones del nuevo núcleo, así como qué se cargará como módulo y qué en la parte monolítica. Podemos plantearlo de dos maneras:

    1. optimizar el kernel para el hardware concreto de nuestro equipo, de manera que tengamos un kernel pequeño y rápido.
    2. hacer un kernel para poder instalarlo en cualquier equipo, con todos los módulos, más grande y lento.
    • Entramos en el directorio /usr/src/linux-2.6.20.1
      # cd /usr/src/linux-2.6.20.1

      y limpiamos las compilaciones anteriores (se borrará .config si existe, veremos las opciones con make –help):

      # make clean
      # make mrproper
    • Para configurar el kernel emplearemos menuconfig, una herramienta en modo texto con menús (requiere las librerías de desarrollo de Ncurses, paquete libncurses5-dev):
      # make menuconfig

      menuconfig

    • Si existe .config (inicialmente no existe), menuconfig lo cargará. Si vamos a recompilar el kernel que ya tenemos instalado, podemos tomar como punto de partida el archivo de configuración del kernel activo (/boot/config-2.6.8-2-386). Para ello, lo copiaremos en /usr/src/linux-2.6.20.1 como .config.old:
      # cp /boot/config-2.6.8-2-386 .config.old

      y lo cargaremos desde la opción Load an Alternate Configuration File.

      Sin embargo, esta opción no es recomendable si vamos a cambiar de versión, porque probablemente hayan cambiado las opciones de configuración: es mejor partir de cero.

    • Exploraremos todos los menús, teniendo tres opciones para cada módulo:
      • [*]: incluir en la parte monolítica.
      • <M>: incluir como módulo.
      • [ ]: no incluir.

      Debemos tener en cuenta que cada opción que seleccionemos para ser incluida en la parte monolítica hará el núcleo un poco más grande, exigiendo más memoria. Dispondremos de Ayuda en cada opción y recomendaciones del tipo: Si no está seguro, marque Sí.

    • Una vez terminada la configuración la guardaremos en el archivo .config para ser usada por el compilador. Podemos guardar la configuración en un archivo distinto con la opción Save configuration to an alternate file.
  4. Compilar
    • Crearemos el enlace /usr/src/linux apuntando al directorio de las fuentes (si existe lo borramos), ya que durante la compilación algunos programas buscan este directorio:
      # rm /usr/src/linux
      # ln -s /usr/src/linux-2.6.20.1 /usr/src/linux
    • Para evitar conflictos si hacemos varias compilaciones del kernel, editaremos /usr/src/linux-2.6.20.1/Makefile y sustituiremos la línea:
      EXTRAVERSION = .1

      por algo similar a:

      EXTRAVERSION = .1-r1

      De esta manera, la versión del kernel generado será 2.6.20.1-r1, es lo que obtendremos al ejecutar uname -r y también será el directorio usado por make modules_install

    • Para compilar ejecutaremos:
      # make

      Esto generará:

      1. /usr/src/linux-2.6.20.1/arch/i386/boot/bzImage: un kernel comprimido.
      2. /usr/src/linux-2.6.20.1/System.map: el archivo de símbolos.
      3. /usr/src/linux-2.6.20.1/…: numerosos archivos .o y .ko (módulos) y subdirectorios.
  5. Instalar
    • Instalar el nuevo kernel vmlinuz (el antiguo es /boot/vmlinuz-2.6.8-2-386):
      # cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.20.1-r1

      Instalar el nuevo archivo de símbolos System.map (el antiguo es /boot/System.map-2.6.8-2-386):

      # cp System.map /boot/System.map-2.6.20.1-r1

      Instalar el archivo de configuración del kernel (el antiguo es /boot/config-2.6.8-2-386):

      # cp .config /boot/config-2.6.20.1-r1

      No eliminaremos los archivos existentes, para poder seguir entrando en el sistema en caso de errores graves.

    • Instalar los nuevos módulos: se instalarán en /lib/modules/2.6.20.1-r1 (los antiguos están en /lib/modules/2.6.8-2-386):
      # make modules_install

      No eliminaremos los módulos anteriores.

    • Crear la imagen de arranque initrd.img para el nuevo kernel (la antigua es /boot/initrd.img-2.6.8-2-386) con el comando mkinitramfs (paquete initramfs-tools):
      # mkinitramfs -o /boot/initrd.img-2.6.20.1-r1 /lib/modules/2.6.20.1-r1
    • Actualizar el enlace simbólico /vmlinuz (el antiguo apunta a /boot/vmlinuz-2.6.8-2-386):
      # rm /vmlinuz
      # ln -s /boot/vmlinuz-2.6.20.1-r1 /vmlinuz
    • Actualizar el enlace simbólico /initrd.img (el antiguo apunta a /boot/initrd.img-2.6.8-2-386):
      # rm /initrd.img
      # ln -s /boot/initrd.img-2.6.20.1-r1 /initrd.img
    • Crear el enlace /boot/System.map (inicialmente no existe):
      # ln -s /boot/System.map-2.6.20.1-r1 /boot/System.map
    • Configurar el gestor de arranque (GRUB) para poder arrancar con el nuevo kernel. Para ello editaremos /boot/grub/menu.lst y añadiremos la entrada para el nuevo kernel:

      title          Debian GNU/Linux, kernel 2.6.20.1-r1
      root           (hd0,1)
      kernel         /boot/vmlinuz-2.6.20.1-r1 root=/dev/hda2 ro
      initrd         /boot/initrd.img-2.6.20.1-r1
      savedefault
      boot

      No eliminaremos la entrada del kernel antiguo para poder entrar en el sistema en caso de problemas. Una vez comprobemos que el nuevo kernel arranca, lo pondremos el primero de la lista para que sea la opción por defecto.

    • En este punto el nuevo kernel está listo para ejecutarlo la próxima vez que iniciemos. Reiniciamos el ordenador y en el gestor de arranque (GRUB) seleccionamos el núcleo nuevo. En caso de error podremos arrancar con el antiguo kernel y realizar las modificaciones necesarias. Para comprobar si el kernel cargado es el nuevo ejecutamos:
      # uname -r
      2.6.20.1-r1

      Si el nuevo kernel arranca correctamente, crearemos los archivos de dependencias entre módulos, que se guardan en /lib/modules/2.6.20.1-r1/modules.dep:

      # depmod -a

      Esto creará varios archivos /lib/modules/2.6.20.1-r1/modules.*

    • Para terminar, repasaremos el sistema para comprobar que todo funciona: disquetera, CD, red, disco duro, etc.

El directorio /proc

El kernel durante su arranque pone en funcionamiento un pseudo-filesystem llamado /proc, donde vuelca la información que recopila de la máquina, así como muchos de sus datos internos. Está implementado sobre memoria y no se guarda en disco, conteniendo tanto datos estáticos como dinámicos.

El directorio /proc contiene gran cantidad de información de bajo nivel sobre el funcionamiento del sistema y muchos comandos se apoyan en él para sus tareas. Por ejemplo, en /proc podremos encontrar las imágenes de los procesos en ejecución, junto con la información que el kernel maneja acerca de ellos. Cada proceso del sistema se puede encontrar en el directorio /proc/<pid_proceso>, donde hay ficheros que representan su estado. Esta es la información que usan comandos como pstree, ps o top.

El archivo /etc/fstab indica cómo debe montarse el filesystem virtual /proc:

# File_system  Mount_point     Type    Options       Dump  Pass
proc           /proc           proc    defaults      0     0

Otros ficheros de /proc son:

Otros ficheros de /proc
Directorio Descripción
/proc/bus Información de los buses PCI y USB.
/proc/cmdline Línea de arranque del kernel.
/proc/cpuinfo Información de la CPU.
/proc/devices Dispositivos del sistema de caracteres o bloques.
/proc/drive Información de algunos módulos de hardware.
/proc/filesystems Sistemas de ficheros habilitados en el kernel.
/proc/ide Información del bus IDE.
/proc/interrups Mapa de interrupciones de hardware (IRQ) utilizadas.
/proc/ioports Puertos de E/S utilizados.
/proc/meminfo Datos del uso de la memoria.
/proc/modules Módulos del kernel.
/proc/net Información de red.
/proc/pci Dispositivos PCI del sistema.
/proc/scsi Directorio de dispositivos SCSI, o IDE emulados por SCSI.
/proc/version Versión y fecha del kernel.

Artículos en la categoría "Lo más básico en Linux"

  1. Lo más básico en la terminal de Linux
  2. Cómo apagar el ordenador en Linux
  3. Cómo conseguir ayuda en una máquina Linux
  4. Abrir un shell en el entorno gráfico en Linux
  5. Hardware en Linux
  6. Copiar/Pegar en Linux
  7. Activar NumLock en Linux
  8. El menú Debian
  9. Iconos en el escritorio en Linux
  10. Salvapantallas en Linux
  11. Formatos libres y propietarios en Linux
  12. Proceso de arranque en Linux
  13. El kernel Linux 2.6
  14. Emergencias en Linux

4 Comments:

  1. Una preguntilla, que siempre he tenido dudas, hay un comando para ver los módulos que tenemos cargados. Pero ¿Cómo puedo saber los módulos compilados con el kernel?, cuando me dicen que una determinada funcion necesita algo en el kernel cómo saber si ya lo tengo o tengo que compilar uno nuevo.

  2. Javier, con ‘modconf’ podrás ver exactamente lo que buscas, los módulos que pueden ser cargados en el kernel y si están ya cargados o no.
    Otra opción es ‘make menuconfig’ y cargar el archivo de configuración del kernel activo, así podremos examinar con qué opciones se compiló nuestro kernel. El archivo a cargar es, por ejemplo:
    /boot/config-2.6.8-2-386

  3. hola crash, muy bueno tu howto, ahora que lo veo me ha ayudado a entender un poco mas un problema que tengo. El tema es que he instalado mi placa de video nvidia usando los controladores de envidia y todo funciona perfectamente. El problema se me presenta cuando reinicio la maquina y no puede arrancar las x. Pero no pienses que me equivoque de lugar, porque lo que he descubierto es que el modulo no se carga correctamente al inicio. Antes de reiniciar hago lsmod y me devuelve “nvidia 7463425 26″, pero cuando hago lsmod después de haber reiniciado me devuelve “nvidia 7463425 0″, parece que no lo está asignando. Para que lo cargue en el inicio lo agregué en /etc/modules y estoy usando un debian etch 4.0 amd64, espero que me puedas ayudar. Gracias.

  4. Muy útil y bien explicado, gracias.