Vous êtes sur la page 1sur 18

Gestión de ficheros - Minix 3

5 Gestión de Ficheros

5.1 Visión general del sistema de ficheros (Tanenbaum 5.6)


5.2 Organización del sistema de ficheros (Tanenbaum 5.6.2)
5.3 La caché de bloques (Tanenbaum 5.6.5)
5.4 Directorios y rutas (Tanenbaum 5.6.6)
5.5 Gestión de Tablas (Tanenbaum 5.7.2)
5.6 Ejemplo llamada al sistema:“read” (Tanenbaum 5.6.10 , 5.7.4)

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 1
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

El Gestor de Ficheros de Minix 3, al igual que cualquier otros sistemas, debe tratar
aspectos como reserva y liberación de espacio para los ficheros, control de bloques
libres y asignados, control de acceso a los ficheros, etc. A lo largo de este capítulo
veremos algunos de los aspectos más relevantes de cómo se acomente la gestion
de ficheros en Minix 3.
El Gestor de ficheros (en adelante GF) de Minix 3 es un programa bastante grande
escrito en “C” que corre en espacio de usuario. Los procesos de usuario realizan
las llamadas al sistema relacionadas con ficheros , tales como abrir fichero, leer,
escribir, cerrar , etc, comunicándose con él mediante el envío y recepción de
mensajes, tal y como es habitual en Minix. El mecanismo es similar al empleado
por el Gestor de Procesos que ya se ha estudiado. Este diseño tiene algunas
implicaciones, por una parte, es posible modificar, ex-perimentar y testear el GF
casi completamente independientemente del resto de Minix. Por otra, es bastante
fácil portar el GF a otro ordenador dotado de un compilador de “C” . De este modo
podría se usado como un servidor de ficheros remoto. Los únicos cambios
requeridos afectarían a la forma en la que los mensajes se han de enviar y recibir,
la cual varía en cada sistema.

1
Gestión de ficheros - Minix 3
Visión general (1/4)
FUNCIONES BÁSICAS DEL GESTOR DE FICHEROS
• Tratar diversas llamadas al sistema
• Resolver las referencias a ficheros
• Comprobar el permiso de acceso a los recursos
• Ofrecer un tamaño de bloque lógico único
• Caché de bloques
• Asignación/liberación de espacio en dispositivos de bloques
• Gestión de errores

Init Proc. Proc. …


Usr. 1 Usr 2.

G.P. Info. S. Net. S G.F. …

Driver Driver Driver …


disco TTY Ethernet
Tarea Tarea Kernel
Sistema Reloj

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 2
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Las funciones principales del GF de Minix 3 son:

- Tratar las llamadas al sistema relacionadas con ficheros tales como: creat, mknord, open,
close, read, write, lseek, stat, fstat, dup, pipe, ioctl, link unlink, mount, umount, sync, chdir,
chroot, chmod, chown, umask, acces, time stime, utime, times , etc.
- Resolver las referencias a ficheros. El GF debe saber qué dispositivo tiene asociado a un
fichero (disco, terminal, etc) para poder realizar las operaciones de E/S . Para ello guarda
en el I-nodo los números de dispositivo principal y secundario. El principal indientfica el
driver y el secundario el dispositivo propiamente dicho.
- Comprobar permisos de acceso a los recursos. Esto se realiza mendiante unos bits de
proteción que se mantienen en el I-nodo. Estos bits especifican entre otras cosas si el
objeto es un fichero o directorio, si tiene acceso de lectura, escritura o ejecución para los
diferentes ususarios y grupos, etc.
- Ofrecer un tamaño de bloque logico único para los dispositivos orientados a bloque. El
tamaño estándar de Minix 3 es de 4096 bytes.
- Almacenamiento intermedio de datos para dispositivos de bloques: Caché de bloques.
Este sistema agiliza la lectura/escritura de información, dado que la memoria en la que
reside la cache es más rápida que la de disco.
- Asignación y liberación del espacio en dispositivos de bloques. Para realizar este trabajo
Minix 3 utiliza mapas de bits de “zonas” (una zona es un número de bloques potencia de 2).
- Gestion y control de errores.

2
Gestión de ficheros - Minix 3
Mensajes proceso de usuario Parámetros de entrada Valor de respuesta
acces Nombre de fichero, modo de acceso Status
chdir Nombre nuevo directorio de trabajo Status
chmod Nombre fichero, nuevo modo Status
chown Nombre fichero, propietario, grupo Status
chroot Nombre del nuevo directorio Status
close Descriptor fichero a cerrar Status
creat Nombre fichero a crear, modo Descriptor de fichero
dup descriptor fichero (para dup2, 2 fds) Nuevo descriptor de fichero
fcntl descriptor fichero, código función, arg Depende de la funcion
fstat Nombre del fichero, buffer Status
ioctl Descriptor fichero, código función, arg Status
link Nombre fichero , nombre del enlace Status
lseek Descriptor fichero, desplazamiento, modo Nueva posición
mkdir Nombre fichero, modo Status
mknod Nombre Directorio especial, modo, dirección Status
mount Fichero especial., donde montar, “ro” flag Status
open Nombre fichero, “r/w“ flag Descriptor de fichero
pipe Puntero a descriptor de fichero [2] (modificado) Status
read Descriptor fichero, buffer, cuantos bytes Nº Bytes leidos
rename Nombre Fichero, nombre fichero Stauts
Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 3
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

El GF acepta 39 mensajes diferentes. De ellos sólo dos no tratan llamadas al


sistema. Estas dos excepciones son mensajes generados por otras partes de Minix
3. De las 37 llamadas al sistema, 31 provienen de procesos de usuario, las otras 6
provienen del Gestor de Procesos (GP) como parte del tratamiento del alguna
llamada al sistema implementada por el GP y que necesita del GF.

3
Gestión de ficheros - Minix 3
Mensajes proceso de usuario Parámetros de entrada Valor de respuesta
rmdir Nombre de fichero Status
stat Nombre de fichero, buffer de estado Status
stime Puntero al tiempo actual Status
sync (nada) Siempre OK
time Dirección donde dejar el tiempo actual Status
times Buffer para tiempos de proceso e hijos Status
umask Complemento del modo mask Siempre OK
umount Nombre fichero especial a desmontar Status
unlink Nombre fichero a desenlazar Status
utime Nombre fichero, tiempos del fichero Siempre OK
write Descriptor de fichero, buffer, cuantos bytes Nº Bytes escritos
Mensajes del Gestor de Procesos
exec, exit Pid Status
fork Pid del padre, pid del hijo Status
Pid, real y efectivo (el uid y gid
setuid, setgid Status
respectivamente)
setsid Pid Status
Otros Mensajes
revive Proceso a revivir (sin respuesta)
unpause Proceso a chequear (explicación aparte)

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 4
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Cuando el Gestor de Procesos intenta enviar una señal a un proceso debe


averiguar si dicho proceso está bloqueado en un pipe o fichero especial (terminal)
por el GF (en cuyo caso debe ser despertado con el error EINTR). Dado que el GP
no controla dicho estado debe enviar un mensaje al GF para ello. Este mensaje es
“unpause” el cual hace que el proceso salga de su bloqueo.

Cuando el GF realiza una operación de lectura por ejemplo sobre el terminal y ésta
no se puede completar, dado que el GF no puede quedarse bloqueado
indefinidamente a la espera de que haya suficientes caracteres en el terminal, el
driver de terminal toma nota de la operación pendiente y devuelve SUSPEND, para
que el GF no quede bloqueado. Más adelante, cuando se complete la operación
(suficientes teclas pulsadas), el driver de terminal envía el mensaje “revive” al GF
para que éste a su vez, desbloquee al proceso de usuario que originó el servicio.

4
Gestión de ficheros - Minix 3
Visión general (4/4)
PUBLIC int main() {
/* Bucle principal del gestor de ficheros. Consiste en tres actividades básicas:
Obtener trabajo, procesarlo y enviar una respuesta */
fs_init (); /* inicializacion */
while (TRUE) { /* bucle sin fin que obtiene y procesa el trabajo */
get_work (); /* devuelve “quien” y “nº llamada” */
if (call_nr==PROC_EVENT) { /* se comprueban mensajes de control especiales */
… /* tales como notificaciones y alarmas vencidas */
if (call_nr<0 || call_nr>= NCALLS) { /* comprobación de error en nº llamada */
….. /* se comprueban otros posibles errores como nº proceso ilegal */
} else
error = (*call_vec[call_nr]) ; /* se procesa la llamada (trabajo) */

/* se copia el resultado y se envia la respuesta */


if (error != SUSPEND) reply (who_e, error);
if (rdahed_inode != NIL_INODE) read_ahead(); /* lectura de bloque adelantada */

}
return(OK); /* no se debería llegar aquí */
}

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 5
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

La estructura del GF es básicamente la misma que la del Gestor de Procesos y los


manejadores de dispositivo. Consta de un bucle principal que espera por la llegada de un
mensaje. Cuando éste llega, se extrae su tipo (get_work). Si es un mensaje especial de
control, éste puede ser SYS_SIG, usado para “SHUTDOWN” , o bien SYN ALARM, que
indica que ha expirado una alarma o por último un NOTIFY_MESSAGE, que indica que un
dispositivo requiere atención. Si no es un mensaje especial entonces el tipo del mismo se
usa como índice en una tabla que contiene las direcciones de las funciones de tratamiento
para invocarlas. Las funciones de tratamiento realizan su trabajo y en función del resultado
se envía o no una respuesta al proceso llamador (reply). La última sentencia detecta que se
está leyendo un fichero secuencialmente y carga el siguiente bloque en la caché antes de
que realmente se solicite y así mejorar el rendimiento. Finalmente el bucle vuelve a
comenzar quedando a la espera de un nuevo mensaje.
Hay que señalar que en la función get_work se comprueba si algún proceso previa-mente
bloqueado ha revivido, ya que si así fuera así esto tendría prioridad y en vez de recibir un
nuevo mensaje se extraería el que quedó pendiente y se retornaría.
Normalmente, el GF al tratar una llamada al sistema la lleva a cabo inmediantemente y
desbloquea al proceso que la hizo, sin embargo en algunos casos, con llamadas
relacionadas con “pipe” y terminales, estas llamadas no se pueden completar de forma
inmediata. Esto obliga a que el GF deje bloqueado al proceso sin enviarle una respuesta y
continúe recibiendo peticiones de otros trabajos. Eventualmente la petición pendiente se
puede completar y se revive al proceso bloqueado, siendo éste el caso que se menciona
arriba.
En la función “reply” se envía una respuesta, aunque puede suceder que el proceso al que
haya que responder esté muerto. En ese caso “reply “devolvería un error, pero esto no
tendría importancia ya que en cualquier caso no habría que hacer nada.

5
Gestión de ficheros - Minix 3
Organización del sistema de ficheros (1/4)
Mapa de bits
de I-Nodos Mapa de bits
de zonas Formato de disco

……

Area de Area de
I-Nodos Datos

Bloque autorranque:
Programa de carga Superbloque:
del S.O -Número de I-nodos
-Número de bloques del mapa de bits de I-Nodos
-Número de bloques del mapa de bits de Zonas
-Primera zona de datos
-Log2 (tamaño zona/tamaño bloque)
-Tamaño máximo de fichero
-Número de zonas
-Tamaño del bloque
-Sub-version del Sistema de Ficheros

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 6
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

El formato lógico del sistema de ficheros presenta siempre la misma estructura:


- Bloque de autoarranque: Su tamaño es siempre de 1024 bytes, independientemente del tamaño del
bloque de Minix 3. Cuando se enciende el ordenador, la BIOS lee el bloque de arranque en memoria
e inicia su ejecución., comenzando entonces el proceso de autocarga del S.O. Todos los discos
tienen reservado este bloque aunque su utilidad no se requiere siempre. En este bloque hay
guardado en una posición fija un número mágico para poder ser comprobado y así evitar un arranque
indebido.
- Superbloque: El superbloque contiene información sobre la disposición lógica de los bloques del
sistema de ficheros. Su tamaño, al igual que el del bloque de autoarranque, es siempre de 1024
bytes. La información en el superbloque es redundante. Algunos datos se pueden calcular en funcion
de otros. A veces la información se requiere en una forma y otras veces en otra. Puesto que no hay
problemas de espacio es mejor así que tener que recalcular en tiempo de ejecución. La unidad de
reserva de espacio para los ficheros es la “zona”, cuyo tamaño son 1, 2, 4, 8, o en general 2n
bloques. El campo Log2 del superbloque contiene precisamente el valor del exponente “n”. En Minix
3 el tamaño de bloque de un disco estándar es de 4 Kbytes y una zona ocupa un bloque.
Los mapas de bits de I-nodos y zonas son áreas que se usan para reflejar el estado libre/ocu-pado
de los I-nodos y/o zonas respectivamente. El primer bit está asociado al I-nodo/zona cero y siempre
vale “1”, ya que el valor cero no puede ser usado, por estar reservado, ni en los I-nodos ni en las
zonas. El mapa de bits de zonas sólo incluye el área de datos, es decir no incluye ni el área de I-
nodos ni los bloques de de mapas de bits.
El área de I-nodos ocupa tantos bloques como se requieran teniendo en cuenta que el tamaño de un
I-nodo es de 64 bytes. El I-nodo 0 es el primero, ocupa espacio pero como ya se ha dicho está
reservado y no puede usarse.
la primera zona de datos es la “1”, donde empieza el directorio raiz del SF, es decir no existe la zona
0.

6
Gestión de ficheros - Minix 3
Organización del sistema de ficheros (2/4)
Bloque
autoarranque Superbloque Formato de disco

……

Area de Area de
I-Nodos Datos

Mapas de bits :
1111101011 1100100011
0010011010 0111010011

I-Nodo
1100010010 1100101010 Zona
20
1001010111 0101001010 29
usado
0001010100 1100001010 libre
. . . . . . . . . .
0100000000 0000000000

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 7
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Minix 3 controla qué I-nodos y qué zonas están ocupados(as) o libres mediante mapas de
bits. Cuando se elimina un fichero, es fácil calcular en qué bloque del mapa de bits está el
bit asociado al I-nodo de dicho fichero y poner dicho bit a 0. Igualmente sucede para las
zonas. Cuando se crea un fichero el GF debe buscar un I-nodo libre. Para ello dispone de
un campo en la copia de memoria del superbloque que contiene la dirección del primer I-
nodo libre. Cuando el GF usa dicho I-nodo, debe actualizar el campo para que apunte al
siguiente I-nodo libre, que resultará ser el siguiente o uno posterior, buscándolo
secuencialmen-te y en adelante en el mapa de bits. Por otro lado, cuando se libera un I-
nodo, se comprueba si dicho I-nodo es anterior al apuntado, para actua-lizar el puntero si
así fuera. Si al buscar no se encuentra ningún I-nodo libre, la rutina devuelve el valor 0.
Esta es la razón por la que no se usa el 0 como número de I-nodo válido. Todo lo dicho
aquí para los I-nodos es aplicable también para las zonas; aunque lógicamente en este
caso, las búsquedas se efectúan cuando se requiere espacio de disco.
El propósito de la “zona” es mejorar el rendimiento de acceso secuencial haciendo que
bloques pertenecientes al mismo fichero se ubiquen en el mismo cilindro. Esto se consigue
al hacer que el fichero crezca y se ubique en unidades “zona”. La mayor parte del GF
trabaja con bloques. Las transferencias de disco son de bloque completo. La caché también
trabaja con bloques individuales.
El trabajar con zonas genera un problema que hay contemplar: Si por ejemplo, sobre un
fichero de 1 KB, en un sistema con bloque=1 KB y zona=4 KB, se efectúa una opera-ción
“lseek(32768)”, y a continuación se escribe 1 byte, el fichero crecería a 32769 bytes.
Posteriores lecturas más alla del byte 1024 podrían obtener información almacenada en el
sistema con anterioridad, lo que sería un fallo de seguridad a evitar. La solución es rellenar
a 0’s explícitamente, los bloques de la última zona que se ubica cuando un fichero crece.

7
Gestión de ficheros - Minix 3
Organización del sistema de ficheros (3/4)
Superbloque Formato de disco

……

Mapas Area de I-Nodos


Area de Datos
Bloque de bits 32 bits
autoarranque
Bits “rwx” y tipo fichero Modo Nº links Entradas de direc del fichero
Id . propietario Uid Gid Grupo del propietario
Tamaño Fichero
Tiempo acceso
Tiempo modificación Tiempo en segundos
desde 1 Enero 1970
Tiempo cambio status
Estructura Zona 0
del I-Nodo Zona 1
(64 bytes) Zona 2
Numeros de zona para
Zona 3 las primeras 7 zonas
Zona 4
Zona 5
Zona 6
Zona simple Indirecto Para ficheros de tamaño
Zona doble indirecto superior a 7 zonas
Sin uso

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 8
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

La función principal del I-nodo es indicar donde se encuentran los bloques del
fichero. El tamaño del I-Nodo en Minix 3 es de 64 bytes. Se usan 9 punteros a zona,
7 directos y 2 indirectos. Aunque hay espacio para uno más, la versión estándar no
lo soporta. Con un tamaño de bloques y zona de 4 KB, y puesto que los números de
zona son de 32 bits, en un bloque/zona de indices caben 1024 entradas
(apuntadores a zona). El doble indirecto da para 1024 x 1024 bloques/zonas,
haciendo que el tamaño máximo del fichero supere los 4GB. En la práctica el uso de
números de 32 bits para “offset” del fichero limita el tamaño del mismo a 4GB. Por
esta razón, al usar el estándar Minx 3 un tamaño de bloque/zona de 4KB, no se
requiere el uso del triple indirecto.
Los campos “tiempo ..“ son estándar, como en Unix. El último de ellos se actualiza
con casi todas las operaciónes excepto con la lectura del fichero.
El I-nodo tambien guarda información de modo, la cual informa del tipo de fichero
(regular, directorio, pipe, especial bloques, especial caracteres) y da los bits de
protección SETUID y SETGID. El campo “link” guarda cuantas entradas de
directorio apuntan al I-nodo.
El I-nodo puede usarse algunas veces de forma un poco especial, por ejemplo los
ficheros especiales de dispositvos de bloque y carácter no requieren los
apuntadores a zona y requieren en cambio los números “major” y “minor” de
dispositivo, por ello reutilizan el número de zona 0 para este propósito. Otro posible
uso, aunque Minix 3 no lo emplea, sería usar el I-nodo para guardar ficheros
pequeños inmediatos en el espacio para los números de zona.

8
Gestión de ficheros - Minix 3
Organización del sistema de ficheros (4/4) -Nº de I-nodos
-Nº de bloques del bitmap de I-Nodos

También en disco
-Modo y links
Tabla de I-nodos Tabla de superbloques -Nº de bloques del bitmap de Zonas
-Uid y Gid
-Primera zona de datos
-Tamaño fichero
-Log2 (tamaño zona/tamaño bloque)
-Tiempos acceso,
-Tamaño máximo de fichero
modificación y . . . . . . . . . . . . . . . .. ....................
-Nº de zonas
cambio status.
-Tamaño del bloque
-Zonas 0 a 6
-Sub-version del Sistema de Ficheros
-Zonas SI y DI
-Puntero a I-nodo del SF Montado
-Dispositivo Tabla flp -Puntero a I-nodo en el que se monta
-Nº I-nodo
- I-nodos / bloque
-Nº veces usado
-Número de dispositivo
-Limpio / sucio
-Flag sólo lectura
...............
-Montado (i_mount)
-Flag nativo o byte intercambiado
-Otros…
-Version del sistema ficheros
-Zonas directas / I-nodo
Tabla de procesos -Zonas indirectas / bloque indirecto
-Abierto para lectura/escritura
-Nº referencias de descrip. Fich.
.....
Tabla locks
....................
-Puntero a entrada Tbl. I-nodos
-Valor puntero L/E
-Máscara creacion ficheros ...............

-Puntero a I-nodo D.Trabajo


-Puntero a I-nodo D. Raiz
-Tabla descriptores fichero -Tipo lock lectura / escritura
-Uid’s real y efectivo -Pid que hizo el lock
-Gid’s real y efectivo -Puntero a I.nod fich. Bloqueado
-Otros campos -Principio y fin region bloqueada

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 9
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

El GF dispone de cinco tablas en memoria importantes: Tabla de procesos, tabla de superbloques,


tabla de I-nodos, tabla de ficheros abiertos (filp) y tabla de locks. Además existe la caché de bloque
que estudiaremos aparte.
La tabla de procesos forma parte de la tabla de procesos distribuida de Minix 3, junto con la del
Kernel y GP. Los campos más relevantes se ven en la figura. Al igual que la tabla del GP, no
incorpora las tareas. Tiene su misma cantidad de elementos y en el mismo orden. Hay que señalar el
campo “tabla de descriptores de ficheros”, el cual guarda cada uno de los descriptores de ficheros
abiertos del proceso. El índice a esta tabla es el valor devuelto por “open” y su contenido es un
puntero a la tabla “filp” .
La tabla “filp” contiene el valor del puntero de L/E de un fichero. Este valor lo pueden compartir varios
procesos mediante el mecanismo creado por “fork”. El nº de procesos que lo comparten se guarda en
un campo de la tabla. Cuando se cierra un fichero de éstos, se decrementa este valor y si queda a 0
se elimina la entrada de la tabla. También se guarda un puntero a la tabla de I-nodos y el modo de
apertura.
La tabla de I-nodos contiene los I-nodos de todos los ficheros abiertos por el sistema, más algunos
campos adicionales. Entre estos figura el dispositivo donde reside el fichero, el nº de I-nodo, si se ha
modificado (limpio/sucio), si hay algún SF montado sobre él, un contador de referencias al mismo, y
otros campos menos relevantes. Cuando se cierra un fichero se decre-menta el contador de
referencias, y si llega a 0, se elmina el I-nodo de la tabla, escribiéndolo en disco si estuviera sucio.
La tabla de locks sirve para gestionar áreas de un fichero que se quieren bloquear para lectura o
escritura. Minix 3 (según normativa POSIX) no impide realmente el acceso a dichas áreas. Esto es
algo que han de convenir y aceptar las aplicaciones.
La tabla de superbloques contiene una entrada por cada SF montado, con una copia del superbloque
del cada uno de ellos y algunos datos adicionales más. De ellos, estudiaremos especialmente más
adelante, los dos campos punteros a I-nodo involucrados en la operación “mount”.

9
Gestión de ficheros - Minix 3
La cache de bloques Puntero Siguiente LRU
MRU Puntero Anterior LRU
LRU
1040 bloques Puntero Lista Hash
(Front) (Rear)
Número de bloque
Dispositivo (maj/min)
0 Limpio / Sucio
1 Contador de uso
2

Datos bloque
4096 bytes
-Para buscar un bloque se extrae su código hash
y se recorre su lista hash. Si no se encuentra se
2047
selecciona al primero de la LRU como víctima
Tabla hash
y le carga el bloque de disco en él, añadiendolo
a su lista hash correspondiente.
-En get_block, cuando se encuentra un bloque
se incrementa el contador de uso y se le quita Nº de bloque: 12345 (0x3039)
de la LRU. En put_block se decrementa el con-
000000000011000000111001
tador y se devuelve el bloque a la lista LRU.
-Al devolver un bloque a la LRU se inserta por
Código hash: 57 (0x39)
el final, excepto si es un bloque del disco RAM.
-Un bloque sucio se escribe en disco cuando:
Es elegido víctima o con la llamada “sync”.

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 10
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

La caché de Minix 3 utiliza un “array” de un tamaño fijo de buffers. El tamaño de este array y el
tamaño del bloque dependen de la compilación de Minix. Para un PC típico este el array es de 1040
elementos y el bloque de 4 KB. Cada elemento, o buffer, contiene una cabecera y un bloque de
información. En la cabecera se encuentran los punteros para implementar las listas LRU, MRU y
Hash, el Nº de bloque, el dispositivo donde reside el bloque, el campo limpio/sucio (indica si ha
habido cambios desde que se cargó en memoria), y un contador de uso. Además de este array
existe otro llamado “tabla Hash” de 2048 elementos que sirve para determinar rápidamente si un
bloque está, o no, en la caché. Todos los buffers que contienen un bloque cuyo código hash es “k”,
están enlazados en una lista simple encabezada por la entrada “k” de la tabla hash. La función hash
calcula “k” extrayendo simplemente los “n” bits menos significativos del nº de bloque, con
independencia del dispositivo. Inicialmente todos los buffers están sin usar y enlazados a la lista hash
“0”. Las demás listas hash están vacías. Cuando el GF requiere un bloque llama a la función
“get_block”, la cual calcula el código hash y busca en su lista hash, discriminando el nº de dispositivo.
Si se encuentra, se incrementa el contador de uso, se quita de la lista LRU/MRU y se devuelve como
resultado un puntero al buffer. Si no se encuentra, se elige como víctima el primer buffer de la lista
LRU. Está garantizado que no estará en uso.
Antes de deshacerse de la victima hay que comprobar el flag limpio/sucio, para escribir o no el
bloque en consecuencia. En este punto se envía un mensaje al driver de disco para leer el bloque
requerido, quedando el GF a la espera de la respuesta. Cuando ésta llega el GF continúa y acaba
retornando un puntero al buffer con el bloque leido. Cuando el procedimiento que solicitó el bloque
completa su trabajo llama a la función “put_block” la cual decrementa el contador de uso y si queda
en 0 devuelve el bloque a la lista LRU.
Casi todos los bloques se insertan por el final de la lista LRU. La excepción son los bloques de disco
RAM. Un bloque no se escribe en disco hasta que sucede, bien que se alcanza el principio de la LRU
y se elige como victima, o bien se ha ejecutado la llamada al sistema “sync”. Esta función recorre el
array de buffers, no la lista LRU, evitando así la omisión de buffers “en uso” (que no están en la lista
LRU).

10
Gestión de ficheros - Minix 3
Directorios y rutas 1/2 Tabla de nodos-
nodos-i Formato de directorio
Nº de I-nodo
Tabla de procesos del GF (4 bytes)

Nombre de fichero
(60 bytes)

Resolució
Resolución de /user/pepe/f1
Punteros a los I-nodo 1 Direct. Raiz I-nodo 7
I-nodos asociados (direct. raí
raíz (bloque 120) (direct. User)
a los directorios 1 .
raíz y trabajo de Mode, links Mode, links
Uid, gid 1 .. Uid, gid
éste proceso.
Size, Times 2 dev Size, Times
Z0=120 7 user Z0=206

Direct. user I-nodo 53 Direct. Pepe


(bloque 206) (direct. Pepe) (bloque 303)
7 . Mode, links 53 .
1 .. Uid, gid 7 ..
15ana Size, Times 88 d3
53 pepe Z0=303 44 f1

Tamaño bloque = zona

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 11
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

En Minix 3 los directorios son ficheros estructurados en forma de tabla con elementos de 64 bytes.
Cada entrada consta de dos campos, el primero, de 32 bits, guarda el nº de I-nodo del fichero. El
segundo, un campo de 60 bytes, guarda el nombre del fichero en forma de array de caracteres
finalizados con el carácter 0. Hay gran cantidad de llamadas al sistema que utilizan como parámetro
una ruta ó camino a fichero. Todas ellas deben resolver dicha ruta para acceder al fichero, siguiendo
una serie de pasos. En la figura se muestra un ejemplo: Para conseguir el I-nodo del fichero
“/usr/pepe/f1” hay que acceder al I-nodo del directorio raiz. Todo proceso guarda en un campo de su
descriptor, en la Tabla de Procesos (TP), un puntero al mismo. En el ejemplo, el I-nodo 1. En dicho I-
nodo leemos el primer bloque (zona) de datos que es la 120. Accediendo a dicho bloque (zona), que
contiene el directorio raiz, buscamos la entrada “user”, la cual tiene de I-nodo el 7. Accedemos al I-
nodo 7 a través de la tabla de I-nodos (si no esturviera en la tabla habría que cargalo desde el area
de I-nodos del disco). Vemos en dicho I-nodo el primer bloque (zona) de datos que es el 206 y
seguimos así hasta conseguir que finalmente el I-nodo 44 se carge en la tabla de I-nodos. En todo
este proceso, al solicitar bloques de datos, se hace uso de la caché. Algunos bloques solicitados
estarán en ella y otros habrá que traerlos de disco a la misma. Los I-nodos de directorios se
descargan de la tabla de I-nodos una vez usados, excepto si estuvieran siendo usados por otro
proceso.
Cuando la ruta a resolver es relativa al directorio de trabajo, como por ejemplo “pepe\f1” el proceso
que se sigue es similar pero comienza con el puntero a I-nodo del directorio de trabajo del proceso, el
cual se encuentra también en su descriptor o entrada en la TP.
En el proceso descrito arriba no se ha contemplado si existe algún SF montado en algún directorio.
Veremos más adelante como se efectua la operación “mount” y como afecta a la busqueda o
recorrido de una ruta.
Hay que señalar también que durante el recorrido de la ruta, el GF ha de comprobar los permisos de
acceso a cada uno de los directorios de paso. Para todas la llamadas al sistema se utilizan los uid y
gid efectivos del proceso excepto para la llamada “access” que se usan los uid y gid reales.

11
Gestión de ficheros - Minix 3
Directorios y rutas 2/2 Sistema de
ficheros montado
Sistema de Sistema de
/
ficheros raíz ficheros a montar
/ /
lib bin user

lib bin user pepe ana juan


/ NO
f_u
visible
Directorio sobre f_u f1 f2
El que se monta pepe ana juan

Superbloque del sistema I-nodo del


de ficheros raíz Directorio /user f1 f2

Tabla de nodos-
nodos-i 2
Tabla de superbloques i_mount
4 activo

s_imount s_isup
5

3
1
I-nodo del directorio raíz del
Superbloque del sistema sistema de ficheros a montar
de ficheros a montar

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 12
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

En la figura se muestra, grosso modo, el proceso de montaje de un SF sobre un directorio


del SF principal. Los puntos relevantes son:
1)Se carga en la tabla de superbloques el superbloque del SF a montar.
2)Carga el I-nodo del directorio /user (sobre el que se va a montar), si éste no estuviera ya
en la Tabla de I-Nodos.
3)Carga el I-nodo del directorio raíz del SF a montar
4)Activa el campo i_mount del l-nodo del directorio /user. Con ello se indica que sobre el
directorio /user se va a montar un SF.
5)En el superbloque del SF a montar se pone en el campo s_imount un puntero al I-nodo
del directorio /user y en el campo s_isup un puntero al I-nodo del directo-rio raiz del SF a
montar.
6)Carga en la caché los bloques de los mapas de bits de I-nodos y zonas del SF a montar
(estos bloques permanerán en la caché hasta que se desmonte el SF).
Al resolver una ruta se ha de tener en cuenta si hay algún SF montado en algún directorio.
Para ello hay que examinar en cada I-nodo del recorrido si el campo i_mount está activo.
Si es así el GF continuará la búsqueda desde el directorio raíz del SF montado. Para
conseguir esto, el GF recorre la tabla de superbloques buscando aquel cuyo campo
s_imount apunte al I-nodo del directorio sobre el que se ha montado el SF secundario. Una
vez localizado, accede al I-nodo del directorio raíz del SF secundario a través del campo
s_isup del superbloque. Todo esto implica que mientras dure el montaje de un SF sobre un
directorio, serán invisibles (e inaccesibles) cualquier posible rama de subdirectorios o
ficheros que cuelguen de dicho directorio.

12
Gestión de ficheros - Minix 3
Gestión de Tablas (1/3)

Procedimientos para la gestión de la caché

Procedimiento Función
get_block Obtiene un bloque para lectura o escritura
put_block Devuelve un bloque previamente pedido por get_block
alloc_zone Reserva una nueva zona (para hacer un fichero mas grande)
free_zone Libera una zona (cuando se elimina un fichero)
rw_block Transfiere un bloque entre disco y caché
invalidate Purga todos los bloques de la caché de algún dispositivo
flushall Escribe todos los bloques sucios de un dispositivo
rw_scattered Lee o escribe datos dispersos a ó desde un dispositivo
rm_lru Quita un bloque de la lista LRU

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 13
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Los procedimientos básicos que soportan la cache son: Get_block. Se invoca con nº de bloque y
dispositivo. Sirve para obtener cualquier tipo de bloque. Ya se ha visto con anterioridad, aunque falta
decir que cuando se especifica only_search como parámetro de entrada, aunque no esté el bloque
en la caché, éste no se lee del disco. Con dicho parámetro se pretende, bien hacer un prefetch, o
bien escribir un bloque en su totalidad. En ambos casos es un desperdicio leer el bloque del disco.
Put_block. Se encarga de devolver el bloque a la lista LRU y en algunos casos escribirlo en disco.
También se ha mencionado con anterioridad. En versiones anteriores de Minix, dependiendo del tipo
de bloque, éste se escribía de forma inmediata o no, Actualmente, aunque se sigue haciendo la
comprobación, no se marca ningún bloque para escritura inmediata. Alloc_zone. Se encarga de
reservar una nueva zona en un dispositivo tomando como punto de partida otra zona que se le da
como parámetro. La reserva la hace buscando en el mapa de bits de zonas. Cuando un fichero crece,
el GF comprueba si es la primera zona, si es así utiliza el campo s_zsearch del superbloque, el cual
apunta siempre a la primera zona disponible del dispositivo. Si no fuera la primera zona, se busca la
siguiente zona a la última zona existente del fichero, para intentar con ello mantener las zonas de un
fichero juntas. Free_zone. Se encarga de devolver las zonas de un fichero al mapa de bits cuando
éste se borra. Lo hace llamando a free_bit, pasándole la posición del bit y el mapa de bits como
parámetros. free_bit también se utiliza para liberar I-nodos. Rw_block. Lee o escribe un bloque entre
disco y cache. Análo-gamente existe la función rw_inode para I-nodos. Invalidate. Elimina todods los
bloques de la caché del dispositivo que se le pasa como parámetro. Flushall. Escribe en disco todos
los bloques sucios de la caché del dispositivo que se le pasa como parámetro. Para hacerlo recorre
el array entero de buffers, evitando así omitir los buffers en uso. Rw_scattered. Los drivers de disco
de Minix 3 no implementan planificación de escritura en disco. Esta función proporciona una
alternativa a dicha carencia. Acepta como parámetros: un dispositivo, un array de punteros a buffers,
el tamaño del array, y un flag indicando lectura o escritura. Lo que hace es ordenar el array de
punteros a buffer según su nº de bloque y luego construye vectores de bloques contiguos para enviar
al driver. La única llamada a rw_scattered para escribir la hace flushall y la única llamada para leer
rahead. Rm_lru. Elimina un bloque de la lista LRU. Se usa desde get_block.

13
Gestión de ficheros - Minix 3
Gestión de Tablas (2/3)

Procedimientos para la gestión de I-nodos


Procedimiento Función
get_inode Trae un I-nodo a memoria
put_inode Devuelve un I-nodo que ya no se necesita
alloc_inode Reserva un nuevo I-nodo (para un nuevo fichero)
wipe_inode Limpia algunos campos de un I-nodo
free_inode Libera un I-nodo (cuando se borra un fichero)
update_times Actualiza los campos de tiempo de un I-nodo
rw_inode Transfiere un I-nodo entre memoria y disco
old_icopy Convierte contenido de I-nodo para escribir a disco V1 I-nodo
new_icopy Convierte datos leidos de un SF con I-nodos V1
dup_inode Indica que algún otro está usando un I-nodo

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 14
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

En la tabla vemos los procedimientos para la gestión de I-nodos. Get_inode. Es análogo a


get_block. Sirve para obtener un I-nodo. Para ello lo busca en la tabla de I-nodos. Si no lo encuentra
lo carga desde disco a la tabla invocando rw_inode. Una vez en la tabla, incrementa el contador de
uso y devuelve su dirección. Cuando el procedi-miento que pidió el i-nodo ya no lo necesita, éste se
devuelve con put_inode, donde se decrementa el contador de uso (i_count). Si llega a 0 se elimina
el I-nodo de la tabla, escribiéndolo a disco si estuviera sucio.
Si el campo i_link es 0, ninguna entrada de directorio hace referencia a él, y por tanto todas sus
zonas son liberadas. Si el I-nodo es de un pipe, todas sus zonas deben ser liberadas, incluso aunque
el nº de links no sea 0 (i_link ! =0). Esto sucede cuando un proceso que lee de un pipe libera el pipe.
No tiene sentido el dejar un pipe para un solo proceso.
Cuando se crea un fichero se reserva un I-nodo con alloc_inode, el cual usa el puntero al primer I-
nodo libre del superbloque para ahorrar tiempo de búsqueda en el mapa de bits, tal y como ya se ha
comentado con anterioridad. Cuando se reserva un I-nodo se llama a get_inode para traerlo a
memoria y ahí se inicializan algunos campos, el resto se inicializa en wipe_inode. Esto se hace así
porque esta función se invoca también en otras partes del GF. Free_inode libera un I-nodo poniendo
su correspondiente bit del mapa de bits a 0 y actualizando el puntero al primer I-nodo libre del
superbloque. Get_times obtiene el tiempo del reloj del sistema y actualiza los campos de tiempo del
I-nodo. Es invocada por stat y fstat. Rw_inode es análoga a rw_block pero con I-nodos. Sus pasos
básicos son: 1) Calcular qué bloque contiene el I-nodo requerido. 2) Leer el bloque mediante
get_block(). 3) Extraer el I-nodo y copiarlo a la tabla de I-nodos, y 4) Devolver el bloque mediante
put_block. En realidad rw_inode es algo más compleja. Cuando se ha de cambiar alguno de los
campos de tiempo del I-nodo, se activa un bit del campo i_update del I-nodo y cuando,
eventualmente, se escribe el I-nodo en disco, se hace la llamada al kernel para obtener el tiempo del
sistema y actualizar entonces los campos de tiempo del I-nodo. Por otro lado, la historia de Minix
añade complicaciones por cambios de formato del SF. Existen las versiones V1, V2 y V3. Las
funciones old_icopy y new_icopy se encargan de realizar las conversiones oportunas. Dup_inode
incrementa el contador de uso de un I-nodo. Se utiliza cuando un fichero es abierto de nuevo.

14
Gestión de ficheros - Minix 3
Gestión de Tablas (3/3)

Procedimientos para la gestión de superbloque y mapas de bits


Procedimiento Función
alloc_bit Reserva u bit de los mapas de bits de zonas o I-nodos
free_bit Libera un bit de los mapas de bits de zonas o I-nodos
get_super Busca la tabla de superbloques de un dispositivo
get_block_size Encuentra el tamaño de bloque a usar
mounted Informa si un I-nodo dado está montado en un SF
read_super Lee un superbloque

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 15
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Como ya se ha visto, los procedimientos alloc_inode y alloc_zone utilizan alloc_bit para


efectuar la búsqueda en el mapa de bits. Esto se lleva a cabo en tres bucles anidados: 1) El
bucle externo itera sobre los bloques del bitmap. 2) El bucle del medio itera sobre las
palabras de un bloque, y 3) El bucle interno itera sobre los bits de una palabra.
Liberar un bit es más sencillo que reservarlo, porque no se requiere búsqueda. Free_bit
calcula en que bloque del bitmap está el bit a liberar, llama a get_block, pone el bit a en
memoria y llamando luego a put_block.
Get_super busca en la tabla de superbloques un dispositivo dado. Por ejemplo, cuando se
va a montar un SF, hay que comprobar que no esté ya montado. Esto se hace llamando a
get_super para comprobar que el dispositivo del SF no esté ya en la tabla.
En Minix 3 el GF es capaz de manejar SF’s con diferentes tamaños de bloque. El propósito
de la lunción get_block_size es determinar el tamaño del bloque de un SF. Para ello busca
en la tabla de superbloques por un dispositivo y devuelve el tamaño del bloque si está
montado, en caso contrario, devuelve MIN_BLOCK_SIZE.
Normalmente, cuando se cierra un dispositivo, se descartan todos sus bloques de datos.
Pero si el dispositivo está montado, esto no es deseable. Para averiguar esto, se llama a
mounted con un puntero al I-nodo del dispositivo. Si el dispositivo es el raíz o es un
dispositivo montado devuelve TRUE.
read_super lee el superbloque de un dispositivo. El superbloque no se lee en la caché. Se
hace una petición directa al dispositivo de lectura de 1024 bytes a partir de otros 1024 bytes
desde el principio. Read_super comprueba la version del SF y realiza las conversiones
pertinentes para traerselo a la tabla de superbloques con una estructura estándar.

15
Gestión de ficheros - Minix 3
Ejemplo llamada al sistema, “read” (1/3)

Proceso
read(df, &buffer, n)
usuario

send_rec(GF, &mensaje)
1) Mensaje para escribir un
bloque sucio que se ha elegido
send(proc_usr, &respuesta)
como víctima. (pueden
producirse varios o ninguno).
Gestor 2) Mensaje para traer un bloque
send_rec(Driver,&mensaje) Ficheros de disco a caché (pueden
producirse varios o ninguno)
send_rec(Driver,&mensaje) 3) Mensaje para copiar datos a
espacio de usuario (pueden
send_rec(TS,&mensaje) producirse varios)
1
--------------------------------------
3 Driver Disco puede referirse al
Driver driver de disco RAM, al de floppy
Disco Tarea o disco duro.
2
del
send(GF,&respuesta) Sistema
Driver
Disco send(GF, &respuesta)
send(GF,&respuesta)

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 16
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

Cuando un proceso de usuario ejecuta read (fd, buffer, nbytes) sobre un fichero ordinario,
la función de librería read construye un mensaje con estos tres parámetros junto con el
código read para el tipo de mensaje, envía el mensaje al GF y se bloquea esperando una
respuesta. Cuando el GF recibe el mensaje, usa el tipo como índice en la tabla de punteros
a procedimiento e invoca la función que trata la lectura (do_read). Esta función extrae el
descriptor de fichero del mensaje y lo usa para localizar la entrada filp y el I-nodo del fichero
a leer. La petición de bytes se divide en trozos que encajen en un bloque. Para cada trozo,
se comprueba si su bloque está en la caché. Si no está el GF selecciona el bloque (buffer)
menos re-cientemente usado que no esté en uso actual y lo reclama, enviando un mensaje
al driver de disco para escribirlo si estuviera sucio y pedirle al driver que obtenga el bloque
a leer (en el buffer seleccionado). Una vez que el bloque está en la caché, el GF envía un
mensaje a la Tarea de Sistema pidiéndole que copie los datos al lugar apropiado del
espacio de usuario, una vez copiados la TS responde con el nº de bytes copiados.
Cuando llega la respuesta al usuario, la funcion de librería read extrae el código de
respuesta y lo devuelve al llamador como valor de retorno de función.
Hay un paso extra que no forma parte de read. Después de que el GF complete la lectura y
envíe la respuesta, El GF inicia la lectura de bloques adicionales, siempre que la lectura
sea sobre un dispositivo de bloques y se cumplan algunas otras condiciones. Ya que la
lectura de ficheros secuencial es corriente, es razonable esperar que se pida el siguiente
bloque del fichero en la siguiente petición, y sería deseable que dicho bloque ya estuviera
en la caché. El número de bloques de lectura adelantada depende de la caché, pudiendo
ser de hasta 32 bloques. El driver no tiene porqué devolver tantos bloques y si devuelve
sólo uno se considera un éxito.

16
Gestión de ficheros - Minix 3
Ejemplo llamada al sistema, “read” (2/3)

Número de byte
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

bloque bloque bloque

Posición actual = 1

Trozo = 6

Posición actual = 6 Tres ejemplos de cómo se determina


el tamaño del primer trozo para un
Trozo = 2 fichero de 10 bytes. El tamaño del
bloque es de 8 bytes y la petición de
Posición actual = 9 lectura es de 6.

Trozo = 1

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 17
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

El núcleo principal del mecanismo de lectura (de un fichero ordinario) lo constituye un bucle que
descompone la petición en trozos, cada uno de los cuales encaja en la lectura de un único
bloque. Un trozo comienza en la posición actual y se extiende hasta que se alcanza alguna de las
siguientes condiciones: 1) Se han leido todos los bytes, 2) se ha encontrado el final de un bloque
y 3) se ha alcanzado el fin de fichero. Estas reglas implican que nunca se requiere más de un
bloque para leer un trozo. El procedimiento que efectúa la lectura de un trozo es rw_chunk.
Cuando esta función devuelve el control, se incrementan varios contadores y punteros y
comienza la siguiente iteración. Cuando finaliza el bucle se actualizan el puntero a la posicion
actual y otras variables (por ejemplo, apuntadores pipe).
Finalmente, si se ejecuta la lectura adelantada, el I-nodo y la posición desde la que leer se
almacenan en variables globales, tal que después de haber enviado la respuesta al usuario, el GF
puede empezar a leer el siguiente bloque. En muchos casos el GF se bloqueará, esperando al
siguiente bloque del disco, mientras tanto el proceso de usuario podrá ir trabajando con los datos
recien recibidos. Con este sistema es posible solapar el procesador con la E/S y con ello mejorar
substancial-mente el rendimiento.

17
Gestión de ficheros - Minix 3
Ejemplo llamada al sistema, “read” (3/3)
Puntos de entrada

do_read do_write

read_write Procedimiento principal de lectura escritura

dev_io pipe_check rw_chunck


Ficheros especiales

read_map rahead sys_copy put_block

Busca la Transfiere desde Devuelve


dirección el GF al usuario el bloque
rd_indir get_block a la caché
de disco
Obtiene dirección
de bloque indirecta
(si necesario) rw_block Busca en la caché

dev_io

rw_dev Listado en la tabla dmap

sendrec Envía mensaje al kernel

Aníbal Ramírez García - Sistemas Operativos II - Departamento de Informática Aplicada - Capítulo V. Pag. nº 18
Escuela Universitaria de Informática - Universidad Politécnica de Madrid.

18

Vous aimerez peut-être aussi