Resumen SO
Resumen SO
PARTES DE LA COMPU
ALU: unidad aritmética lógica, donde se realizan las operaciones.
REGISTROS: medios de almacenamiento de la CPU. Estos son acotados (de baja capacidad), no
persisten los datos que aloja (al igual que la RAM, y a diferencia de los medios de
almacenamiento secundarios, si la computadora se apaga estos se pierden) y, debido a su gran
velocidad, son donde se guarda la información inmediata a procesar por la CPU.
- De uso general: son aquellos utilizados para guardar datos que se han de procesar por
la CPU.
- De segmento: son utilizados por una estrategia particular de memoria ya que permiten
saber dónde está el comienzo y el fin de cada segmento.
- De control: guardan la información que proviene del BUS (que se ha de alojar en
memoria para ser utilizada)
- De uso específico como:
o IP (Instruction Pointer) / PC (Program Counter): indican la dirección de
memoria de la próxima instrucción a ejecutar. En un programa, lo esperado, es
que su ejecución sea secuencial por lo que cuando termina de ejecutarse cada
instrucción se incrementa en 1 el IP para que así (luego de validar si las
interrupciones están habilitadas, si hay interrupciones que se han de ejecutar
y ejecutarlas si las hay) se ejecute la siguiente instrucción.
o PSW (flags): hay múltiples flags y entre ellos están, por ejemplo, el flag del
overflow, el de zero y muchos más que indican el modo de ejecución de las
instrucciones (del programa en sí).
** Puede ser que se ejecuten secuencialmente, es decir, una tras otra. Sino puede que la
forma de ejecutar las interrupciones sea de forma anidada (por prioridades donde se guarda el
contexto de la interrupción que se estaba ejecutando, además del IP de la próxima instrucción,
y luego de ser ejecutada aquella con mayor prioridad se determina si se vuelve a ejecutar la
que se interrumpió).
MECANISMOS DE IO
Consiste en los formatos en los que se puede hacer una E/S, como leer algo de un disco rigido.
E/S programada:
Es un mecanismo en el cual el procesador se encarga de todo: leer los datos del módulo de IO,
consultar continuamente sobre el estado del módulo IO (es decir, verificar si los datos se
encuentran disponibles) y pasar byte a byte los datos a memoria. Si es una transferencia de
pocos bytes permite que haya poco overhead (tiempo desperdiciado por el procesador para
realizar un cambio de contexto) de procesos más complejos, pero, en caso contrario, hace un
mal uso de la CPU (esta podría estar ocuapada realizando y ejecutando instrucciones de mayor
prioridad).
Es otro tipo de mecanismo en el cual mantiene el hecho de que el procesador sigue leyendo
los datos del módulo de IO y pasándolos a memoria (sigue habiendo un mal uso de la CPU,
aunque en menor medida) pero no se encuentra continuamente verificando el estado del
módulo (si los datos se encuentran disponibles) sino que usa una interrupción para ello.
Entonces si no están los datos se ocupa de ejecutar instrucciones y en caso que estén una vez
ejecutada la instrucción con la que estaba (porque no se puede interrumpir el ciclo de una
instrucción) se ocupará de atender la interrupción.
Mecanismo en el que se incorpora otro componente que tiene permitido copiar la información
directamente a la memoria (el DMA) y que se encarga de todo (permite que la CPU se ocupe
de otras cosas de mayor importancia) con el inconveniente de que debe compartir el BUS con
la CPU para cargar los datos a memoria (genera que sea más lenta al robarle ciclos de CPU).
Involucrar a este otro componente hace que el set up también sea más lento pero que la
transferencia en su totalidad, generalmente, sea más eficaz. Sigue utilizando las interrupciones
para la verificación del estado, solo que cuando los datos estén disponibles no le avisa a la CPU
sino a este componente intermediario. La CPU es avisada cuando toda la transferencia sea
completada.
INTERRUPCIONES
Son alteraciones del flujo normal del programa (la CPU no interrumpe el ciclo de una
instrucción sino que para atenderlas, si es que están habilitadas, espera a que se ejecute la
instrucción)
PPT 2: Introducción a SO
¿QUÉ ES UN SISTEMA OPERATIVO?
Software que se encuentra en un medio de almacenamiento secundario y que posee permisos
particulares. Su objetivo es coordinar todos los componentes para que se ejecuten
correctamente y administrar los recursos bien.
- Aplicaciones de usuario.
- Aplicaciones utilitarias: no son de uso final pero son muy útiles.
- Bibliotecas
- Syscalls: mecanismos dados por el sistema operativo para pedir algunos de sus
servicios (funcionalidades del kernel que no pueden ser accedidas directamente). Para
hacer el cambio de privilegios hay que hacerlo:
o Mediante interrupciones (que requiere un previo acceso a memoria, antes de
ser atendido por el interrupt handler que ya es parte del sistema operativo).
o Mediante fast syscalls, es decir, instrucciones específicas (más rápido porque
no requiere de un acceso a memoria).
Existen wrappers (envoltorios) función que encapsula a más de una syscalls, consisten
en un conjunto de syscalls que es más fácil de usar (nos abstraen de ciertas
complejidades) y más portable (si cambia algo el wrapper se encargará de adaptarse)
- Kernel: núcleo, parte central (más bajo nivel) con funcionalidades básicas de sistema
operativo. Si bien existen varias arquitecturas de kernel, todas ellas incluyen: la
comunicación con el hardware, la creación de procesos y la comunicación entre ellos.
MODOS DE EJECUCIÓN
Consiste en que se debe tener un esquema (con el fin de tener una mayor protección) en el
que haya instrucciones más privilegiadas que otras y ciertos modos de ejecución que puedan o
no acceder a realizarlas (modo kernel posee todos los privilegios, modo user no)
Entonces para pasar de modo user a modo kernel se puede realizar a través de:
- Interrupciones
- Syscalls:
o Interrupciones
o Fast Syscalls
- Instrucciones privilegiadas
- Restaurando el contexto.
TIPOS DE KERNEL
Existen distintas arquitecturas entre las cuales esta:
Monolítico: todas las funcionalidades del sistema operativo se encuentran dentro del kernel
por lo que es rápido a nivel ejecución y excelente en cuanto a la comunicación entre
componentes. Sin embargo presenta ciertas desventajas en el diseño tales como la seguridad,
la estabilidad, el encontrar un error ya que esta todo en modo kernel, entre ellas. Es el usado
hoy en día.
Multi-Capa: teórico.
- PCB (Process Control Block): estructura que posee el sistema operativo con toda la
información del proceso para administrarlo. Siempre se encuentra en memoria a
diferencia de los demás componentes que puede que no lo estén.
- Stack: pila (estructura LIFO) que contiene las variables locales (los parámetros) de las
funciones utilizadas.
- Heap: memoria dinámica que se le pide al sistema operativo y que se tiene
responsabilidad de liberar una vez ya utilizada
Tanto el Stack como el Heap son dos estructuras cuyo tamaño no es fijo, sino que va variando.
Nuevo: ya existe la abstracción del proceso pero eso no quiere decir que todos los
componentes estén en memoria (el PCB es el único que podemos asegurar que sí). Los
procesos en nuevo competirán por ser admitidos en el sistema (pasar a un estado
Listo).
Listo: el proceso es admitido en el sistema, todos sus componentes pasan a estar en
memoria y se lo deja listo para ser ejecutado. Así como en nuevo los procesos
compiten por pasar a un estado listo, los procesos en listo compiten por estar en
ejecución.
En ejecución: se ejecutan las instrucciones del proceso en cuestión.
Pasa a estar Finalizado cuando ejecuta toda sus instrucciones, para ello previamente se
deben liberar todos los recursos posibles (como el heap que es memoria dinámica
pedida al sistema operativo).
Pasa a estar en una cola En Espera (donde se referencia al PCB del proceso) debido a
que debe esperar a que un evento ocurra o que se realice una IO. Cuando ocurre el
evento o la IO finaliza el proceso pasa a estar nuevamente en Listo.
Pasa a estar En Listo debido a que desalojo voluntariamente o debido a que fue
interrumpido por el SO.
CAMBIO DE CONTEXTO
Un cambio de contexto de un proceso conlleva guardar el contexto de ejecución para luego
reanudarlo en el lugar donde fue interrumpido (el tiempo que comprende el cambio de
contexto es considerado overhead y debe minimizarse). Si dicha interrupción es temporal, el
contexto de ejecución se guarda en el stack (que conlleva un menor costo) pero si es más
permanente (por ejemplo si luego de la interrupción se comienza a ejecutar otro proceso) esta
se debe guardar en el PCB.
- Una interrupción.
- Una syscall.
- La ejecución de otro proceso.
PCB
Posee:
CREACIÓN DE PROCESOS
Se realiza a través de una syscall llamada fork que devuelve un valor (que se almacena en el
stack) que debe ser validado (ya que esta puede fallar): en caso que sea 0 es el proceso hijo, en
caso que sea un valor positivo es el proceso padre.
El espacio de direccionamiento del proceso hijo a través de la syscall fork puede ser una copia
exacta a la del proceso padre o puede ser una imagen completamente nueva pasada por
parámetro. De todas formas a ambos procesos, en su ejecución, se los diferencia por su PID
(Process ID) siendo el del padre menor al del hijo.
FINALIZACIÓN DE PROCESOS
Los procesos, si desean finalizar deben hacer una syscall llamada exit que, en caso que tengan
un proceso padre le informará que fue finalizado con un wait y sus recursos serán liberados.
En caso que un proceso desee finalizar y tenga procesos hijos, según el sistema operativo
estos:
- Finalizan en cascada
- Pueden ser asignados al padre de su padre (abuelo) y seguir ejecutándose.
Sin embargo, existen procesos que son cooperativos y tienen un fin en común. Para lograrlo
comparten recursos ya sea:
- Con un paso de mensajes lo cual es performante si los datos que deben de compartir
son pocos, pero dicho traspaso es muy lento
- Con memoria compartida (establecen una zona de memoria compartida por la cual
pueden comunicarse y compartir datos) lo cual es muy rápido pero puede generar
problemas si desean usar un recurso compartido al mismo tiempo o si se genera una
condición de carrera.
CONCEPTO HILOS
Es la minima unidad de planificación
Comparten datos, código y heap con otros hilos (por lo que no hay protección entre
ellos, un hilo puede escribirle a otro en el espacio de memoria compartida pero no
necesita mecanismos para inter-comunicación entre ellos)
Cada hilo es administrado por un TCB (“PCB en hilos”) y tiene su propio sector de stack
VENTAJAS
➔ Permiten paralelismo dentro de un proceso o aplicación.
➔ Permiten la comunicación privada entre varios hilos del mismo proceso, sin solicitar
intervención del S.O. (es más rápida)
DESVENTAJAS
➔ Cuando un Proceso “muere” todos sus Hilos también, pues los recursos de Proceso son
tomados por el Sistema Operativo.
KLTs VS ULTs
KLT:
ULT:
● El SO “no los ve”, sino que son administrados por una biblioteca en nivel de usuario
● El cambio entre ULTs (del mismo KLT) es más rápido (no interviene SO)
SWAPPING
Permite aprovechar mejor la RAM (al quitarle procesos hay más espacio para otros procesos) y
un mejor uso de la CPU
CONCEPTOS Y CLASIFICACIÓN
El planificador tiene como objetivo asignar procesos para ser ejecutados de tal forma que se
cumplan los objetivos del sistema
SJF
Sin desalojo
Algoritmo sin desalojo que atiende a los procesos en base a cuál de ellos posee menor ráfaga
de CPU y ante un empate el orden de llegada desempata. Esto genera que se tenga en cuenta
el hecho de que no haya mucho tiempo de espera pero permite que en principio se pueda
generar starvation. Starvation, también conocido como inanición, consiste en negarle
continuamente los recursos a un proceso, lo cual puede surgir si continuamente se agregan
procesos de ráfagas más cortas que el proceso en cuestión este será continuamente aplazado
al darle prioridad a los otros. También, al igual que en FIFO, al ser sin desalojo puede generarse
que un proceso monopolice la CPU.
CS MS
CS MS => IO y FIN de IO
CS MS => FIN DE Q
Cuanto menor sea el alfa más tiende a priorizar la historia general de ejecución (la estimación)
y no tanto las ráfagas reales más recientes. Por lo tanto las estimaciones tardan en adaptarse a
los nuevos tamaños de ráfagas. Mientras que con un alfa más grande la adaptación se produce
más rápido.
HRRN
Es un algoritmo en el que se tiene en cuenta el tiempo que se encuentra en espera cada
proceso y, además prioriza según las ráfagas de CPU. Es sin desalojo siempre porque sino
cambiaría continuamente el Response Ratio (RR) calculado y generaría mucho overhead (más
del que ya hace) al cambiar continuamente de procesos y hacer muchos cambios de contexto.
RR (Round Robin)
Algoritmo que desaloja los procesos según un Q (quantum) predeterminado, replanificando
únicamente si estos liberan la CPU voluntariamente o si se termina el quantum.
Si el quantum es pequeño puede generar mucho overhead (mucho context swich) pero si es
muy grande puede generar que un proceso monopolice la CPU. Este permite, con un quantum
moderado, que todos los procesos terminen ejecutándose (todos juntos, “a la par, no
literalmente”).
VRR
Algoritmo con desalojo en donde hay dos colas (con distinto quantum) permitiéndole dar
prioridad a los procesos con ráfaga más corta.
COLAS MULTINIVEL
En vez de tener una sola cola ready, tener varias a las que los procesos los vamos asignando a
las distintas colas según su prioridad. Para ello hay que identificar los tipos de procesos.
Cada cola tiene su algoritmo de planificación pero por fuera se realiza una meta planificación
con un algoritmo con desalojo por prioridades.
El mismo Ult? Sigue el Ult que se estaba planificando antes, la biblioteca no puede
replanificar
Un wrapper de la biblioteca => el Ult que, según el algoritmo de la biblioteca, tenga
que ejecutarse.
Al bloquearse un ULT se bloquea todo el KLT o Proceso asociado. Para que esto no ocurra no se
debería contar al SO que estamos bloqueados => Jacketing (mientras que un ULT pueda
ejecutar que lo haga).
PPT 7: Sincronización
DEFINICIÓN CONDICIÓN DE CARRERA
Situación en la que se encuentran aquellos procesos / hilos que manipulan de forma
concurrente datos compartidos de tal forma que el resultado de la ejecución depende de un
orden en particular en que se ejecutan.
- Procesos independientes: que no afectan ni deben ser afectados por los demás por lo
que no pueden llegar a estar en condición de carrera.
- Procesos cooperativos: que poseen un fin en común y para ello pueden comunicarse
de dos formas:
o Paso de mensajes: a través de syscalls lo cual es bastante lento pero impide
que pueda ocurrir estar en condición de carrera.
o Mediante memoria compartida: puede generar que los procesos estén en
condición de carrera si se manipulan los datos de forma concurrente y al
menos uno los escribe (modifica)
- Procesos competitivos: no tienen un objetivo en común pero si un sector de memoria
compartida que genera que puedan estar en condición de carrera.
A nivel HW:
- Deshabilitar las interrupciones: debido al hecho de que para que ocurra una condición
de carrera debe pasar un cambio de hilo/proceso (generado por una interrupción)
definido por el planificador. Esta solución a bajo nivel en general es usada en entornos
de un procesador debido a su simplicidad (uno deshabilita las interrupciones, ejecuta
la sección critica, y luego las habilita). Pero en entornos de multiprocesador no se
aplica debido a que:
o En primer lugar es muy costoso enviarle a cada CPU una señal para que se
deshabiliten las interrupciones (el proceso tarda más en ingresar a la SC
debido hay que esperar que todas las CPU las deshabiliten) y luego habilitarlas.
o Generaría un retardo al no poder atender interrupciones y si una es de gran
importancia (no enmascarable) no se podría atender.
- Instrucciones atómicas (Test and Set): se ejecuta la instrucción como una unidad
(atómica) utilizando espera activa. Es por esto que son eficientes también en entornos
de multiprocesador y sencillas de usar pero no todos los sistemas tienen este soporte.
A nivel SO:
- Semáforos: son variables enteras que únicamente pueden ser utilizadas mediante dos
funciones atómicas (dos syscalls): wait y signal. Existen distintos tipos de semáforos
tales como los:
o Binarios: permiten que haya dos estados (ocupado 0 o disponible 1).
o Contadores: permiten que únicamente se pueda acceder a cierta cantidad de
instancias de un recurso.
o Mutex: permiten la mutua-exclusión. Siempre se inicializan en 1.
Hay que recalcar que a veces los semáforos pueden causar una inversión de
prioridades si el algoritmo utilizado por el planificador de corto plazo es por
prioridades (lo cual es un problema). Esto significa que un proceso P3 con mayor
prioridad que otro P2 no pueda ejecutar (se encuentre bloqueado) debido a que otro
proceso P1 desalojado previamente porque llego otro proceso con mayor prioridad P3
le bloquea algún recurso compartido que requiere y por lo tanto P2 teniendo menor
prioridad ejecute primero. Para resolver esta situación existe la herencia de
prioridades, en este caso P1 cuando P3 requiere el recurso compartido hereda la
prioridad de dicho proceso P3 termina de ejecutar (liberando dicho recurso) apra que
así el recurso con mayor prioridad ejecute antes que el otro con menor prioridad P2.
- Monitores: mecanismo que provee mutua exclusión al ser el único punto de acceso a
un recurso compartido (en vez de acceder directamente a la variable se accede a
través del monitor asegurando y abstrayendo la lógica de la sincronización). El monitor
va a tener en forma interna ese recurso compartido y expone de forma publica una
interfaz de lo que se pueda hacer sobre dicho recurso. De esta forma nos aseguramos
de que cada una de las funciones que afectan a la sección critica, estarán sincronizadas
en sí.
SEMÁFOROS IMPLEMENTACIÓN
Un semáforo es una variable entera que es accedida únicamente a través de 2 syscalls (2
funciones atómicas).
Esta solución se puede implementar con o sin espera activa (con bloqueo en caso que no).
1. Debido a que usar los semáforos con bloqueo genera que haya muchos cambios de
contexto (más overhead) y ahorra el bloqueo/desbloqueo
2. Si hay más de una CPU
3. Cuando la sección crítica es muy chica y el tiempo que se espera en el while es más
corto.
TIPOS DE SEMÁFOROS
Mutex: permiten garantizar la mutua exlusión, se los inicializa siempre en 1.
Binarios: permiten garantizar cierto orden de ejecución (tienen dos estados únicamente: libre
u ocupado)
USOS DE SEMÁFOROS
- Mutua exclusión
- Ordenar una ejecución
- Limitar el acceso a cierta cantidad de instancias
- Producto-consumidor (donde un proceso consume y otro genera recursos)
PPT 8: Deadlock
RECURSOS DEL SISTEMA
Los sistemas poseen recursos limitados. Estos pueden ser:
- Recursos consumibles: una vez usados no pueden ser devueltos al SO una vez pedidos.
Por ejemplo: interrupción, señal, mensaje, info en IO buffers
- Recursos reusables: algo que le puedo pedir al sistema, que mediante una syscall lo da
(me los asigna), y luego lo puedo devolver una vez usados. Por ejemplo: Memoria,
archivos, dispositivos IO.
Los procesos para utilizar los recursos deben pedirlos y luego liberarlos a través de llamadas al
sistema:
Los recursos pueden tener más de una instancia (cualquiera satisface a un proceso por igual).
Esto quiere decir que entre recursos lo que importa es cuál es cuál, pero entre instancias
importa la cantidad.
DEFINICIÓN DEADLOCK
Situación en la que los procesos / hilos se encuentran en interbloqueo esperando que suceda
un evento producto de la actividad de otro de los procesos en cuestión (que también está
bloqueado).
CONDICIONES NECESARIAS
Para que haya deadlock se deben cumplir todas estas condiciones:
TRATAMIENTO DE DEADLOCK
El deadlock puede tratarse de multiples maneras entre las cuales se encuentran:
o Espera y retención
Los procesos pidan y se le asignen previamente todos los recursos que
vaya a usar.
Un proceso para pedir un nuevo recurso tenga que liberar todos los
que retiene (ineficaz)
o Sin desalojo
Si un proceso pide un recurso que no está disponible, debe esperar y
se liberan todos los recursos que tenía asignados.
Si un proceso pide un recurso retenido por otro proceso en espera, los
mismos son desalojados y asignados al primero (si un recurso que
necesito lo está usando otro que está bloqueado, se lo saco)
Estas estrategias de prevención para un sistema de uso normal (con múltiples procesos) no son
las más utilizados ya que la experiencia del usuario sería mala. Para ellos se utiliza más las
estrategias de evasión y detección. Sin embargo, Para un sistema cerrado en que se sabe que
cosas se deben hacer, en qué orden y que se necesita se utiliza la estrategia de prevención.
EVASIÓN
Asignación de los recursos en cuestión.
- El proceso debe indicarle al SO cuáles van a ser los recursos máximos que puede llegar
a solicitar durante su tiempo de vida.
- Ante cada solicitud, se analizará si se le asigna el recurso al proceso o si se lo hace
esperar. Para tomar una decisión se realiza una simulación (se utiliza el algoritmo del
banquero) teniendo en cuenta las posibles futuras solicitudes y liberaciones de
recursos por parte de todos los procesos del sistema.
- Mantiene al sistema siempre en Estado Seguro
o Un estado es seguro si el sistema puede asignar recursos a cada proceso (hasta
su máximo) en determinado orden sin que eso produzca un deadlock (existe
una secuencia segura). Con que haya una secuencia segura es suficiente
o Si el estado es seguro → no existe ni existirá deadlock
o Si el estado es inseguro → podría ocurrir deadlock
- Sólo se asigna un recurso si dicha asignación deja al sistema en estado seguro.
- Se podría utilizar un grafo de asignación de recursos para analizar el estado del sistema
Estructuras necesarias:
Ante cada solicitud se debe simular la asignación, actualizando las estructuras adecuadas, y
luego analizar si existe una secuencia segura.
DETECCIÓN
Supone un costo y se debe determinar la frecuencia en la que se verifica si el sistema se
encuentra en un estado seguro (con las matrices del algoritmo del banquero menos las
peticiones máximas)
LIVELOCK
Es una situación similar al deadlock en la cual un conjunto de procesos no puede progresar en
la ejecución de su trabajo pero, en este caso, los procesos siguen ejecutándose lo cual es más
difícil de detectar.
Esta tiene un espacio reservado para el sistema operativo (kernel space) y otro espacio para
distribuir los procesos de usuario (user space). Se tiene un espacio reservado para el sistema
operativo debido a que al saber que cosas va a estar utilizando le conviene utilizar otra
estrategia (de como guardar esa información y administrar dicha porción de memoria)
respecto a lo que usa para los procesos (que al ser más general no sabe que es lo que van a
necesitar).
RAM: es donde en general se cargan los procesos para poder ser ejecutados.
¿En qué momento se pueden definir las direcciones? Es decir, ¿En qué momento se mapean
las direcciones simbólicas y pasan a ser representadas por direcciones absolutas?
Direcciones lógicas (DL): son aquellas que cuando uno va ejecutando se trata de acceder.
ASIGNACIÓN CONTIGUA
Consiste en que toda la imagen del proceso debe de encontrarse junta en memoria, de forma
contigua.
PARTICIÓNES FÍJAS
Estrategia de memoria en la que la imagen del proceso se encuentra toda contigua en
memoria. La memoria se encuentra dividida en N particiones fijas de X tamaño y cada proceso
que se desea ejecutar se aloje en una de dichas particiones. El que haya N particiones fijas
hace que el máximo grado de multiprogramación sea de N (porque no podrán haber más de N
procesos en memoria) y que dichas particiones tengan un tamaño fijo hace que se limite el
tamaño que pueden tener los procesos (no pueden excederse de ese X tamaño). Además, los
procesos rara vez tendrán el mismo tamaño que las particiones por lo que seguramente se
generará un espacio que la memoria no aprovechará (no puede ser asignado a otro proceso),
es decir, habrá fragmentación interna.
Por otra parte, los procesos serán muy fáciles de manipular y encontrar ya que únicamente se
debe saber cuál es el tamaño de todas las particiones y en que partición se encuentra el
proceso (información que se guarda en el PCB del mismo).
PARTICIONES DINÁMICAS
Estrategia de memoria en la que la imagen del proceso se encuentra toda contigua en
memoria pero que, a diferencia de particiones fijas, la memoria no se encuentra dividida en
particiones sino que el proceso se cargará en memoria tal cual el tamaño que tenga. Esto hace
que no se limite ni el grado de multiprogramación ni el tamaño de los procesos (obviamente
que el espacio en memoria es limitante pero en si la estrategia de memoria no lo limita). Al
cargar todo el proceso con su tamaño (lo cual no es fijo porque no todos los procesos poseen
el mismo tamaño) hace que estos sean más complejos de manipular ya que ahora no se
requerirá únicamente de la base en la que se encuentra el proceso sino saber su tamaño para
ver si las direcciones de memoria a las que se pretenden acceder son válidas para él. Por otro
lado, si bien no habrá fragmentación interna, al ir cargando y finalizando procesos
seguramente queden huecos entre ellos que ninguno podrá aprovechar, es decir, habrá
memoria desperdiciada lo cual se denomina fragmentación externa. De vez en cuando, sin
abusarse porque es alto el costo, se puede ir compactando los procesos de tal forma que los
espacios libres en memoria queden todos juntos en un mismo lugar.
COMPACTACIÓN
ELECCIÓN DE DONDE ASIGNAR EL PROCESO
En cuanto a la elección de donde asignar el proceso esta se puede hacer:
PAGINACIÓN
Estrategia de memoria donde la imagen del proceso ya no se debe de cargar de manera
contigua sino que puede dividirse. Esta consiste en dividir la memoria en frames (marcos) de
igual tamaño (que para administrar que está libre y que no se puede tener un vector de bits,
un bitmap de los marcos libres) y al proceso que se desea cargar en páginas de igual tamaño a
los frames. De esta forma, al igual que particiones fijas, habrá fragmentación interna pero en
menor medida ya que solo habrá fragmentación interna en la última página del proceso.
Obviamente dependiendo del tamaño de la página se tendrá mayor o menor fragmentación
interna (cuanto más chica menos y cuanto más grande más). Si son más chicas las páginas los
procesos van a tener más páginas por lo que las estructuras para administrarlas van a ser más
grandes por lo que...
- Que las páginas sean chicas sería una ventaja en cuanto a la fragmentación interna
pero una desventaja en cuanto a la administración de éstas (es más costoso).
- Lo contrario para las páginas grandes (administrarlas va a ser más sencillo debido a
que son menos pero potencialmente va a tener más fragmentación interna con la
limitación de que es solo la última página).
El costo de esta mejora es que el acceso a una dirección dentro de un proceso (pasar de una
DL a una DF) es más complejo (la traducción no será tan lineal):
Cuando se tiene particiones fijas, no se necesitaba la base sino que con saber el número de
partición se podía calcular (porque todos poseen el mismo tamaño). Para paginación es lo
mismo, no se requiere saber la base de cada página sino que con saber en qué marco está ya
se puede calcular la dirección de la base (se multiplica el número de marco por el tamaño de la
página que es igual al del marco). Sin embargo para esto se requiere de una tabla de páginas
(estructura que estará en una sección separada al proceso debido a que la primera va a ser una
estructura del SO) por cada proceso (cuya dirección en memoria será guardada en el PCB
inicialmente pero una vez creado el proceso y al querer cargar una DL, el puntero se trasladará
a los registros para que esté más al alcance) en dónde el índice sea el número de páginas y
cada página tenga asignada el frame correspondiente.
Por lo que para acceder a una página determinada en memoria se deben realizar 2 accesos a
memoria (1 al PCB y otra a la tabla de páginas) lo cual es más lento que en las otras estrategias.
Es por esto que para mejorar este tiempo se puede utilizar una caché (estructura extra a nivel
de HW que posee un espacio limitado) llamada TLB (Translation Look-aside Buffer) que
permite que el acceso a las páginas sea más rápido. La TLB es una memoria asociativa de alta
velocidad (caché HW) dónde se guardan las entradas de la tabla de páginas para agilizar el
proceso de traducción y el acceso efectivo a memoria. Puede, además, guardar en cada
entrada un identificador del proceso por protección de otros procesos y para no tener que
vaciar la caché al cambiar de proceso.
Por otro lado, en paginación compartir memoria, a diferencia de particiones fijas, es sencillo.
¿Por qué? Porque básicamente lo que se necesita que compartan es un frame. Entonces lo
único que se requiere es que a nivel traducciones (mapeo de tablas de páginas) dos páginas de
diferentes procesos apunten al mismo frame.
Entonces, si se requiere acceder a una dirección (que va a ser una DL) se debe interpretar la
página en la que está incluida y el desplazamiento dentro de esta misma (es decir, el offset). Y
una vez que se obtenga eso, con la página acceder a la tabla y recuperar el número de frame
para así calcular la base (con el tamaño de la página*frame) y con el desplazamiento la
dirección física dentro de la RAM.
Por último, si bien en paginación no se pretende limitar el tamaño de los procesos al ser las
tablas de páginas fijas y contiguas en memoria, limitan al proceso y quizás, si este es muy
grande, le impiden direccionar idealmente todo en la memoria. Es por esto que se realiza una
paginación jerárquica (lo cual complejiza aún más la estrategia), es decir, se pagína la tabla de
páginas.
Hay una tabla para todo el sistema (en lugar de una tabla por proceso) que está indexada por
marco en lugar de por página (hay tantas entradas como marcos en la memoria física). Es
decir, que el input (el índice) antes era el número de página y el output (el contenido) era el
frame en el que se carga y ahora es al revés.
El problema es que al cambiar el punto de acceso, nuestro dato sigue siendo el número de
página (cuando se accede a una dirección lógica lo que se obtiene de ella es el número de
página al que se está accediendo). Para solucionarlo lo que se hace en la tabla de páginas
invertida es buscar uno por uno la página, por lo que si bien ocupa menos espacio, el acceso no
es directo (es una búsqueda lineal). Por cada uno de los accesos se debería ir recorriendo
secuencialmente todas las entradas de la tabla (frames) para poder encontrar donde está.
SEGMENTACIÓN PAGINADA
Se divide la RAM en frames y a la imagen de los procesos en segmentos (es decir, está dividida
lógicamente) que se encuentran paginados lo cual hace que únicamente haya fragmentación
interna (un poco más que en paginación porque no es en la última página de la imagen total
sino en la última página de cada segmento del proceso). Además permite que cada segmento
pueda tener permisos distintos (R, W, X). Sin embargo, su administración es mucho más
compleja.
Define el tamaño de partición a asignar dinámicamente pero con ciertos tamaños posibles
(potencia de 2):
Cada vez que se divide en dos a un bloque para realizar la búsqueda los dos nuevos bloques
producto de la división serán buddies. Dos bloques A y B son buddies si:
Al liberar un bloque, hay que chequear si su buddy está libre. En caso afirmativo, ambos
bloques se consolidan en uno y luego se vuelve a chequear por su buddy (y así hasta que no
pueda hacerse o hasta que se consolidó toda la memoria). Una liberación puede generar 0 o
varias consolidaciones -> no es determinístico
Un bloque se encuentra compuesto por un header donde está toda su información (si está
libre y su tamaño, que al ser todos potencia de dos solo necesita tener guardado el exponente)
y los datos por otro lado.
Es en el header donde se debe de mirar para ver verificar si un proceso es buddy de otro y si
ambos están libres, es decir, para realizar la consolidación.
Hay distintas estructuras que se pueden utilizar para realizar este esquema (técnica):
- Árboles binarios
- Listas de particiones libres de tamaño X
- Bitmap de bloques de orden i
VENTAJAS:
DESVENTAJAS:
1. Nos limita el tamaño máximo de los procesos. Si se tiene procesos grandes no podrían
entrar.
2. Limita también el grado de multiprogramación: si se debe cargar a los procesos
enteros (de new a ready por ejemplo) no se podrán cargar muchos.
OVERLAYING
Dentro de las primeras soluciones está el overlaying que consiste en dividir el programa en
partecitas definidas por el programador (analogía con segmentación). Había algunas partes
que debían estar si o si en RAM como el overlay driver (que administra las partecitas en las que
se lo divide) y la sección principal del proceso. Y otras partes, los overlays seccions, se iban
swicheando.
Esta solución no es a nivel SO sino que es a nivel programación: se optimiza la cantidad de
RAM que se utiliza definiendo ciertas partes del proceso (programa) que se determina cuando
se desean cargar y descargar.
Sin embargo, lo que se buscaba era una solución a nivel SO: manejar este problema de alguna
manera más transparente para el programador, es decir, que este no tenga que definir que
cargar y que no en la RAM. Sino que se le engaña al proceso haciendo que tiene todo el
espacio en memoria que requiere y por atrás el SO maneje que está en RAM y que no.
MEMORIA VIRTUAL
- Todo lo que es memoria virtual se realizará con paginación: es más cómodo para poder
swippear el tener todo dividido en páginas que hacerlo de otra forma (como por
ejemplo con particiones dinámicas que es mucho más complejo para definir que se
trae y que no de disco).
- La idea es: en la tabla de páginas además de tener un bit de validez se tiene un bit de
presencia. En caso de que la página sea válida y esté en la RAM que el bit de presencia
(que indica si la página está en la RAM) dirá en que frame está.
- Las instrucciones que se deben ejecutar tienen que estar en RAM
Tiene como ventaja el hecho de que el tiempo de carga de los procesos disminuye, es mucho
más rápido ya que cuando un proceso se encuentra en ready no se debe de esperar a que
cargue todo sino que cuando comienza a ejecutar se van cargando las páginas necesarias y
arranca.
Como desventaja cada vez que se quiera acceder a páginas que están en swap ese acceso va a
ser más lento, el proceso va a tener que esperar a que esta página se cargue de swap a RAM.
PROCESO DE TRADUCCIÓN DE UNA DL A UNA DF
Esta se la busca en la TLB. Si acierta (se hace HIT) se obtiene la dirección física.
En caso que no acierte se la busca en la tabla de páginas (RAM). Si la página está en la TP (el bit
de presencia es 1), se carga la página en la TLB y se obtiene la dirección física de esta misma.
En caso que no esté en la TP (bit de presencia = 0) se lanza una interrupción PAGE FAULT (que
es bloqueante, es decir, el proceso va a quedar bloqueado hasta que lo resuelva) que genera
un mode switch haciéndose cargo el SO. Se atiende la interrupción y se comprueba si la
dirección es válida o inválida para dicho proceso -> ¿Está dentro del espacio de direcciones del
mismo?
➔ Sustitución de frames (se quiere sustituir dentro de los frames asignados al proceso
en cuestión o no)
◆ Local -> las víctimas a elegir deben estar dentro del conjunto de frames
asignados al proceso
◆ Global -> se puede elegir como víctima cualquier frame (puede ser de otro
proceso)
GLOBAL-FIJA: No se puede garantizar una asignación fija si se tiene una sustitución global. Si
desde un principio el SO determina que un proceso tiene una asignación fija de 10 frames, si
otro proceso viene y me quita uno, ya no estaría teniendo esos 10 frames.
THRASHING/SOBREPAGINACIÓN
Todo proceso utiliza un conjunto de páginas activamente durante un lapso de tiempo y
necesita que las mismas estén cargadas, al mismo tiempo, en memoria durante dicho lapso.
Entonces necesita un mínimo e indispensable número de frames que el SO le debe de asignar.
En un sistema donde el grado de multiprogramación es bajo por lo que el nivel de uso de CPU
también lo es, el aumento de la multiprogramación está bien implementado siempre y cuando
también tenga en consideración la cantidad de page faults (el rate) que comience a tener al
poner más procesos en memoria. Esto es así ya que si no se tiene en cuenta esto puede
generar que los procesos en cuestión no tengan la cantidad de frames que requiere para
ejecutar.
o Matando procesos.
o Suspendiendo de forma total a los procesos (que estén totalmente cargados
en memoria).
- ¿Cómo se puede prevenir o atacar lo antes posible?
Para ello se debe aproximar viendo "hacia atras" las últimas n referencias que se hicieron. Es
decir, se debe definir el tamaño de la ventana en la que se mira para atrás (cantidad de
referencias que se deben tener en cuenta). Si se aproxima muy seguido se genera mucho
overhead pero si se hace cada poco tiempo existe la posibilidad de que los procesos se dejen
mucho tiempo bloqueados o en thrashing.
ANOMALÍA DE BELAMY
Consiste en desmentir la creencia que cuantos más frames tenga un proceso menos page
faults generará. Algunos algoritmos ante determinadas secuencias de referencias al aumentar
el número de frames sin embargo incrementan la frecuencia de PFs. Por ejemplo: en el
algoritmo FIFO se da la anomalía de que a pesar de tener más frames asignados, ante la misma
cadena de referencia de páginas podes tener más Page faults que con menos frames
asignados. Es decir, la creencia de que si uno le da más recursos a un proceso se comportará
mejor en FIFO puede llegar a ser mentira.
FIFO
Elige como víctima a la página que está cargada en memoria hace más tiempo
Se puede implementar:
- Guardando el instante en el que la página fue cargada -> se elige la que tiene el menor
valor
- Cola FIFO -> se elige la página que primero se agregó a la misma
ÓPTIMO
Elige como víctima a la página que no vaya a ser referenciada por un mayor período de tiempo
Se utiliza a fines comparativos -> se puede saber cuántos más PFs genera otro algoritmo
comparado al Óptimo
LRU
Elige como víctima a la página menos recientemente utilizada (hace más tiempo que no se
referencia) -> utiliza el pasado reciente como una aproximación del futuro
Se puede implementar:
- Guardando el instante de última referencia de cada página -> se elige al que tiene el
menor valor
- Pila con números de págs -> con cada referencia se coloca la pág superior, se elige
como víctima la pág de la parte inferior
CLOCK
Está basado en FIFO, con un bit de referencia (Bit de Uso) trata de aproximar el algoritmo LRU
CLOCK MODIFICADO
Tiene en cuenta además del bit de Uso, al bit de Modificado
Teniendo al par (U , M)
PAGE BUFFERING
Se mantiene un pool de frames libres que se utilizarán como buffer para que la operación de
escritura en swap (del proceso que se pretende sustituir) y la operación de lectura de la nueva
página (que se pretende poner en el frame que ocupaba la página modificada) se hagan en
paralelo.
Si bien se tienen que dejar algunos frames libres para formar este pool de frames buffers, en
vez de darle unos frames más al proceso u otros procesos (lo cual es una pequeña pérdida),
permite optimizar esas operaciones de disco (gran ganancia) cada vez que haya un PF y la
víctima que hay que sustituir esté modificada.
LOCKEO DE PÁGINAS
Al iniciar la IO se puede permitir habilitar un bit lockeo sobre el frame para que no pueda ser
reemplazado durante la operación.
Al finalizar la misma, el frame dejará de estar lockeado y podrá ser elegido como víctima de
sustitución nuevamente
Es decir, al hacerse una IO, el SO antes de decirle al DMA "hace esto" lockea la/s página/s en
donde se va a hacer una E/S. Una vez que termine esa E/S, cuando maneje la interrupción, va a
deslockearla y será nuevamente una página que pueda estar dentro del scope de víctimas.
PPT 12 FYLESYSTEM
¿QUÉ ES?
Es una parte del sistema operativo que podía ser que esté dentro del kernel o no
(dependiendo el tipo de kernel) y está relacionado a dar servicio del uso de archivos. La utiliza
tanto el usuario final como también las aplicaciones utilitarias como el mismo SO para guardar
información.
OBJETIVOS
- Almacenar datos y poder operar con ellos.
Este también es quien decide el formato de los archivos, no al reves. Pero si uno
formatea dicho medio de almacenamiento (una memoria flash o un disco rigido por
ejemplo) con un formato en particular obviamente no lo va a poder interpretar.
Dependiendo del criterio del filesystem, el espacio de almacenamiento se divide
logicamente y lo administra de cierta forma.
- Garantizar (en lo posible) la integridad de los datos: para poder administrar el archivo
habrá muchas estructuras administrativas, entonces... ¿En qué estado quedan dichas
estructuras si hay alguna falla de algún dispositivo por ejemplo?
Apuntado a la consistencia, si están accediendo varios al mismo archivo.
- Optimizar desempeño
o Usuarios -> tiempo de respuesta
o Sistema -> aprovechamiento de los recursos
La idea es que se pueda dar la interfaz de que se desea hacer sobre un archivo (crearlo,
escribir, leer, eliminarlo) sin importar el medio de almacenamiento (si es una memoria
flash, un disco rígido o en estado sólido) el filesystem debería funcionar en cualquiera.
Lo que si se verá es que quizás el filesystem realiza una optimización pensada para un
determinado almacenamiento pero esto no quiere decir que no se pueda utilizar en
otro tipo de almacenamiento.
¿Qué API/syscalls se van a poder hacer para operar sobre los archivos?
- Soporte para múltiples usuarios -> ¿qué puede hacer un usuario con los archivos de
otro?
ARCHIVO
¿QUÉ ES?
Conjunto de datos /registros relacionados etiquetados con un nombre y almacenados en un
medio secundario. Es decir, datos que pueden estar almacenados en forma dispersa en disco
pero están relacionados. En si el nombre del archivo no es un atributo de él pero si tendrá un
identificador para el SO (filesystem).
- Existencia de larga duración (tiene durabilidad): uno podría crear un archivo temporal
en memoria pero por lo general cuando se crean se desea que se almacene de forma
durable.
- Compartible entre procesos -> archivo = nombre + permisos asociados: al querer
compartir archivos (para acceder a ellos) se debe conocer su nombre (el path, es decir,
la ubicación en toda la estructura del directorio) y tener un permiso para poder
acceder.
- Estructura -> FCB
¿CÓMO SE ADMINISTRA?
FCB (File Control Block): estructura que utiliza el SO para administrar el archivo (parecido al
PCB en procesos). Cada archivo tendrá un FCB.
Es una estructura que se desea tener a mano (en memoria) que cambia respecto al PCB debido
a que...
… el PCB (que siempre está en RAM) dura hasta que el proceso finalice (dicha
estructura no tiene más utilidad por lo que se libera y en todo caso se utilizará dicho
espacio para otro proceso). Por otro lado, en el caso del filesystem estos archivos
tienen existencia durable (por más que se apague la compu por ejemplo, seguirán
existiendo) lo que nos da una pauta de que el FCB tiene que existir en disco.
Contiene:
- File permissions
También se podría encontrar como time stamps. Está relacionado a cuándo fue la última
vez que se hizo un acceso en particular (Se escribió, se leyó, etc.)
- File size
DIRECTORIO
Es un archivo que contiene un listado de nombres de otros archivos (que también podrían ser
directorios) y sus atributos asociados.
Uno por lo general identifica a un archivo por su nombre pero en realidad no es parte del
contenido ni identificación de ese archivo en sí. ¿Por qué? Porque hay otros tipos de archivos
(los directorios) cuyo objetivo es almacenar las referencias a otros archivos. El directorio no
posee el contenido de aquellos archivos a los que referencia.
Cuando uno crea un archivo, lo crean en algún lugar del filesystem (posicionados en algún
directorio). Siempre hay una estructura de directorio que puede tener diferentes formatos. En
el directorio donde lo creo, agrego como contenido de ese archivo directorio una entrada más.
Uno podría acceder al mismo archivo desde diferentes lugares y el nombre en sí, que uno le
da, en realidad no es parte del archivo. Es por eso que no es parte del FCB sino que dicho
nombre está almacenado en el directorio en el que se creó.
Permite realizar el mapeo entre nombres de archivos (conocidos por usuarios y aplicaciones) y
los archivos en sí. Nosotros como usuarios finales usamos dicho nombre para poder mapear lo
que conocemos de dicho archivo a algún contenido que está en el disco. Entonces el filesystem
hace ese mapeo para poder decir en definitiva en donde está.
- Un nivel (todos los archivos juntos, no se pueden repetir nombres). Aun así hoy en día
hay algunas estructuras que no tendrían sentido como que para todo el filesystem se
tenga un único nivel.
- Dos niveles (un directorio por usuario). Tampoco es real hoy en día poner todos los
archivos de un usuario en un mismo directorio.
- Árbol: al tener mayor profundidad significa que podría tardar más en encontrar un
nodo (a más niveles uno tarda más). Para optimizar se busca una estructura que
permite minimizar esa cantidad de niveles y la búsqueda sea más rápida.
- Grafo acícilo
- Grafo general: uno puede volver y generar un ciclo, además de poder llegar a un
mismo archivo a partir de más de uno.
IMPLEMENTACIÓN DE DIRECTORIOS
Del más simple al más complejo: se tiene en cuenta que operaciones se desearán hacer en
dicho directorio: si quiere poder buscar ordenado, si quiere ordenar por diferentes criterios,
etc. Por lo general, para levantar el directorio también se debe tener información de los FCB
- Lista lineal
o Más fácil de programar
o Manipulación más compleja (buscar -agregar-eliminar)
o Requiere búsqueda lineal
- Lista enlazada ordenada
o Más complejo agregar/eliminar entradas
- Árbol-B
o Minimiza el tiempo de búsqueda
- Tabla de hash
o Lista lineal + estructura de hash
OPERACIONES SOBRE ARCHIVOS
- CREAR: consiste en definir un nuevo archivo, por lo que hay una abstracción de él,
asignándole un FCB y un espacio de almacenamiento, además de agregar una entrada
al directorio.
- ELIMINAR: consiste en liberar al FCB, además del espacio en almacenamiento, además
de eliminar la entrada del archivo del directorio donde se encontraba.
- OPEN: consiste en que un proceso abre un archivo existente obteniendo así su
identificador para realizar en él futuras operaciones (y poniendo su FCB en memoria
también). Para obtener el identificador del archivo se debe de recorrer todo el path del
mismo por lo que sería bastante ineficaz si lo hiciese cada vez que se pretende hacer
una operación en él.
- CLOSE: una vez que el proceso no pretende realizar ninguna operación más a futuro se
cierra el archivo abierto (se puede volver a abrir pero conlleva un costo: volver a
buscar su identificador). Si no se cerrase el archivo y se termina de ejecutar, se
liberaría junto con todos los recursos que el proceso debe liberar.
- LEER/ESCRIBIR: para leer o escribir sobre un archivo se utiliza el identificador del
mismo obtenido cuando se abrió previamente.
- TRUNCAR
- POSICIONAR PUNTERO FSEEK
- OPERACIONES COMPUESTAS:
o COPIAR: para copiar un archivo se requiere abrir y leer el archivo en cuestión,
y, en el lugar de destino donde se pretende copiar, crear un nuevo archivo y
escribir en él (lo que se leyó previamente).
o MOVER – CORTAR: tanto mover como cortar un archivo son operaciones de las
cuales depende dónde se haga el tiempo que tardara:
Si se hace dentro del mismo file system donde se encuentra el archivo
en cuestión, lo único que se requiere es cambiar la entrada del archivo
en el directorio al lugar de destino donde se pretende mover o cortar.
Si se hace de un file system a otro diferente es una operación más
compleja ya que consiste en copiar el archivo y eliminarlo del lugar de
origen.
o RENOMBRAR
LOCKS
Se utilizan:
Puede ser:
- Exclusivo (lock de escritura): un proceso puede adquirirlo por vez, los demás se
bloquearan al intentar acceder al archivo.
- Compartido (lock de lectura): si el archivo no está siendo modificado, todo proceso
que desee acceder al archivo en modo lectura podrá. Si hay procesos que se
encuentran leyendo el archivo y un proceso pretende modificarlo, este debe de
esperar a que los procesos liberen el archivo (se bloquea). Es decir, muchos procesos
pueden adquirirlo concurrentemente. Un proceso no puede adquirir un lock exclusivo
mientras haya uno compartido.
1. Cuando se tienen casos que procesos van a acceder en modo lectura y otros en modo
escritura. Con mutex si uno quiere acceder al recurso compartido (en modo escritura o
lectura, es indiferente para el mutex) el resto se bloquea (sea que quiere hacer una
modificación o leerlo), pero los locks permiten que varios procesos puedan acceder en
modo lectura a la vez, y si uno pretende escribir se bloquea esperando que el archivo
sea liberado por los demás liberen al archivo. Cuando un proceso está en modo
escritura, aquellos que pretendan tanto leer o escribir no podrán y se bloquearán
hasta que el proceso termine de modificar al archivo.
Es por esta razón que se puede decir que los mutex hacen esperar más a los procesos.
2. Además otra característica que tienen los locks y que los mutex no es que uno puede
lockear una parte del archivo, es decir, no necesita lockear todo el archivo entero lo
cual es aún más óptimo.
MANIPULACIÓN DE ARCHIVOS
El FCB es la estructura por la cual el SO administra un archivo. Esta estará en un principio en
disco pero cuando se está accediendo a un archivo uno va a querer traerlo a memoria,
administrarlo y tener en cuenta que procesos van a querer acceder a él.
Cuando un proceso pretende abrir un archivo, lo que se quiere recuperar es su id y con él traer
a memoria el FCB (entonces todas las operaciones que se quieran hacer se realizaran a partir
de la información obtenida de ese FCB que ya se encuentra en RAM). Sin embargo, como
varios procesos pueden acceder a él (por el lock de lectura) puede que el FCB ya esté en RAM y
otro archivo haya accedido a él. Es por esto que cuando un proceso pretende abrir un archivo,
la apertura puede ser rápida (si el FCB ya está en RAM y otro archivo accedió a él primero
recuperando el id) o más lenta (si debe de recurperar el id recorriendo todo el path del archivo
en cuestión).
Para una mejor manipulación se necesita tener una tabla de archivos abiertos global y una
particular para cada proceso.
Por otro lado, cada proceso podría estar accediendo a diferentes archivos y podría tener cosas
particulares (como el modo de apertura, por donde está leyendo, información de locks, etc.).
Aun así no sería necesario tener toda la información del FCB copiada debido a que sería
redundante, por lo que probablemente podría estar apuntando a la entrada de la tabla global
del/de los archivo/s a los que accede.
Entonces cuando se abre un archivo, primeramente se tiene que mirar si está en la tabla global
de archivos abiertos para ver si nos podemos ahorrar ir a buscarlo a la estructura directorio (y
traerlo a RAM). Es por esto que a veces abrir un archivo se hace más rápido y otras veces más
lento. Obviamente si un proceso abre un archivo, se agregará una entrada en su tabla de
archivos abiertos (la del proceso). Si el archivo ya está en la tabla global, desde la entrada del
proceso se podrá apuntar a esa global.
Al tener estas estructuras... ¿En qué momento se borrará una entrada en la tabla global y en
qué momento en la del proceso?
Cada vez que un proceso hace close de un archivo la entrada en su tabla de archivos abiertos
se borrará. En cuanto a la tabla global, para borrar la entrada de un archivo determinado habrá
que esperar a que ningún proceso tenga abierto el archivo en cuestión. Para eso se tendrá un
contador de aperturas por entrada (aumenta si un proceso abre un archivo y disminuye si lo
cierra). Cuando llegue a 0 significa que ningún proceso está accediendo a él y se podrá borrar
de la tabla global.
PROTECCIÓN
Puede ser:
- Acceso total: no se aplica ninguna estrategia de protección (todos los procesos pueden
acceder a cualquier archivo si tienen el path)
- Acceso controlado: indica quien puede operar y cómo (qué permisos tiene). Puede ser
con:
o Una matriz de acceso
o Propietario | grupo | universo (resto)
o ACL
PROTECCIÓN EN LINUX
Consiste en usar como protección OWNER | GROUP | UNIVERSE pero con un bit más para
identificar el tipo de archivo (si es un directorio o no). Esto es así debido a que los accesos son
distitos:
Podría pasar que con el esquema de Propietario | Grupo | Resto no alcance para dar permisos
en forma adecuada para nuestra situación. Es por esto que se puede combinar dicha estrategia
con ACL en caso de ser necesario (lo cual agrega granularidad y con ello ocupa más espacio y
genera más complejidad). Cuando uno accede se le dará el permiso más específico.
¿Por qué?
Uno al usar file system, cada vez que tiene que hacer una operación sobre un archivo (open,
un close, write, read, etc.) tiene que hacer una llamada al sistema, es decir, una syscall (que
conlleva un cambio de modo, el cambio de contexto). Entonces, uno puede mapear al archivo
(puede ser una parte, no hace falta que sea todo el archivo) al espacio de direcciones del
proceso que accedió a él (como si fuese una parte de la imagen del mismo) a través de una
syscall y acceder a él como si fuese cualquier parte de la memoria.
Obviamente se necesita esa syscall inicial para que el SO lo mapee, pero después todas las
operaciones se hará sin realizar syscalls. Simplemente se accederá a memoria cuando esté
cargado y, cuando no, realizará el PF y lo irá a buscar.
MÉTODOS DE ACCESO
- Secuencial: Un registro después del otro
- Directo: Se puede acceder a cualquier registro sin recorrer los anteriores
- Indexado: Se coloca un índice para acelerar búsquedas sobre archivos grandes
- Hashed: Para agilizar accesos directos. Se utiliza la función de hash para acceder
directamente al bloque deseado
Para esto, el disco posee un espacio pequeño para el MBR (master boot record) que nos dice la
mínima información del disco (que particiones hay, si poseen formato o no).
Cada partición posee un formato llamado volumen que tiene (según el file system será
diferente pero hay algo que si suelen mantener):
En este caso el almacenamiento en disco va a ser por sectores. Sin importar el medio de
almacenamiento el file system administrará igual, porque siempre va interpretar que va a
tener un disco virtual con bloques lógicos (que van de 0 a n dependiendo del tamaño del
bloque lógico y de la capacidad de la partición en la cual estemos trabajando, en este caso el
disco físico).
Es decir, La unidad de asignación del FS será Bloque Lógico. Para ello se debe de tener una
estrategia para la asignación de bloques y la administración de los que se encuentren libres.
Lo que uno necesita para administrar un esquema así es poder decir: en donde empieza el
archivo (para saber desde donde acceder) y donde termina (además de no pasarse, si uno
quiere extender el archivo poder cambiarlo fácilmente). La otra opción es en vez de saber
dónde termina, saber la cantidad de bloques que ocupa (el tamaño) y de esa forma calcular
cual es el último.
VENTAJAS
- Sencillo de administrar.
- Si uno quiere acceder de forma secuencial puede, de forma directa también.
- Los reposicionamientos se encuentran relacionados a cómo es que se almacena la
información en los discos rígidos. Teniendo en cuenta de que si están cerca
probablemente estén en el mismo cilindro (moverse de un cilindro a otro es lo que
genera el movimiento mecánico del brazo del disco y es lo que toma más tiempo). Por
lo tanto los reposicionamientos en esta estrategia de asignación de bloques serán
mínimos ya que al tener los datos del archivo juntos en el disco lógico hace que sea
más probable que estén juntos en el disco rígido y por ende el brazo del disco rígido se
tendrá que mover menos.
DESVENTAJAS
- A priori cuando uno crear un archivo tendrá que saber cuántos bloques necesitará
(pre-alocacion), es decir, el tamaño del mismo.
- Si bien todos los datos del archivo están contiguos, entre bloques no. Estos se asignan
de forma dinámica lo cual genera que la administración entre bloques sea compleja y
además provoca fragmentación externa (que se puede solucionar con compactación
pero al ser movimientos en disco y no en memoria será mucho más lento).
La forma de entender cuál es el bloque que le sigue al actual es a traves de un puntero. Dicho
puntero estará almacenado dentro del bloque de datos.
Se necesita el bloque inicial y el final ya que si uno en vez de guardar el bloque final guarda el
largo, sería muy molesto para agregar nuevos bloques. Esto es así debido a que para agregar
un nuevo bloque uno debería modificar el puntero del último bloque enlazado y sabiendo
únicamente el largo se tendría que leer todos los bloques previos para ello.
VENTAJAS
- No hay problemas para aumentar el tamaño del archivo (no hay prealocación)
- No presenta fragmentación externa (importante para almacenamiento secundario)
- Es bueno para acceso secuencial
DESVENTAJAS
- Espacio ocupado por punteros: se está usando una parte del bloque (aunque pequeña)
para almacenar algo que no es datos (un puntero al siguiente bloque).
- Si hay un fallo en el disco y una de las partes intermedias se rompe se pierde la
trazabilidad del archivo.
- Los reposicionamientos del cabezal del disco pueden ser mayores (bloques dispersos).
Es preferible esto a tener fragmentación externa.
- Si se quiere leer directamente un bloque se tendrá que acceder a todos los anteriores
a él (que realmente no se querian) para obtener la dirección.
¿Qué tan grande o que tan chico va a ser este bloque de punteros?
- Si es muy chico desperdicio menos espacio pero estoy limitando el tamaño de mi
archivo.
- Pero si es muy grande seguramente tengamos para algunos bloques bastante
fragmentación interna.
¿Cómo se soluciona?
- Esquema enlazado. Cada bloque de índice ocupa normalmente un bloque de disco ->
puede leerse y escribirse directamente. Para que puedan existir archivos de gran
tamaño, enlazamos varios bloques de índice.
- Índice multinivel. utilizar un bloque de índice de primer nivel para apuntar a un
conjunto de bloques- de índice de segundo nivel, que a su vez apuntarán a los bloques
del archivo.
- Esquema combinado. mantener los primeros N punteros del bloque de índice en el
nodo del archivo siendo algunos ptrs a bloques de datos(BD) y otros a bloques de ptrs
(BP)
o Los archivos pequeños no necesitan un índice separado
o Se pueden aun así referenciar a muchos bloques de datos, por lo que no se
limita el tamaño del archivo.
VENTAJAS
- No hay problemas para aumentar el tamaño del archivo (no hay prealocación)
- No presenta fragmentación externa
- Es bueno para acceso secuencial y directo
DESVENTAJAS
- Los reposicionamientos del cabezal del disco pueden ser mayores ( bloques dispersos )
- Espacio ocupado por punteros es aún mayor (quizás haya entradas que no se utilicen)
- Corrupción de punteros es peor porque si se rompe el bloque de índices no se sabrá
dónde están los bloques del archivo en cuestión -> problema fiabilidad
El acceso no será tan directo como en un principio que se tenía un índice y ay se tienen todos
los punteros a los bloques de datos. Se encadenan accesos (que aplicaba para bloques de
datos y ahora también para bloques de índices). Dependiendo que bloque de datos tenga que
acceder, serán menos o más accesos a bloques de punteros.
Si por ejemplo se quiere acceder al bloque 25 y la N=10, se sabe que la referencia al bloque se
encuentra en el índice 3. Es por esto que se tendrá que traer el bloque 1 (+1) para recuperar el
puntero al dos (+1), el bloque dos para recuperar el puntero al bloque 3 (+1) y recién ahí, ya en
el bloque 3 acceder a la 5ta posición (+1). (4 accesos).
Pero esto no significa que si quiere acceder al bloque de datos n°25 tengo que acceder a los 24
anteriores.
A priori se debe determinar qué nivel de dirección se quiere, lo cual definirá cuanto se puede
direccionar (no será infinito).
Siempre el número de accesos será NIVEL + 1. Cuanto mayor sea el nivel, más serán los accesos
que se deberán hacer para acceder a un bloque de datos. + COSTOSO
Bloques indexados: espacio libre tratado como un archivo, todos los bloques libres
administrarlos con un índice
Lista de bloques: se almacena en los bloques libres las direcciones de los siguientes N-1
bloques libres
JOURNALING
La información de las estructuras del FS por lo gral están más actualizadas en memoria que en
disco
Un fallo en el sistema (apagones repentinos por ejemplo, sino terminará lo que deba hacer) /
en el HW puede generar inconsistencias.
Para que esto no ocurra se usará un journal (un log en el cual uno va a ir escribiendo cuales son
las operaciones que se realizaron sobre las estructuras administrativas). Se va a guardar y se
usará en forma circular (no crecerá infinitamente sino que en algún momento los cambios se
bajarán a disco por lo que se va pisando en forma circular).
Se marcará con un flag/commit cuáles son las operaciones necesarias para que un cambio
quede consistente. Se aplican las transacciones que se encuentran completas (que hay un
commit debajo de todas sus microperaciones), y las que no se borran y no se aplican (no
quedan persistidas en disco). Si se llegó a escribir una transacción pero quedo incompleta se
tendrá que volver para atrás.
Cuando se deba modificar en disco, se tendrá un puntero que indicará cual es la última
operación actualizada.
PPT 13 IMPLEMENTACIONES EXT2 Y FAT
EXT
INODOS
Estructura muy importante que posee todas las propiedades del archivo en cuestión (como el
FCB).
Tiene una asignación indexada combinada (hay bloques directos, de un nivel, de dos niveles,
etc.), es decir, guardan punteros directos e indirectos (usa esquema mixto con punteros
directos a bloques y con esquema indexado)
ESTRUCTURA EXT2
¿Cómo organiza su volumen?
- Con un súper bloque con información general del file system: tanto para saber su
configuración como también para saber su estado (que bloques y que INODOS están
libres).
- Descriptores de grupo
- Bitmap bloques datos (para administrar los bloques de datos)
- Bitmap de nodos
- Tabla de inodos (Tipo, Dueño, Tamaño, TIMESTAMPS, NRo bloques, PTRs a BD y PTRS a
BP).
- BLOQUES DE DATOS
Porque si bien los bloques de un archivo no estarán contiguos (al ser indexado), logrará que no
estén tan dispersos dentro del disco lo cual generará menos movimientos del cabezal del disco
y por ende va a ser más rápido leer el disco. Es decir, se realiza para optimizar el acceso en este
tipo de dispositivos.
DIRECTORIOS
La entrada de directorio posee el nombre (no es parte del archivo pero está) y el identificador
del FCB (en este caso el número de inodo para recuperarlo y operar en memoria).
TIPOS DE ARCHIVOS
En general los fyle system no poseen la lógica para interpretar todos los tipos de archivos
existentes. A priori interpreta un par de tipos nativamente y el resto se delega en un par de
aplicaciones
- Regular (-)
- Directorio (d)
- Links
o Soft/Symbolic Links (l)
o HardLinks (-) no lo distingue de un archivo regular.
SOFTLINK
- Análogo a “acceso directo” en Windows
- Es un archivo independiente al archivo original (al cual se está linkeando)-> posee su
propio inodo
- Su contenido posee la ruta a otro archivo al que apunta
- Puede realizarse entre distintos FSs (da cierta flexibilidad debido a que se puede hacer
un softlink de cualquier cosa debido a que es solo un path)
El acceso es más lento y costoso debido a que tiene un nivel de mayor indirecciones:
Si uno cierra el archivo en cuestión se generará una inconsistencia (el SL seguirá estándo al ser
un archivo independiente y en su contenido habra un path no existente).
HARDLINK
- Es una nueva referencia (entrada de directorio) a un archivo que a punta al mismo
inodo
- Existe un único archivo con uno o más hardlinks (counter)
- No puede realizarse entre distintos FSs, solo tiene sentido dentro del mismo scope.
Tampoco se podrá hacer sobre directorios
Se necesitará administrar cuántas referencias tendrá ese archivo para saber cuándo se podrá
borrar. Si hay otro que está referenciando un archivo, al hacer un rm no debería borrarlo sino
que se debería borrar solo esa entrada a directorio.
FAT
FAT (dile allocation table) se llama al file system y también a la tabla que utiliza.
➔ Hay una entrada por bloque (cluster = bloque lógico) de disco. Es decir, tiene tantas
entradas como bloques tiene el disco virtual (y el bloque coincide con el bloque
lógico).
Las relaciones entre bloques no se encuentran en los bloques de datos sino en esta tabla que
probablemente siempre estará cargada en memoria. Es por esto que:
- Si bien hay que hacer todos los recorridos (al ser enlazados) se hará en la tabla (por lo
que no se tiene que hacer todos los accesos y traer los bloques de disco). por lo que
todos los accesos serán en memoria (menos costoso y lento)
- Si se pierde, se pierde el sentido entre los bloques de datos de esa partición. Entonces
lo más probable es que se tenga una copia o dos de esta estructura dentro del
volumen. Obviamente cuando se esté cargando en memoria se utilice solo una de
estas FAT's y se tendrá que linkear a disco (para actualizarse)
VOLUMEN
Está dividido en:
TAMAÑO ENTRADA
¿A qué hace referencia el número? Al tamaño de direccionamiento.
Cada entrada hace alusión a un bloque lógico de disco, por lo que se puede tener hasta 2^12
bloques.
➔ FAT 12
◆ Entradas de 12 bits
➔ FAT 16
◆ Entradas de 16 bits
➔ FAT 32
◆ Entradas de 32 bits
¿Qué creen que limita el tamaño del archivo? ¿Qué tan grande puede ser un archivo en FAT?
La tabla tendrá tantas entradas como bloques pueda referenciar, entonces uno podría
direccionar más del espacio que se posee en la partición o al revés (que tenga una partición
más grande de lo que me permite direccionar el filesystem). La tabla va a tener las entradas
justas (lo que necesita).
Lo que limitará el tamaño del archivo es lo mismo que limita el tamaño del filesystem porque
se puede direccionar la cantidad de bloques que tenga ese file system.
Para saber el tamaño del archivo se le deberían restar el tamaño de las estructuras
administrativas pero se minimiza ese espacio que se descarta (se lo toma como 0 y se cuenta
únicamente los datos).
Pero no es como el EXT que hay otra configuración (como el INODO) que nos termina
limitando el tamaño del archivo. Lo mismo que permite direccionar (el tamaño de FAT) es lo
que limita.