En este capítulo se explica, como se puede activar dispositivos que no están incluidos en la configuración básica de las distribuciones. También se indica la forma como optimizar y reinstalar el núcleo del sistema operativo mismo.
Una fundamental característica del núcleo de Linux es su modularidad. Mediante el mecanismo de módulos del núcleo se pueden conseguir dos efectos:
En la programación se utilizan bibliotecas de programas para resolver tareas comunes. P.ej. una de las más famosas biblioteca en la programación en C es asociada con el archivo de inclusión <stdio.h>. Es la biblioteca que contiene las rutinas para imprimir y leer caracteres desde archivos y dispositvos.
A la hora de escribir un programa, el o la programador/a ya no tienen que reinventar las rutinas de entrada y salida, sino utilizan las prefabricadas de la biblioteca.
Como casi todos los programas en el sistema incluyen esta biblioteca de rutinas, a la hora de cargarlos se desperdicia espacio de memoria, porque el código de programa de las rutinas de la biblioteca está incluido en cada programa. Para evitar esta desventaja se inventaron las bibliotecas dinámicas, u objetos compartidos. El primer nombre (DLL: dinamic linked library = biblioteca enlacada dinámicamente) proviene de los sistemas operativos Microsoft, mientras en Linux se utiliza la segunda expresión: Shared Objects = objetos compartidos, designados con la extensión de archivo “.so”. Las bibliotecas absolutas, o estáticas, que se requieren solamente para la compilación tienen la extensión “.a”.
En la compilación de programas estáticos se incluyen los archivo de las bibliotecas absolutas después de generar el código del programa mismo, y a continuación se resuelven los saltos a las rutinas de la biblioteca mediante un programa llamado el Linker = enlazador. El resultado es un archivo monolítico que contiene todo el código necesario para ejecutar su tarea.
En contraste se compilan programas modulares sin incluir el código de las bibliotecas. El Linker ahora tiene un rol diferente, y en efecto es un programa diferente, en Linux: “ld.so”, shared object linker. A la hora de cargar un programa con bibliotecas dinámicas ld.so entra en acción, analiza cuáles bibliotecas requiere el programa para funcionar, los carga en espacios libres en la memoria y en este momento modifica el código del programa de tal manera, que todos los enlazes resuelven correctamente. Si la biblioteca ya está cargado en la memoria, ld.so no vuelve a hacerlo, sino resuelve los saltos hacia las rutinas correspondientes hacia la biblioteca presente. Esto requiere, sin embargo, que las bibliotecas estén escritas de una forma que permite reutilizar las mismas rutinas por diferentes programas.
Ahora comparemos módulos estáticos con módulos dinámicos:
Ventajas de módulos dinámicos:
Desventajas de módulos dinámicos:
En el sistema Linux es necesario ejecutar la utilidad “ldconfig” como root, cuando se instalan nuevas bibliotecas. El archivo “/etc/ld.so.conf” contiene una lista de directorios que se utilizan para encontrar y registra bibliotecas dinámicas. Esta lista solamente es para directorios adicionales, ya que ld.so “sabe” las vías de acceso estándard.
El núcleo del sistema operativo es por un lado también un programa C, pero por otro lado es especial, en el sentido que se carga desde “la nada”, y no puede contar con muchas de las utilidades versátiles, que el sistema operativo pone a disposición. Sin embargo se integró al núcleo de Linux un sistema de resolución dinámica de “bibliotecas”, que en este caso se llaman módulos. Esto quiere decir, que ciertas rutinas del núcleo no se incluyen en el mismo archivo que el bootstraploader - el cargardor inicial lee del disco duro (o de donde sea), sino que residan en el disco duro en archivos aparte. A la hora que se requiere estas rutinas se tienen que copiar estos módulos del disco duro a la memoria principal, y resolver las direcciones dentro del núcleo a la ubicación que tengan en este momento. En la figura 16.1.2 se ilustra la diferencia entre un núcleo estático y un núcleo con módulos.
Diferencia entre núcleo estático y núcleo modular. |
Usar un núcleo con módulos implica, que primero tiene que funcionar el acceso al disco duro (o más preciso: al sistema de archivos) para que se pueden cargar módulos adicionales y por lo tanto que las rutinas esenciales para acceder al sistema de archivo no pueden ser compilados como módulos. Además el núcleo necesita “saber” cuáles módulos pueden potencialmente cargarse “en el”. A la hora de compilar el código fuente del núcleo de Linux se le indica, cuales rutinas son residentes (fijos) en el, cuáles se compilan como archivos de módulos y cuales no se compilan. Para los que son módulos se reservan los saltos para cargarlos en el núcleo, por lo que se agrandece mínimamente el volumen del núcleo.
Ventajas de módulos de núcleo:
Los mismos módulos pueden ser “modulares” por ellos mismos, quiere decir, si varios módulos utilizan las mismas rutinas, estos pueden separarse en un módulo aparte, y se dice que entonces estos módulos dependen del último. Tiene que cargarse primero el módulo con las rutinas compartidas, para poder cargar los otros.
El núcleo puede ser configurado también para cargar automáticamente los módulos que necesita. Esta funcionalidad se llama kernel-daemon o kerneld.
Hay varias utilidades para cargar, descargar y administrar los módulos :
Y existe todo un sistema de gestión de módulos, llamado modutils, que facilita poner en orden las dependencias de los módulos. En un sistema instalado, estas utilidades por lo general no se necesitan invocar manualmente, porque están integrados en el arrance y la administración automático.
En el archivo /etc/modules.conf pueden especificarse además varios parámetros que se aplican a la hora de cargar un módulo. Si se trata de módulos que acceden directamente a un dispositivo de hardware, muchas veces se requiere especificar el puerto de Entrada/Salida o la interrupción que utiliza el dispositivo. Especialmente si pueden haber varios dispositivos del mismo tipo en una computadora, se puede especificar el orden en el cual se les asigna su numeración. Otro comando utilizado con frecuencia en este archivo es “alias” que permite darle un “nombre” sinónimo a un módulo. Así se puede por ejemplo llamar al módulo del hardware de sonido siempre “sounddriver”, independientemente si es un soundblaster, o si es un chipset cmpci.
El comando “insmod” requiere, que se especifíca las opciones en la línea de comandos, mientras modprobe los lee desde el archivo modules.conf. Con el tiempo la cantidad de módulos ha crecido a un gran número, así que el sistema Debian Gnu/Linux utiliza un mecanismo de diversificación de estos archivos. En el directorio /etc/modutils se pueden crear archivos o editar los existentes, en los cuales se especifican opiones o comandos correspondientes a modules.conf. Con el comando “update-modules” todos estos archivos son integrados en el archivo modules.conf automáticamente, el cuál no debe ser editado a mano.
En el sistema Debian Gnu/Linux se utiliza el archivo /etc/modules para indicar, cuales módulos deben cargarse automáticamente al iniciar el sistema. Se escribe una línea por cada módulo, solamente con el nombre del módulo que se quiere cargar.
Ya que un sistema puede trabajar con diferentes versiones de núcleos existe un esquema que permite a los modutils identificar cual módulo cargar. Los módulos están ubicados en el directorio /lib/modules, en un subdirectorio con el nombre de la versión del núcleo, para el cual fueron compilados. Si tenemos un núcleo de la versión 2.2.17 (Debian 2.2) y uno de la versión 2.4.0 entonces encontramos dos directorios: /lib/modules/2.2.17 y /lib/modules/2.4.02.
Bajo estos directorios hay una jerarquía de subdirectorios, para dividir los archivos de módulos según su función o tarea. Para detectar cual versión de núcleo estamos usando puede ejecutarse la línea de comando: uname -a, o uname -r
Pueden haber varias razones por qué recompilar el núcleo del sistema operativo, que parten todos del hecho que el núcleo “universal” o genérico que se instala en el proceso de la instalación del sistema no es adecuado para la tarea que se quiere realizar con la computadora. Pueden haber uno varios de los siguientes escenarios:
El procedimiento a realizar ha llegado a ser bastante estándardizado y no requiere conocimientos de programación. El primer paso es la instalación del código fuente del núcleo, por lo general (y recomendablemente) en un subdirectorio de “/usr/src”. En el sistema Debian el núcleo se instala en un subdirectorio llamado “kernel-source-<version>”, en RedHat se utiliza “linux-<versión>” y se crea un enlace simbólico “linux” al subdirectorio del núcleo actualmentente utilizado.
Para trabajar con el núcleo hay que entrar en este directorio, que se llama también el directori raíz de la fuente del núcleo. El siguiente paso es la configuración de todos los parametros y la definición de los gestores estáticos y/o módulos de núcleo que se quiere incluir. Para esto hay tres utilidades:
La primera versión no es recomendable, ya que procesa todas las preguntas de configuración de forma secuencial y no permite regresar a decisiones anteriores. La segunda y la tercera versión permiten seleccionar las categorias interactivamente y repetir los pasos de configuración cuantas veces sea necesario. Además permiten una cierta administración de configuraciones, ya que permiten cargar y salvar archivos de configuración nombrados. Es perfectamente posible y a veces inclusive recomendable compilar en una computadora núcleos para otras computadoras. El código fuente actualmente alcanza los 80 Megabyte de espacio y se requier alrededor de un cuarto a una media hora con una computadora veloz con bastante memoria para compilarlo. Así que es preferible compilar núcleos para computadoras lentas en otras computadoras y después copiarlos a la máquina destino. Para esto se maneja p. ej. archivos de configuración con los nombres de las computadoras en la computadora donde se compilan los núcleos, para más rápido acceso a las configuraciones diferentes.
Al finalizar la configuración se graba un archivo “.config” que contiene todos los parametros de compilación necesarios. Ahora se procede a compilar el núcleo, esencialmente con los comandos:
Se utiliza preferiblemente una sola línea de comando, ya que cada uno de los procesos es tardado y de esta manera no se tiene que estar presente para dar los comandos individuales a concluir cada paso. Sin embargo, si la ejecución de un paso se interrumpe por un error, un hecho que pocas veces ocurre, se tiene que reinicializar solamente a partir del comando fallado.
La compilación del núcleo es una prueba dura para el procesador y para la memoria principal de la computadora. Es casí imposible que una memoria con fallas no se descubra a la hora de (re)compilar el núcleo. El símptoma presentado en este caso es muchas veces un mensaje raro con “broken pipe” o “compiler error”, o puede ocurrir en la fase de generación del código de máquina, que normalmente nunca falla. Con otras palabras: Si duda de la memoria de su computadora compila un núcleo de Linux en ella. Otra razón para la compilación que no mencioné arriba.
Para usuarios de un sistema Debian Gnu/Linux las cosas se facilitan con el paquete utilitario “kernel-package”, que provee el comando “make-kpkg”. Para compilar un núcleo y preconfigurarlo para la instalación solamente se necesita ejecutar:
y eventualmente de antemano “make-kpkg clean”.
Hay varios categoría de configuraciones para un núcleo, las cuales cada una tiene su cantidad de opciones. Muchas de las categorías o son presentes, o no lo son. En caso que se selecciona por ejemplo compilar un núcleo sin soporte de red, ya no se hacen preguntas acerca de tarjetas de red, protocolos de red, o sistemas de archivos que permiten compartir archivos en red.
A continuación se describe brevemente cada categoría de configuración del núcleo versión 2.2.17 que es estándard para la distribución Debian Gnu/Linux. Esto está tomado de la configuración mediante “make menuconfig”. En el programa de configuración mismo se puede obtener ayuda extensiva para cada categoría y para cada pregunta (opción), pero también hay mucha infomración en el código fuente del núcleo mismo. En primer lugar esta se encuentra en el directorio “Documentation” dentro de la raíz del núcleo, después hay información adicional en los directorios de los archivos .c mismos.
En la versión 2.4. del núcleo la estructura es un poco diferente, aquí solamente se discutan opciones no existentes en el núcleo 2.2.
En un núcleo modular hay varios componentes que poner en su lugar para que el sistema pueda utilizarlo en el arranque. Primero lógicamente el archivo de núcleo mismo, y un bootstrap loader que lo carge a la memoria en el inicio del sistema. Este va a ser lilo en nuestro caso. Después se necesitan copiar los archivos de los módulos correspondientes al núcleo al directorio respectivo. y por fín conviene copiar el archivo con los símbolos de rutinas exportádos del núcleo a su lugar correspondiente, porque varias utilidades administrativas los utilizan para mostrar información sobre el sistema.
En la misma computadora se puede utilizar varios núcleos, inclusive utilizando el mismo dispositivo para el sistema de archivos raíz.
Aunque en teoría se puede utilizar cualquier lugar en el sistema de archivos que esté disponible al Bios de la computadora para guardar el archivo del núcleo, existen convenciones que preferiblemente se respetan. Hay una convención de tener un enlace simbólico con nombre “vmlinuz” en el directorio raíz. El directorio “/boot” se utiliza para guardar todos los núcleos que se ofrecen para el arranque. El núcleo estándard se instala entonces con un archivo /etc/lilo.conf estándard que contenga las líneas:
image=/vmlinuz
label=Linux
read-only
y mediante el comando: “lilo”
Una convención práctica del sistema Debian Gnu/Linux es, tener un segundo enlace simbólico /vmlinuz.old que indica al núcleo genérico de instalación en el directorio /boot y que se puede cargar con la etiqueta “LinuxOld”. De esta manera se garantiza que siempre hay un núcleo “de reserva” si se compila e instala un núcleo nuevo que no funciona.
Con el comando “make modules_install” ya se copian los archivos de módulos generados a la hora de compilar el nucleo en su lugar correspondiente. No es trivial ubicar dónde específicamente va a parar un archivo de módulo. Entre las diferentes versiones de núcleos se han estado desarrollando también diferentes formas de organizar y repartir los archivos de núcleos.
Las versiones 2.0 del núcleo han sido orientados a computadoras con procesadores intel (i386) y contemplando solamente hardware “estándard”, más que todo controladores de discos (dispositivos bloque), de terminales (dispositivos de caracteres), dispositivos de red y algunos mas. La gran variedad de hardware, por ejemplo dispositivos de sonido ha requerido separar estos en un subdirectorio aparte en el núcleo 2.2.
A partir del núcleo 2.4 hubo una reestructuración fundamental, que toma en cuenta que el núcleo Linux ya está disponible para muchos diferentes arquitecturas de computadoras (diferentes procesadores), y separa elementos independientes de la arquitectura de elementos específico para el CPU o para los buses específicos para un cierto hardware en diferentes directorios.
También el paquete modutils depende de esta distribución y versiones anteriores de este software no encuentran los módulos de núcleos mas recientes.
En el directorio /boot también se copian los archivos config-<versión> del núcleo, que contiene todos los parametros de compilación del núcleo en cuestión, y el archvio System.map-<versión> que contiene los símbolos exportados.
Los felices que utilizan el sistema Debian pueden contar con que la utilidad “kernel-package” copie estos archivos y los módulos automáticamente en el lugar correcto. “make-kpkg kernel-image” crea un paquete debian (.deb) en el directorio /usr/src, que puede ser “instalado” con el comando “dpkg -i kernel-image-<versión>_Custom.1.00_i386.deb”. Este paquete contiene todos los componentes arriba mencionados, los copia en sus lugares correctos y ejecuta lilo para instalar el núclo en el sector de arranque. Si se trata de instalar un núcleo con una versión ya instalado, el programa se rehusa a copiar los módulos y pide reconfirmación. Si se está seguro de querer sobreescribir la versión actual del núcleo de esta versión no se debe insistir, sino primero borrar el directorio con los módulos por completo: rm -rf /lib/modules/<version>, de otra manera se mantienen posiblemente archivos de módulos adicionales en este directorio de los cuales depmod genera mensajes de error de dependencia a la hora de iniciar la computadora.
No es recomendable borrar los módulos del núcleo de instalación. “kernel-package” permite especificar una “sub-versión” para el núcleo a la hora de compilación, con lo cual el nuevo núcleo se distingue aunque sea de la misma versión que un núcleo actual En este caso se instalan los módulos en un directorio diferente. Esto se realiza mediante la opción:
donde <etiqueta> puede ser escogido por el administrador del sistema, p.ej. “-actual”, o “-1”, “-2”, etc.
El paquete “kernellab” permite la administración y regeneración automática de muchos versiones y configuraciones de núcleos en una sola computadora, por ejemplo para una máquina “servidor” de núcleos para una red grande y con diferentes computadoras.
[rol de demonios en el sistema. Funcionamiento detallado de init y uso de diferentes runlevel - niveles de ejecución.]