Introduccion — De que sirve un dispositivo crudo?
Existen tres tipos de interfaz para un dispositivo en Linux: dispositivos de red, dispositivos de caracteres y dispositivos de bloques. Los tres son descritos en detalle en cualquier libro de texto acerca de la arquitectura interna de un SO POSIX, y para una comprensión detallada y maximizar su explotación, sería necesario que se estudiara propiamente (cosa que es típica de una clase de Sistemas Operativos).
De los primeros no hablaré. Son algo muy basto.
Los segundos son aquellos cuya interfaz natural de acceso es “caracter a caracter”, como puede ser un puerto serial, una tarjeta de sonido, un puerto paralelo o un puerto USB. Cada vez que se quieren obtener/enviar datos desde/hacia el dispositivo en cuestión se hacen lecturas de números arbitrarios de bytes, que son procesados directamente desde el espacio kernel al espacio usuario.
Los terceros son aquellos cuya interfaz natural de acceso es “en bloques de tamaño fijo”, como puede ser un disco duro, una unidad de CD-ROM o un RAM-disk. Cada vez que se quieren obtener/enviar datos desde/hacia el dispositivo en cuestión se hacen lecturas de bloques de un tamaño fijo, usualmente optimizado para adaptarse a las características de la plataforma particular, que son procesados desde el espacio kernel hacia el buffer cache, y desde allí son llevados a espacio usuario. En efecto se hacen _dos_ transferencias de memoria, pero la intención del cache es que solamente se haga una transferencia física con la esperanza de que varios procesos quieran “leer lo mismo”. Suena simple pero es bastante complicado: algoritmos LRU, algoritmos de ascensor, algoritmos de lectura anticipada, algoritmos de lectura en demanda y copia en escritura son combinados delicadamente para maximizar el rendimiento y minimizar la latencia y retardo en las operaciones de I/O.
Los requerimientos Ocacionales
En ocasiones, se requiere que un dispositivo de bloques sea manipulado directamente sin pasar por el buffer cache.
Linux permite manipular un dispositivo de bloques a través de la interfaz cruda, queriendo decir que se le indica al kernel “a partir de este momento, cualquier operación sobre el dispositivo de bloques X, que usualmente harías a través del buffer cache, quiero que se haga directo de espacio kernel a espacio usuario… porque yo sé lo que estoy haciendo”. Eso se logra enlazando un /dev/rawX con el dispositivo de bloques deseado.
Creacion de nuestra particion Cruda (raw)
Dentro de nuestro escenario de pruebas, tenemos al sistema operativo linux instalado sobre /dev/sda/. Visualicemos las particiones existentes en /dev/sda:
[root@localhost ~]$ fdisk -l /dev/sda Disk /dev/sda: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sda1 * 1 13 104391 83 Linux /dev/sda2 14 1044 8281507+ 8e Linux LVM
Nuestro dispositivo de bloques /dev/sda se encuentra completamente particionado, a razon de esto, hemos agregado otro disco duro (un disco IDE) sobre /dev/hdc. Actualmente dicho dispositivo no alberga particion alguna.
[root@localhost ~]$ fdisk -l /dev/hdc Disk /dev/hdc: 524 MB, 524288000 bytes 16 heads, 63 sectors/track, 1015 cylinders Units = cylinders of 1008 * 512 = 516096 bytes Disk /dev/hdc doesn't contain a valid partition table
Generando las particiones Raw
[root@localhost ~]$ fdisk /dev/hdc Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won't be recoverable. Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite) Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1015, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-1015, default 1015): +250M Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 2 First cylinder (486-1015, default 486): Using default value 486 Last cylinder or +size or +sizeM or +sizeK (486-1015, default 1015): Using default value 1015 Command (m for help): p Disk /dev/hdc: 524 MB, 524288000 bytes 16 heads, 63 sectors/track, 1015 cylinders Units = cylinders of 1008 * 512 = 516096 bytes Device Boot Start End Blocks Id System /dev/hdc1 1 485 244408+ 83 Linux /dev/hdc2 486 1015 267120 83 Linux p Disk /dev/hdc: 524 MB, 524288000 bytes 16 heads, 63 sectors/track, 1015 cylinders Units = cylinders of 1008 * 512 = 516096 bytes Device Boot Start End Blocks Id System /dev/hdc1 1 485 244408+ 83 Linux /dev/hdc2 486 1015 267120 83 Linux Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks.
Agregando reglas udev
udev es el administrador de dispositivos para la serie de kerneles 2.6. Su funcion primaria es la administracion de nodos dispositivo sobre el directorio /dev. Este es el sucesor de devfs y hotplug. Para agregar un dispositivo raw a nuestro sistema linux 2.6, agregaremos entradas a el archivo /etc/udev/rules.d/60-raw.rules utilizando el siguiente formato:
ACTION=="add", KERNEL=="hdc1", RUN+="/bin/raw /dev/raw/raw1 %N" ACTION=="add", KERNEL=="hdc2", RUN+="/bin/raw /dev/raw/raw2 %N"
Podemos comprobar que los dispositivos raw han sido asignados correctamente ejecutando:
[root@localhost ~]$ raw -qa
