\newpage
%===========================================================================
%       x.6 > Sistemas operativos
%===========================================================================
\pagestyle{empty}
\begin{latexonly}
\ifpdf
 \begin{figure}[htbp]
% \includegraphics[bb = -250 220 0 0, scale=1]{./TuXes/tux-net.jpg}
 \end{figure}
 \vspace{5in}
\else
 \begin{figure}
%       \includegraphics[-275,650][0,0]{./TuXes/tux-net}
 \end{figure}
\fi
\hfill\line(1,0){400}
\end{latexonly}
\topmargin 1in
\section{SISTEMAS OPERATIVOS}
\begin{latexonly}
\line(1,0){400}
\newpage
\end{latexonly}
\topmargin 0in
\pagestyle{fancy}
%========================cita===============================================
\begin{latexonly}
\hspace{1in}\textcolor{blue_omosix}{{\em Microsoft isn't evil, they just make really crappy operating systems.}}

\hspace{4in}\textcolor{blue_omosix}{{\em Linus Torvalds}}
\vspace{0.5in}
\end{latexonly}
%===========================================================================
\subsection*{Introducci\'on}
Los ordenadores se est\'an convirtiendo en una plataforma cada vez m\'as abierta
 y los sistemas operativos tienen que dar los servicios necesarios para
 que esto pueda gestionarse de manera adecuada. Dando un breve repaso a la historia de
 los sistemas operativos puede verse que cada vez tienen m\'as posibilidades
 de comunicaci\'on.

Cuando se construyeron las primeras redes de computadores se vio la
 potencia que ten\'\i an estos sistemas y se desarroll\'o el paradigma cliente/servidor.
 Se crearon los sistemas operativos de red con servicios como NFS o FTP
 para acceder a sistemas de ficheros de otros ordenadores. {\tt Xwindow} para entorno gr\'afico, {\tt lpd} para poder imprimir remotamente adem\'as de un conjunto de herramientas que permit\'\i an el acceso a recursos compartidos.
 
En los aurales de la inform\'atica el sistema operativo ni siquiera
 exist\'\i a: se programaba directamente el hardware. Se vio que
 era muy pesado y se program\'o una capa de abstracci\'on que evitaba al programa
 tener que tener un conocimiento total del hardware: el sistema operativo.
Se descubri\'o tambi\'en que con un solo proceso se desperdiciaba tiempo de
 procesador y como tales dispositivos eran car\'\i simos se empezaron a inventar mecanismos que
 evitasen que el programa esperase bloqueado por ejemplo las operaciones de entrada/salida. Se lleg\'o a
 la multiprogramaci\'on en el ambicioso MULTICS y el posterior UNIX.
 Estos dos sistemas se desarrollaron a finales de los a\~{n}os 60 y se basaban
 en el {\em MIT Compatible Timesharing System} realizado en 1958.

 En los a\~{n}os 70 se a\~{n}adieron las primeras capacidades de
 interconexi\'on:
\begin{itemize}
  \item Xerox invent\'o la red Ethernet
  \item IBM la Token Ring 
  \item y surgi\'o UNIX BSD 4.2
\end{itemize}
Este sistema operativo fue ampliamente usado porque integraba capacidades
 de comunicaci\'on: implementaba TCP/IP y ten\'\i a capacidades de intercomunicaci\'on
 entre procesos.

\vspace{.2in}
Un sistema operativo distribuido puede acceder a cualquier recurso
 transparentemente y tiene grandes ventajas sobre un sistema operativo
 de red. Pero es muy dif\'\i cil de implementar y algunos de sus
 aspectos necesitan que se modifique seriamente el n\'ucleo del
 sistema operativo, por ejemplo para conseguir memoria distribuida
 transparente a los procesos. Tambi\'en se tiene que tener en cuenta
 que ahora la {\em m\'aquina} sobre la que corre todo el sistema es el
 sistema distribuido (un conjunto de nodos) por lo que tareas como
 planificaci\'on de procesos ({\em scheduling}) o los hilos ({\em
 threads}) y se\~{n}ales entre procesos
 toman una nueva dimensi\'on de complejidad. Por todo esto a\'un no
 existe ning\'un sistema distribuido con todas las caracter\'\i sticas de transparencia necesarias para considerarlo eficiente.

A partir de ahora no hablaremos de computadores, ordenadores ni
 PC. Cualquier dispositivo que se pueda conectar a
 nuestro sistema y donde se pueda desarrollar un trabajo \'util para
 el sistema se referenciar\'a como {\bf nodo}.
 El sistema operativo tiene que controlar todos estos nodos y permitir que
 se comuniquen eficientemente.
 
Aunque tras leer este cap\'\i tulo el lector podr\'a intuir esta idea, queremos
 hacer notar que un sistema distribuido se puede ver como el siguiente nivel
 de abstracci\'on sobre los sistemas operativos actuales.
 Como hemos visto la tendencia es a dar m\'as servicios de red y m\'as concurrencia.
 Si pusi\'eramos otra capa por encima que aunara ambos, esta capa ser\'\i a el
 sistema operativo distribuido.
 Esta capa debe cumplir los criterios de transparencia que veremos en el
 pr\'oximo apartado.

 Podemos comprender esto mejor haciendo una analog\'\i a con el SMP: cuando
 s\'olo existe un procesador todos los procesos se ejecutan en \'el, tienen
 acceso a los recursos para los que tengan permisos, se usa la memoria a
 la que puede acceder el procesador, {\em etc}.
 Cuando hay varios procesadores todos ellos est\'an corriendo procesos
 (si hay suficientes para todos) y los procesos migran entre
 procesadores.

En un sistema multiprocesador al igual que un sistema multicomputador
 hay una penalizaci\'on si el proceso tiene que correr en un elemento
 de proceso (procesador o nodo) distinto al anterior: en
 multiprocesador por la contaminaci\'on de cache y TLB; en
 multicomputador por la latencia de la migraci\'on y p\'erdidas de
 cache. En un sistema multicomputador se persigue la misma
 transparencia que un sistema operativo con soporte multiprocesador,
 esto es, que no se deje ver a las aplicaciones que realmente est\'an funcionando en varios procesadores.

En este cap\'\i tulo adem\'as se tratar\'an las zonas de un sistema operativo que
 se ven m\'as afectadas para conseguirlo. \'Estas son:
\begin{itemize}

  \item {\bf Scheduling.}

El {\em scheduling} de los procesos ahora puede ser realizado por
 cada nodo de manera individual, o mediante alg\'un mecanismo que
 implemente el cluster de manera conjunta entre todos los nodos.

  \item {\bf Deadlocks.}

Las t\'ecnicas usadas hasta ahora en un nodo local no
 se pueden generalizar de una forma eficiente en el sistema distribuido.

  \item {\bf Manejo de memoria.}

Hay que disponer de memoria distribuida: poder
 alojar y desalojar memoria de otros nodos de una forma transparente a las
 aplicaciones.
 
  \item {\bf Intercomunicaci\'on de procesos.}

Los procesos podr\'\i an estar ubicados
 en cualquier nodo del sistema.
 Se deben proveer de los mecanismos necesarios para permitir esta intercomunicaci\'on de tipo se\~{n}ales, memoria distribuida por el cluster u otros.

  \item {\bf Sistemas de ficheros.}

Pretenden que todo el sistema distribuido tenga la
 misma ra\'\i z para que no sea necesario explicitar en qu\'e nodo se encuentra
 la informaci\'on.

  \item {\bf Entrada/salida.}

Tendr\'\i a que ser posible acceder a todos los recursos de
 entrada/salida globalmente, sin tener que indicar expl\'\i citamente a que
 nodo est\'an estos recursos conectados.
\end{itemize}
%===========================================================================
\subsection{Procesos y Scheduling }
%---------------------------------------------------------------------------
\subsubsection{Utilidad de migrar procesos}
La migraci\'on de un proceso consiste en mover el proceso desdel nodo donde se
 est\'a ejecutando a un nuevo entorno.
 Aunque no se suela emplear en este caso, se podr\'\i a hablar de migraci\'on
 cuando un proceso se mueve de procesador.
 Aqu\'\i\  consideraremos migraci\'on cuando un proceso se mueve de un nodo a otro.

En un sistema de tipo cluster lo que se pretende, como se ver\'a en el
 cap\'\i tulo {\em Clusters}, es compartir aquellos dispositivos (a partir de ahora ser\'an los {\em recursos}) conectados a cualquiera de los nodos.
 Uno de los recursos que m\'as se desear\'\i a compartir, aparte del almacenamiento
 de datos, es el procesador de cada nodo. Para compartir el
 procesador entre varios nodos lo m\'as l\'ogico es permitir que las
 unidades at\'omicas de ejecuci\'on del sistema operativo (procesos, con PID propio) sean
 capaces de ocupar en cualquier momento cualesquiera de los nodos que conforman
  el cluster.

En un sistema multiusuario de tiempo compartido la elecci\'on
 de qu\'e proceso se ejecuta en un intervalo de tiempo determinado la hace
 un segmento de c\'odigo que recibe el nombre de {\em scheduler}, el planificador de procesos.
 Una vez que el scheduler se encarga de localizar un proceso con las
 caracter\'\i sticas adecuadas para comenzar su ejecuci\'on, es otra
 secci\'on de c\'odigo llamada {\em dispatcher} la que se encarga de
 substituir el contexto de ejecuci\'on en el que se encuentre el
 procesador, por el contexto del proceso que queremos correr.
 Las cosas se pueden complicar cuando tratamos de ver este esquema en un
 multicomputador.
 En un cluster, se pueden tener varios esquemas de actuaci\'on.
\begin{itemize}
  \item {\em Scheduling} conjunto. En el cual todos los nodos del
 cluster hacen la elecci\'on de los procesos que se ejecutaran en el
 cluster y quiz\'a incluso en cada nodo.  Esto requiere una
 actuaci\'on conjunta de todos los nodos, lo que implica que el
 scheduling podr\'\i a ser:
   \begin{itemize}
   \item \underline{Centralizado:} una o varias m\'aquinas trabajando para efectuar las tareas
 de scheduler y organizar el resto del cluster.
 Es sencillo de implementar, pero tiene m\'as inconvenientes que ventajas,
 aparte que los inconvenientes son de mucho peso y muy obvios.
   \item \underline{Distribuido:} requieren un modelo matem\'atico adecuado y una implementaci\'on
 m\'as complicada.
   \end{itemize}

  \item {\em Scheduling} individual: cada nodo act\'ua de la manera comentada en sistemas individuales,
 pero a\~{n}ade la acci\'on de migrar procesos a otros nodos, de manera que se
 optimice tiempo de ejecuci\'on global en el cluster.
 Para esto, los nodos comparan la carga de otros nodos y deciden c\'ual de
 los procesos que tienen en la cola de espera para ser ejecutados es el
 \'optimo para ser enviado a otro nodo.
\end{itemize}
Conforme se avance en este manual se ver\'a cu\'al puede convenir m\'as para cada caso. Otra de las pol\'\i ticas que puede variar del scheduling en un ordenador individual
 a un cluster es la de diseminaci\'on de la informaci\'on de los nodos.
 A la hora de elegir sobre qu\'e nodo migrar un proceso, tanto en el 
{\em scheduling} conjunto como en el individual, se debe conocer la informaci\'on de los nodos
 para balancear convenientemente el sistema.
 Esta diseminaci\'on puede estar basada en:
\begin{itemize}
  \item Informaci\'on global.
  \item Informaci\'on parcial.
\end{itemize}
De estos dos, el primero no es muy escalable, pero probablemente sea m\'as
 adecuado en ciertas condiciones.
 Lo m\'as habitual es que un cluster deje las decisiones
 sobre cu\'ando ejecutar cada proceso a cada nodo particular, por tanto la
 principal novedad en un sistema distribuido es que hay que permitir
 que los procesos se ejecuten en cualquier computador no necesariamente
 en el que se crearon. Y transparentemente a los mismos procesos.
 Este ha sido un tema estudiado numerosas veces, con todo tipo de conclusiones,
 seguramente la m\'as sorprendente es la de Tanenbaum\footnote{{\em La migraci\'on real de procesos en ejecuci\'on es trivial en teor\'\i a, pero cerca de lo imposible en la pr\'actica}, del libro publicado
 junto a R. Renesse {\em Distributed Operating Systems}}.
Se equivoc\'o (una vez m\'as) porque openMosix ha conseguido la
 migraci\'on en la pr\'actica. Esta migraci\'on de procesos tiene varias ventajas, como son:
\begin{itemize}
  \item Compartici\'on de carga: los procesos se trasladar\'an a la m\'aquina con menos
 carga para evitar que haya sistemas sobrecargados. Tambi\'en 
 se tiene en cuenta cu\'ando se est\'a acabando la memoria de la m\'aquina. En definitiva
 los procesos van donde tengan m\'as recursos.
 En el caso \'optimo se tendr\'\i a la potencia de todas las m\'aquinas sumadas,
 pues con un balanceo perfecto podr\'\i an tenerse a todos los nodos
 trabajando a m\'aximo rendimiento, aunque el trabajo original se produjese
 en un nodo solo.

 Por supuesto este este es el caso ideal y no se puede dar en la realidad
 pues siempre se necesita potencia de c\'alculo para enviar y recibir los
 procesos as\'\i\ como para tomar las decisiones ({\em overhead}).
  \item Rendimiento de las comunicaciones: los procesos que necesitan entrada/salida
 en un nodo se desplazan a \'este para evitar traer todos los datos a trav\'es
 de la red.
 Otra variante es mantener a todos los procesos que interact\'uan fuertemente
 entre ellos en una misma m\'aquina.
\end{itemize}
Las principales decisiones que se deben tomar en un sistema distribuido
 para hacer esta migraci\'on eficiente las podemos englobar en tres pol\'\i ticas
 distintas:
\begin{itemize}
 \item Pol\'\i ticas de localizaci\'on
 \item Pol\'\i ticas de migraci\'on
 \item Pol\'\i ticas de ubicaci\'on
\end{itemize}
A parte de estas pol\'\i ticas tambi\'en hay que hacer otras consideraciones
 que no tienen que ver con las decisiones que se toman sino c\'omo van a ser
 implementadas en la pr\'actica, estas son:
\begin{itemize}
 \item Parte del proceso a migrar
 \item Mecanismos de migraci\'on
\end{itemize}
%---------------------------------------------------------------------------
\subsubsection{Pol\'\i tica de localizaci\'on}
Cubre las decisiones referentes a desde d\'onde se lanzaran los procesos.

Este tipo de planteamiento s\'olo se efect\'ua en los sistemas SSI de los que
 se hablar\'a m\'as tarde, ya que necesita un acoplamiento muy fuerte entre
 los nodos del cluster.
 Un ejemplo puede ser el requerimiento de un cluster que dependiendo del
 usuario o grupo de usuario elija un nodo preferente donde ejecutarse por
 defecto.
En openMosix no se hace uso de esta pol\'\i tica, ya que el sistema
 no est\'a tan acoplado como para hacer que otro nodo arranque un
 programa.
%---------------------------------------------------------------------------
\subsubsection{Pol\'\i tica de migraci\'on}
La pol\'\i tica de migraci\'on plantea las decisiones que hay que hacer para responder
 a preguntas, a saber:
\begin{itemize}
  \item ?`cu\'ando se inicia la migraci\'on?
  \item ?`qui\'en inicia la migraci\'on?
\end{itemize}  
Para saber cu\'ando se debe realizar una migraci\'on nuestro nodo debe estar
 en contacto con los dem\'as nodos y recolectar informaci\'on sobre su estado
 y as\'\i , y teniendo en cuenta otros par\'ametros como la carga de la red, se
 debe hacer una decisi\'on lo m\'as inteligente posible y decidir si es momento
 de migrar y qu\'e es lo que se migra.
 
Las causas que hacen que se quiera realizar la migraci\'on van a depender
 del objetivo del servicio de la migraci\'on.
 As\'\i\  si el objetivo es maximizar el tiempo usado de procesador,
 lo que har\'a que un proceso migre es el requerimiento de procesador en su nodo local, as\'\i\ 
 gracias a la informaci\'on que ha recogido de los dem\'as nodos decidir\'a si
 los merece la pena migrar o en cambio los dem\'as nodos est\'an sobrecargados
 tambi\'en.

La migraci\'on podr\'\i a estar controlada por un organismo central que tuviera
 toda la informaci\'on de todos los nodos actualizada y se dedicase a decidir
 como colocar los procesos de los distintos nodos para mejorar el rendimiento.
Esta soluci\'on aparte de ser poco escalable, pues se sobrecargan mucho la
 red de las comunicaciones y uno de los equipos, es demasiado centralizada
ya que si este sistema falla se dejar\'an de migrar los procesos.

El otro mecanismo es una toma de decisiones distribuida: cada nodo tomar\'a
 sus propias decisiones usando su pol\'\i tica de migraci\'on.
 Dentro de esta aproximaci\'on hay dos entidades que pueden decidir cuando
 migrar un proceso: el propio proceso o el kernel del sistema operativo.
\begin{itemize}
 \item  Si el proceso es quien va a decidirlo hay el problema de que \'el
 tiene que ser consciente de la existencia de un sistema distribuido.
 \item En cambio si es el kernel quien decide, la funci\'on
 de migraci\'on y la existencia de un sistema distribuido pueden ser transparentes
 al proceso.
\end{itemize}
 Esta \'ultima es la pol\'\i tica que usa openMosix.
%---------------------------------------------------------------------------
\subsubsection{Pol\'\i tica de ubicaci\'on}
Encontrar el mejor nodo donde mandar un proceso que est\'a
 sobrecargando el nodo de ejecuci\'on no es una estrategia f\'acil de implementar.
Entran en juego una gran amplia gama de algoritmos generalmente
 basados en las funcionalidades o recursos a compartir del cluster,
 y dependiendo de cu\'ales sean estos, se implantar\'an unas medidas u otras.
 El problema no es nuevo y puede ser tratado como un problema
 de optimizaci\'on normal y corriente, pero con una severa limitaci\'on.
 A pesar de ser un problema de optimizaci\'on se debe tener en cuenta que
 este c\'odigo va a ser c\'odigo de kernel, por lo tanto y suponiendo que est\'a
 bien programado, el tiempo de ejecuci\'on del algoritmo es
 crucial para el rendimiento global del sistema.
?`De qu\'e sirve optimizar un problema de ubicaci\'on de un proceso que va a
 tardar tres segundos en ejecutarse, si dedicamos uno a decidir donde colocarlo
 de manera \'optima y adem\'as sin dejar interactuar al usuario?

Este problema penaliza a ciertos algoritmos de optimizaci\'on de nueva generaci\'on
 como las redes neuronales, o los algoritmos gen\'eticos y beneficia a
 estimaciones estad\'\i sticas.
%---------------------------------------------------------------------------
\subsubsection{Parte de los procesos a migrar}
Una vez se sabe cu\'ando, de d\'onde y hacia d\'onde migrar\'a el proceso, falta saber
 qu\'e parte del proceso se va a migrar.
Hay dos aproximaciones:
\begin{enumerate}
  \item {\bf Migrar todo el proceso.}

Implica destruirlo en el sistema de origen y crearlo en el sistema de destino.
 Se debe mover la imagen del proceso que consta de, por lo menos, el bloque
 de control del proceso (a nivel del kernel del sistema operativo).
 Adem\'as, debe actualizarse cualquier enlace entre \'este y otros procesos,
 como los de paso de mensajes y se\~{n}ales (responsabilidad del sistema operativo).
 La transferencia del proceso de una m\'aquina a otra es invisible al proceso
 que emigra y a sus asociados en la comunicaci\'on.

El movimiento del bloque de control del proceso es sencillo.
 Desde el punto de vista del rendimiento, la dificultad estriba en el espacio
 de direcciones del proceso y en los recursos que tenga asignados.
 Consid\'erese primero el espacio de direcciones y sup\'ongase que se est\'a utilizando un esquema de memoria virtual (segmentaci\'on y/o paginaci\'on).
 Pueden sugerirse dos estrategias:
\begin{itemize}
  \item Transferir todo el espacio de direcciones en el momento de la migraci\'on.
 No hace falta dejar rastro del proceso en el sistema anterior.
 Sin embargo si el espacio de direcciones es muy grande y si es probable
 que el proceso no necesite la mayor parte, este procedimiento puede ser
 costoso.
  \item Transferir s\'olo aquella parte del espacio de direcciones que reside en memoria
 principal.
 Cualquier bloque adicional del espacio de direcciones virtuales ser\'a transferido s\'olo bajo demanda.
 Esto minimiza la cantidad de datos que se transfieren.
 Sin embargo, se necesita que la m\'aquina de origen siga involucrada en la
 vida del proceso, pues mantiene parte de su espacio de direcciones, n\'otese
 que este sistema no tiene nada que ver con el anterior, pues el sistema
 de origen es un mero almacenador de informaci\'on.

Tambi\'en es una estrategia obligada cuando lo que se migran son hilos en
 vez de procesos y no migramos todos los hilos de una vez.
 Esto est\'a implementado en el sistema operativo Emerald\footnote{Mas
 informaci\'on en {\em Migration of Light-Weight Processes in
 Emerald}. Carta de la sociedad de sistemas operativos de la IEEE.} y
 otras generalizaciones de este a nivel de usuario. 
\end{itemize}

  \item {\bf Migrar una parte del proceso.}

En este sistema:
\begin{itemize}
  \item el contexto del nivel de usuario del proceso es llamado 
{\em remote}: contiene el c\'odigo del programa, la pila, los datos, el mapeo de la memoria
 y los registros del proceso.
 El {\em remote} encapsula el proceso cuando \'este est\'a corriendo en el nivel de usuario.
  \item El contexto del kernel es llamado {\em deputy}: contiene la
 descripci\'on de los recursos a los cuales el proceso est\'a
 unido, y la pila del kernel para la ejecuci\'on del c\'odigo del sistema cuando
 lo pida el proceso.

 Mantiene la parte del contexto del sistema que depende del lugar por lo
 que se mantiene en el nodo donde se gener\'o el proceso.
\end{itemize}

 Como en Linux la interf\'\i cie entre el contexto del usuario y el contexto
 del kernel est\'a bien definida, es posible interceptar cada interacci\'on
 entre estos contextos y enviar esta interacci\'on a trav\'es de la red.
 Esto est\'a implementado en el nivel de enlace con un canal especial
 de comunicaci\'on para la interacci\'on.

El tiempo de migraci\'on tiene una componente fija que es crear el nuevo proceso
 en el nodo al que se haya decidido migrar; y una componente lineal proporcional
 al n\'umero de p\'aginas de memoria que se vayan a transferir.
 Para minimizar la sobrecarga de esta migraci\'on, de todas las p\'aginas que
 tiene mapeadas el proceso s\'olo se van a enviar las tablas de p\'aginas y las
 p\'aginas en las que se haya escrito.

OpenMosix consigue transparencia de localizaci\'on gracias a que las llamadas
 dependientes al nodo nativo que realiza el proceso que ha migrado
 se env\'\i an a trav\'es de la
 red al {\em deputy}. As\'\i\  openMosix intercepta todas las llamadas al
 sistema, comprueba si son independientes o no, si lo son las ejecuta
 de forma local (en el nodo remoto) sino la llamada se emitir\'a al
 nodo de origen y la ejecutar\'a el {\em deputy}. \'Este devolver\'a el
 resultado de vuelta al lugar remoto donde se continua ejecutando el
 c\'odigo de usuario.
\end{enumerate}
%---------------------------------------------------------------------------
\subsubsection{Mecanismos de migraci\'on }
 Normalmente las pol\'\i ticas de ubicaci\'on y localizaci\'on no suelen influir
 en estos mecanismo pues en general, una vez que el proceso migra no importa
 donde migre. Si se ha decidido que los mismos procesos son quienes lo
 deciden todo (automigraci\'on) se llega a un mecanismo de migraci\'on que es
 el usado en el sistema operativo AIX de IBM. Para este caso el procedimiento que se sigue cuando un proceso decide migrarse es:
\begin{enumerate}
  \item Se selecciona la m\'aquina destino y env\'\i a un
 mensaje de tarea remota.
 El mensaje lleva una parte de la imagen del proceso y de informaci\'on de
 archivos abiertos.

  \item En el nodo receptor, un proceso servidor crea un hijo y le cede esta informaci\'on.

  \item El nuevo proceso extrae los datos, los argumentos, la informaci\'on del entorno
 y de la pila que necesita hasta completar su operaci\'on.
 
  \item Se indica con una se\~{n}al al proceso originario que la migraci\'on ha terminado.
 Este proceso env\'\i a un mensaje final para terminar la operaci\'on al nuevo
 proceso y se destruye.
\end{enumerate}
Si en cambio es otro proceso el que comienza la migraci\'on en vez de ser
 el propio proceso tenemos el sistema que se usa en Sprite: se siguen los
 mismos pasos que en AIX pero ahora el proceso que maneja la operaci\'on lo
 primero que hace es suspender el proceso que va a migrar para hacerlo en
 un estado de no ejecuci\'on.
 Si el proceso que decide no est\'a en cada m\'aquina sino que hay solamente
 uno que hace decisiones globales, hay una toma de decisiones centralizada.
 En este caso se suelen usar unas instrucciones especiales desde esa m\'aquina
 a las m\'aquinas origen y destino de la migraci\'on, aunque b\'asicamente se
 sigue el patr\'on expuesto del sistema AIX.
 
Tambi\'en puede ocurrir que se necesite un consenso de un proceso en la m\'aquina
 origen y otro proceso en la m\'aquina destino, este enfoque tiene la ventaja
 de que realmente se asegura que la m\'aquina destino va a tener recursos
 suficientes, esto se consigue as\'\i :
\begin{enumerate}
  \item El proceso controlador de la m\'aquina origen (despu\'es de
 las decisiones oportunas) le indica al proceso controlador de la
 m\'aquina destino que le va a enviar un proceso, este proceso le
 responde afirmativamente si est\'a preparado para recibir un proceso.

  \item Ahora el proceso controlador de la m\'aquina origen puede hacer dos cosas:
 ceder el control al n\'ucleo para que haga la migraci\'on o pedir al n\'ucleo
 estad\'\i sticas del proceso y se las env\'\i a al proceso controlador destino
 (el n\'ucleo hace lo mismo si toma el control).

  \item El proceso controlador de la m\'aquina destino, o su kernel, toman esa informaci\'on
 (el proceso se la enviar\'\i a al kernel) y deciden si hay suficientes recursos
 en el sistema para el nuevo proceso. Si lo hubiera el n\'ucleo reserva los
 recursos necesarios para el proceso y lo notifica al proceso controlador
 que notifica al proceso controlador de la m\'aquina origen que proceda con
 la migraci\'on.
\end{enumerate}
%===========================================================================
\subsection{Compartici\'on de recursos}
%---------------------------------------------------------------------------
\subsubsection*{Problemas}
Para entender como compartir recursos en un sistema distribuido se plantean
 nuevos problemas respecto a compartirlos en un s\'olo sistema. V\'ease
 con un ejemplo: sup\'onganse dos instancias del mismo proceso
 que comparten memoria y acceden a una misma variable {\tt contador} contenida en esta e inicializada con
 valor 5. Luego se incrementa {\tt contador}. Lo que se espera es:
\begin{table}
\begin{center}
\begin{tabular}{ | c | c | } \hline
Instancia 1 & Instancia 2 \\ \hline \hline
lee(contador) &  \\ \hline
suma(contador,1) &  \\ \hline
escribe(contador) &  \\ \hline
 & lee(contador)  \\ \hline
 & suma(contador,1) \\ \hline
 & escribe(contador) \\ \hline
\end{tabular}
\caption{Sistemas Operativos. Compartici\'on de recursos (1)}
\end{center}
\end{table}
Si esto ocurriera as\'\i\, la primera instancia del programa pondr\'\i a el
 contador a 6, entonces la segunda instancia del programa, leyendo ese
 valor, escribir\'\i a el valor 7.
 
 Sin usar los mecanismos necesarios que controlen la ejecuci\'on, \'esta es una de las trazas de lo que podr\'\i a ocurrir:
\begin{table}
\begin{center}
\begin{tabular}{ | c | c | } \hline
Instancia 1 & Instancia 2 \\ \hline \hline
lee(contador) &  \\ \hline
a~{n}ade(contador,1) &  lee(contador)  \\ \hline
escribe(contador) & a~{n}ade(contador,1)  \\ \hline
 &  escribe(contador) \\ \hline
 & \\ \hline
 & \\ \hline
\end{tabular}
\caption{Sistemas Operativos. Compartici\'on de recursos (2)}
\end{center}
\end{table}
 El programa parece fallar de forma aleatoria, puesto que no podemos garantizar cu\'al ser\'a su ejecuci\'on real.

Esto es lo que se llama una {\em condici\'on de carrera} y desde que GNU/Linux funciona
 en m\'aquinas SMP (a partir de la versi\'on 2.0 ) se ha convertido en un tema
 principal en su implementaci\'on. Por supuesto no es un problema
 \'unico de este sistema operativo sino que ata\~{n}e a cualquiera con soporte multitarea.
 La soluci\'on pasa por encontrar estos puntos y protegerlos por ejemplo con sem\'aforos, para que s\'olo uno de los procesos pueda entrar a la vez
 a la regi\'on cr\'\i tica.
 
Esta es seguramente la situaci\'on m\'as sencilla: compartici\'on de una variable en memoria. Para aprender como solucionar \'estas y otras situaciones de conflicto
se recomienda al lector consultar los autores de la bibliograf\'\i a.
%===========================================================================
\subsection{Comunicaci\'on entre procesos}
En un cluster existe un nuevo problema: al mover un proceso
 a otro nodo, ese proceso debe seguir pudiendo comunicarse
 con los dem\'as procesos sin problemas, por lo que es necesario enviar las
 se\~{n}ales que antes eran locales al nodo a trav\'es de la red.
 
En los clusters donde los procesos tienen consciencia de si estan siendo ejecutados locales o remotos, cada nodo tiene las primitivas de comunicaci\'on necesarias para
 enviar toda la comunicaci\'on a trav\'es de la red.
 En clusters donde solo el kernel puede conocer este estado de los procesos, estas primitivas se hacen innecesarias pues la transparencia suple esta capa. \'Este es el caso de openMosix.
 
 Hay mecanismos de comunicaci\'on m\'as problem\'aticos que otros.
 Las se\~{n}ales no lo son demasiado pues se pueden encapsular en
 un paquete qu\'e se env\'\i e a trav\'es de la red.
 Aqu\'\i\ se hace necesario que el sistema sepa en todo momento
 el nodo d\'onde est\'a el proceso con el que quiere comunicar.
 
Otros mecanismos de comunicaci\'on entre procesos son m\'as complejos
 de implementar. Por ejemplo la memoria compartida: se necesita tener
 memoria distribuida y poder/saber compartirla.
 Los sockets tambi\'en son candidatos
 dif\'\i ciles a migrar por la relaci\'on que tienen los servidores con el nodo.
 %---------------------------------------------------------------------------
\subsection{La importancia de los sistemas de ficheros}
Los sistemas de ficheros son necesarios en nuestros sistemas
 para mantener la informaci\'on y compartirla
 entre usuarios y programas.
 Un fichero no es m\'as que una abstracci\'on del dispositivo de almacenaje
 permanente.

 El sistema de ficheros tradicional tiene como funciones la organizaci\'on,
 almacenaje, recuperaci\'on, protecci\'on, nombrado y compartici\'on de ficheros.
 Para conseguir nombrar los ficheros se usan los directorios, que no son
 m\'as que un fichero de un tipo especial que provee una relaci\'on entre los
 nombre que ven los usuarios y un formato interno del sistema de ficheros.

Un sistema de ficheros distribuido es tan importante para un sistema distribuido
 como para uno tradicional: debe mantener las funciones del sistema de ficheros
 tradicional, por lo tanto los programas deben ser capaces de acceder a
 ficheros remotos sin copiarlos a sus discos duros locales. Tambi\'en proveer acceso
 a ficheros en los nodos que no tengan disco duro.
 Normalmente el sistema de ficheros distribuido es una de las primeras
 funcionalidades que se intentan implementar y es de las m\'as
 utilizadas por lo que su buena funcionalidad y rendimiento son cr\'\i ticas.
 Se pueden dise\~{n}ar los sistemas de ficheros para que cumplan los criterios
 de transparencia, esto es:
\begin{itemize}
 \item {\bf Transparencia de acceso:} los programas no tienen por qu\'e saber como est\'an
 distribuidos los ficheros.
 Se deben usar las mismas instrucciones para acceder a los fichero locales
 o remotos por lo tanto los programas escritos para usar ficheros locales
 podr\'an usar ficheros remotos sin ninguna modificaci\'on.

 \item {\bf Transparencia de localizaci\'on:} los programas deben ver un espacio de nombres
 de ficheros uniforme, los ficheros o grupos de ficheros podr\'\i an ser cambiados
 de lugar sin que cambien su {\em path} ni sus nombres.
 El programa podr\'a ser ejecutado en cualquier nodo y ver\'a el mismo espacio
 de nombres.

 \item {\bf Transparencia de concurrencia:} los cambios a un fichero ocasionados por
 un cliente no deber\'\i an interferir con las operaciones de otros clientes
 que est\'en simult\'aneamente accediendo o cambiando el mismo fichero.

 \item {\bf Transparencia a fallos:} se debe conseguir una operaci\'on correcta tanto si
 falla el cliente como el servidor, haya perdida de mensajes o interrupciones
 temporales.

 \item {\bf Transparencia de r\'eplica:} un fichero podr\'\i a estar representado por varias
 copias de sus contenidos en lugares diferentes.
 Esto tiene varias ventajas, permite a muchos servidores compartir la carga
 si un n\'umero de clientes est\'an accediendo al mismo conjunto de ficheros
 aumentando la escalabilidad, permite tener copias en cache, m\'as cercanas
 al lugar donde se est\'an utilizando, aumentando el rendimiento y permitiendo
 a los clientes seguir accediendo a los ficheros aunque alguno de los servidores
 haya tenido alg\'un error aumentando la tolerancia a fallos.

 \item {\bf Transparencia de migraci\'on:} de todo lo anterior se concluye que un proceso
 o un fichero puede migrar en el sistema sin tener que preocuparse por un
 nuevo {\em path} relativo.
\end{itemize}
Para comprender mejor el problema vamos a ver cuatro sistemas de ficheros
 que desde el m\'as simple a otros m\'as complejos han intentado solucionar
 estos problemas hasta cierto grado.
 Estos sistemas de ficheros son:
\begin{itemize}
 \item NFS, Network File System.

 \item MFS, Mosix File System. Necesario en openMosix para proveer de acceso directo al FS y mantener consistencias de cache.

 \item GFS. Es un sistema de ficheros para discos compartidos.
\end{itemize} 
A continucaci\'on se enumeran sus propiedades b\'asicas y se har\'a una peque\~{n}a
 comparaci\'on entre ellos. La elecci\'on de estos sistemas de ficheros entre
 los muchos que existen no es casual: NFS es bien
 conocido y aunque existen otros sistemas similares y m\'as avanzados (como AFS, Coda o Intermezzo
 que como NFS dependen de un servidor central) sus caracter\'\i sticas avanzadas
 (cache en los clientes de AFS y la adaptaci\'on al ancho de banda, reintegraci\'on
 de una comunicaci\'on perdida y m\'ultiples peticiones RPC de Coda, simpleza
 y distinci\'on kernel/programa de usuario de Intermezzo) hacen que sea
 m\'as complejo comprender las caracter\'\i sticas que se quiere destacar en esta comparativa.
\begin{itemize}
 \item {\bf NFS}

Es uno de los primeros sistemas de archivos de red, fue creado por
 Sun basado en otra obra de la misma casa, RPC y parte en XDR para que pudiese
 implementarse en sistemas hetereog\'eneos.
 El modelo NFS cumple varias de las transparencias mencionadas anteriormente
 de manera parcial.
 A este modelo se le han puesto muchas pegas desde su creaci\'on, tanto a
 su eficiencia como a su protocolo, como a la seguridad de las m\'aquinas
 servidoras de NFS.
 
 El modelo de NFS es simple: m\'aquinas servidoras que exportan directorios
 y m\'aquinas clientes\footnote{Si bien una misma m\'aquina puede ser cliente y servidor a la vez.}
 que montan este directorio dentro de su \'arbol de directorio y al
 que se acceder\'a de manera remota.
 
De esta manera el cliente hace una llamada a {\em mount}
 especificando el servidor de NFS al que quiere acceder, el directorio
 a importar del servidor y el punto de anclaje dentro de su \'arbol de directorios
 donde desea importar el directorio remoto. Mediante el protocolo
 utilizado por NFS\footnote{Que tiene implementaci\'on en varios
 sistemas operativos no solo en UNIX o derivados, por ejemplo MSDOS.}
 el cliente solicita al servidor el directorio exportable (el servidor
 en  ning\'un momento sabe nada acerca de d\'onde esta montado el sistema en el
 cliente), el servidor en caso de que sea posible la operaci\'on, concede
 a el cliente un {\em handler} o manejador del archivo, dicho manejador contiene campos que identifican
 a este directorio exportado de forma \'unica por un i-node, de manera que
 las llamadas a lectura o escritura utilizan esta informaci\'on para localizar
 el archivo.
 
 Una vez montado el directorio remoto, se accede a \'el como si se tratase
 del sistema de archivos propio, es por esto que en muchos casos los clientes
 montan directorios NFS en el momento de arranque ya sea mediante scripts
 {\tt rc} o mediante opciones en el fichero {\em /etc/fstab}. De hecho
 existen opciones de {\em automount} para montar el directorio cuando
 se tenga acceso al servidor y no antes, para evitar errores o
 tiempos de espera innecesarios en la secuencia de arranque.

NFS soporta la mayor\'\i a de las llamadas a sistema habituales sobre los sistemas
 de ficheros locales as\'\i\  como el sistema de permisos habituales en los sistemas
 UNIX. Las llamadas {\em open} y {\em close} no est\'an implementadas
  debido al dise\~{n}o de NFS. El servidor NFS no
 guarda en ning\'un momento el estado de las conexiones establecidas a sus archivos
\footnote{De hecho no guarda ni las conexiones con los clientes ya
 que son UDP, por el poco control de coherencia de las caches que
 tiene.}, en lugar de la funci\'on {\em open} o {\em close} tiene una
 funci\'on {\em lookup} que no copia informaci\'on en partes internas del sistema.
 Esto supone la desventaja de no tener un sistema de bloqueo en el propio
 NFS, aunque esto se ha subsanado con el demonio {\bf rpc.lockd} lo
 que implicaba que pod\'\i an darse situaciones en las cuales varios
 clientes estuviesen produciendo inconsistencias en los archivos remotos.
 Por otro lado, el no tener el estado de las conexiones, implica que si
 el cliente cae, no se produce ninguna alteraci\'on en los servidores.
\begin{latexonly}
\ifpdf
        \begin{figure}[htbp]
        \includegraphics[bb = -134 280 0 0, scale=.65]{./pics/VFS_NFS.png}
        \vspace{2.5in}
        \caption{Sistemas operativos. NFS}
        \end{figure}
\else
\end{latexonly}
        \begin{figure}
        \centering
        \includegraphics{pics/VFS_NFS}
        \caption{Sistemas operativos. NFS}
        \end{figure}
\begin{latexonly}
\fi
\end{latexonly}

\vspace{.2in}
La implementaci\'on de NFS de manera general es la siguiente.
 Se efect\'ua una llamada al sistema del tipo 
{\em open(), read(), close()} despu\'es de analizar la llamada, el
 sistema pasa \'esta al VFS que se encarga
 de gestionar los archivos abiertos mediante tablas de {\em v-nodes}. Estos
 v-nodes apuntan a archivos de varios tipos, locales, remotos, de
 varios sistemas de archivos, y especifican a su vez que operaciones
 deben hacer en cada caso.

 De esta manera para el caso de NFS, VFS guarda en el v-node un apuntador
 al nodo remoto en el sistema servidor,que define a la ruta del directorio
 compartido y a partir de este todos son marcados como v-nodes que apuntan
 a r-nodes o nodos remotos.

 En el caso de una llamada {\em open()} a un archivo que se encuentra
 en parte de la jerarqu\'\i a donde est\'a un directorio importado de un
 servidor NFS, al hacer la llamada, en alg\'un momento de la
 comprobaci\'on de la ruta en el VFS, se llegara al v-node del archivo
 y se ver\'a que este corresponde a una conexi\'on NFS, procediendo a la solicitud
 de dicho archivo mediante opciones de lectura, se ejecuta el c\'odigo especificad
o por VFS para las opciones de lectura de NFS.
 
En cuanto al manejo de las caches que se suelen implementar en los clientes
 depende de cada caso espec\'\i fico. Se suelen utilizar paquetes de 8KB en
 las transferencias de los archivos, de modo que para las operaciones de
 lectura y escritura se espera a que estos 8KB est\'en llenos antes de enviar
 nada, salvo en el caso de que se cierre el archivo.
 Cada implementaci\'on establece un mecanismo simple de {\em timeouts}
 para las caches de los clientes de modo que se evite un poco el trafico
 de la red.

 La cache no es consistente, los ficheros peque\~{n}os se llaman en una cache
 distinta a esos 8KB y cuando un cliente accede a un fichero al que accedi\'o
 poco tiempo atr\'as y a\'un se mantiene en esas caches, se accede a esas caches
 en vez de la versi\'on del servidor. Esto hace que en el caso de ficheros
 que no hayan sido actualizados se gane el tiempo que se tarda en llegar
 hasta el servidor y se ahorre tr\'afico en la red.
 El problema es que produce inconsistencias en la memoria cache puesto que
 si otro ordenador modific\'o esos ficheros, nuestro ordenador no va a ver
 los datos modificados sino que leer\'a la copia local.

 Esto puede crear muchos problemas y es uno de los puntos que m\'as se le
 discute a NFS, este problema es el que ha llevado a desarrollar MFS pues
 se necesitaba un sistema que mantuviera consistencia de caches.

 \item {\bf MFS.}

Este es el sistema de ficheros que se desarroll\'o para openMosix en espera de
 alguno mejor para poder hacer uso de una de sus t\'ecnicas de balanceo, DFSA.
 Este sistema funciona sobre los sistemas de ficheros locales y permite
 el acceso desde los dem\'as nodos.
 
 Cuando se instala, se dispone de un nuevo directorio que tendr\'a varios
 subdirectorios con los n\'umeros de los nodos, en cada uno de esos subdirectorios
 se tiene todo sistema de ficheros del nodo en cuesti\'on\footnote{
 Por ejemplo si tenemos MFS montado en {\em /mfs}, entonces {\em
 /mfs/3/usr/src/linux/} es el directorio {\em /usr/src/linux/} del nodo 3.}.
 Esto hace que este sistema de ficheros sea gen\'erico pues {\em /usr/src/linux/}
 podr\'\i a estar montado sobre cualquier sistema de ficheros; y escalable, pues
 cada nodo puede ser potencialmente servidor y cliente.

A diferencia de NFS provee una consistencia de cache entre procesos
 que est\'an ejecut\'andose en nodos diferentes, esto se consigue
 manteniendo una sola cache en el servidor.
 Las caches de GNU/Linux de disco y directorio son s\'olo usadas en el servidor
 y no en los clientes. As\'\i\ se mantiene simple y escalable a cualquier n\'umero de procesos.
 
 El problema es una p\'erdida de rendimiento por la eliminaci\'on de las caches,
 sobre todo con tama\~{n}os de bloques peque\~{n}os.
 La interacci\'on entre el cliente y el servidor suele ser a nivel de llamadas
 del sistema lo que suele ser bueno para la mayor\'\i a de las operaciones de
 entrada/salida complejas y grandes.
 
Este sistema cumple con los criterios de transparencia de acceso, no cumple
 con los dem\'as.
 Tiene transparencia de acceso pues se puede acceder a estos ficheros con
 las mismas operaciones que a los ficheros locales.
 Los datos del cuadro 3.3 son del Postmark\footnote{{\tt
 http://www.netapp.com}} benchmark que simula grandes cargas al sistema de ficheros, sobre GNU/Linux
 2.2.16 y dos PCs Pentium 550 MHz\footnote{ {\em The MOSIX scalable
 cluster file systems for LINUX} de Lior Amar, Amnon Barak, Ariel Einzenberg y Amnon Shiloh.}:
\begin{table}
\begin{center}
\begin{tabular}{ | c | c | c | c | c | c | c | c | } \hline
M\'etodo de acceso & 64 & 512 & 1K & 2K & 4K & 8K & 16K \\ \hline \hline
Local & 102.6 & 102.1  & 100.0 & 102.2  & 100.2  & 100.2  & 101.0\\ \hline
MFS con DFSA & 104.8 & 104.0  & 103.9  & 104.0  & 104.9  & 105.5  & 104.4\\ \hline
MFS sin DFSA & 1711.0 & 169.1  & 158.0  & 161.3  & 156.0  & 159.5  & 157.5\\ \hline
NFS & 184.3 & 169.1  & 158.0  & 161.3  & 156.0  & 159.5  & 157.5\\ \hline
\end{tabular}
\caption{Sistemas Operativos. MFS}
\end{center}
\end{table}

 \item GFS:

Se basa en que las nuevas tecnolog\'\i as de redes (como fibra \'optica) permiten a
 muchas m\'aquinas compartir los dispositivos de almacenamiento.
 Los sistemas de ficheros para acceder a los ficheros de estos dispositivos
 se llaman sistemas de ficheros de dispositivos compartidos.
 Contrastan con los sistemas de ficheros distribuidos tradicionales donde
 el servidor controla los dispositivos (f\'\i sicamente unidos a \'el).
 El sistema parece ser local a cada nodo y GFS sincroniza los acceso a los
 ficheros a trav\'es del cluster.
 Existen dos modos de funcionamiento, uno con un servidor central (asim\'etrico)
 y otro sin \'el (sim\'etrico).
 
En el modo que necesita servidor central, \'este tiene el control sobre los
 metadatos (que es un directorio donde est\'an situados fechas de actualizaci\'on,
 permisos, etc.), los discos duros compartidos solamente contienen los datos.
 Por tanto todo pasa por el servidor, que es quien provee la sincronizaci\'on
 entre clientes, pues estos hacen las peticiones de modificaci\'on de metadata
 al servidor (abrir, cerrar, borrar, etc.) y leen los datos de los discos
 duros compartidos, es similar a un sistema de ficheros distribuido corriente.
En la figura 3.2 se muestra una configuraci\'on t\'\i pica de este sistema:
\end{itemize}
\begin{latexonly}
\ifpdf
        \begin{figure}[htbp]
        \includegraphics[bb = -100 210 0 0, scale=.83]{./pics/GFS.png}
        \vspace{2.5in}
        \caption{Sistemas operativos. GFS con servidor central}
        \end{figure}
\else
\end{latexonly}
        \begin{figure}
        \centering
        \includegraphics{pics/GFS}
        \caption{Sistemas operativos. GFS con servidor central}
        \end{figure}
\begin{latexonly}
\fi
\end{latexonly}
El modo que no necesita servidor central es llamado modo sim\'etrico, los
 discos contienen datos y metadatos, que son controlados por cada m\'aquina
 al ser accedidos, estos accesos son sincronizados gracias a locks globales,
 que se apoyan en la ayuda del hardware tanto por parte de SCSI (DMEP) como
 por parte del switch (DLM). Esto hace esta alternativa a\'un m\'as cara.
En la figura 3.3 se muestra un gr\'afico con una configuraci\'on t\'\i pica de este
 sistema. Se puede ver que la Network Storage Pool no tiene procesadores, pues est\'a
 directamente conectada a la red, gracias a fibra \'optica y SCSI.
 La {\em Storage Area Network} t\'\i picamente es un {\em switch} de
 alta velocidad).
\begin{latexonly}
\ifpdf
        \begin{figure}[htbp]
        \includegraphics[bb = -50 300 0 0, scale=1]{./pics/san.png}
        \vspace{4.2in}
        \caption{Sistemas operativos. SAN}
        \end{figure}
\else
\end{latexonly}
        \begin{figure}
        \centering
        \includegraphics{pics/san}
        \caption{Sistemas operativos. SAN}
        \end{figure}
\begin{latexonly}
\fi
\end{latexonly}
Entre las caracter\'\i sticas que este sistema de ficheros se encuentra
 que no hay un solo punto de fallo, si un cliente falla, o si incluso muchos
 clientes quedasen inutilizables, el sistema de ficheros estar\'\i a todav\'\i a
 ah\'\i  accesible a todos los clientes que a\'un estuvieran funcionando.
 Gracias a que los discos est\'an compartidos por todos los clientes todos
 los datos a los que los clientes que dieron error estaban accediendo est\'an
 todav\'\i a a disposici\'on de los clientes que est\'en funcionando.

\begin{itemize}
 \item Cada cliente puede acceder a cualquier parte de los datos (cualquier disco),
 por lo tanto se facilita la migraci\'on de procesos pues ya no hay que tener
 en cuenta si llevar con el proceso los ficheros abiertos o no y no hay
 que dejar en el nodo origen informaci\'on sobre ficheros abiertos.

 \item Usando t\'ecnicas de LVM ({\em Logic Volume Management}) se
 pueden unir varios de los discos duros en uno solo, simplificando el
 control de los dispositivos de almacenamiento y reduciendo la
 complejidad de la administraci\'on.

 \item Aumenta la escalabilidad en capacidad, conectividad y ancho de banda con
 respecto a otros sistemas como NFS que est\'an basados en servidores centrales.

 \item Es un sistema de ficheros {\em journaled}, un espacio
{\em journaled} para cada cliente para evitar que sea tan ineficiente,
adem\'as se env\'\i a la informaci\'on por grupos y se intenta mejorar el I/O clustering, y tiene
 capacidad de una recuperaci\'on r\'apida de los fallos de los clientes, gracias
 a los distintos espacios {\em journaled}, s\'olo los tiene que
 reparar secuencialmente , no importa que caigan gran n\'umero de nodos.
 No se pierde informaci\'on.

 \item Requiere hardware muy caro, fibra \'optica, {\em switch/hub} de
 alta velocidad, SCSI (normalmente RAID SCSI)
\end{itemize}
Aunque de todos estos puntos solo el \'ultimo sea negativo es una raz\'on bastante
 fuerte y relega al uso de este sistema para empresas con gran presupuesto
 que no quieran usar un servidor centralizado.
 
Este sistema de ficheros cumple todas las transparencias explicadas al principio
 de la lecci\'on, en el caso de haber un servidor central este es el que no
 cumple los criterios de transparencia pero en la parte de los clientes
 si los cumple pues no saben d\'onde est\'an los ficheros (transparencia de
 acceso), se podr\'\i an cambiar de disco duro sin problema (transparencia de
 localizaci\'on), si un nodo falla el sistema se recupera (transparencia a
 fallos), varios clientes pueden acceder al mismo fichero (transparencia
 de concurrencia) y se mantienen caches en los clientes (transparencia de
 r\'eplica).
%===========================================================================
\subsection{Entrada salida}
En un sistema tradicional, la entrada/salida es local al nodo en el que
 se produce, pero desde la aparici\'on de las redes se han venido aprovechando
 \'estas para acceder a determinados recursos de entrada/salida colocados
 en un ordenador distante.
 
 Por ejemplo es t\'\i pico en las empresas comprar una \'unica impresora cara
 para obtener la mejor calidad posible y dejar que esa impresora sea accedida
 desde cualquier ordenador de la intranet de la empresa, aunque esto significa
 el desplazamiento f\'\i sico de los empleados. Puede ser un ahorro considerable
 a instalar una impresora en cada uno de los ordenadores.

El problema es que para este ejemplo se ha desarrollado una soluci\'on
 espec\'\i fica que necesita un demonio escuchando peticiones en un determinado
 puerto. Desarrollar una soluci\'on general es mucho m\'as complejo y quiz\'as incluso
 no deseable.
 Para que cualquier nodo pueda acceder a cualquier recurso de entrada/salida,
 primero se necesita una sincronizaci\'on que como ya se ha visto en una secci\'on
 anterior de este cap\'\i tulo puede llegar a ser complejo.
 Pero tambi\'en se necesita conocer los recursos de entrada/salida de los que se dispone, una forma de nombrarlos de forma \'unica a trav\'es
 del cluster, etc.

Para el caso concreto de migraci\'on de procesos el acceso a entrada/salida
 puede evitar que un proceso en concreto migre, o m\'as convenientemente los
 procesos deber\'\i an migrar al nodo donde est\'en realizando toda su entrada/salida
 para evitar que todos los datos a los que est\'an accediendo tengan que viajar
 por la red.
 As\'\i\  por ejemplo un proceso en openMosix que est\'e muy vinculado al hardware
 de entrada/salida no migrar\'a nunca (Xwindow, lpd, etc.).
 Los sockets como caso especial de entrada/salida tambi\'en plantean muchos
 problemas porque hay servicios que est\'an escuchando un determinado puerto
 en un determinado ordenador para los que migrar ser\'\i a catastr\'ofico pues
 no se encontrar\'\i an los servicios disponibles para los ordenadores que accedieran a ese nodo en busca del servicio.