Professional Documents
Culture Documents
Indice
1 I File System Distribuiti 1.1 Tipologie di servizio . . . . . . . . . . . . . . . 1.1.1 Servizio con informazione di stato . . . 1.1.2 Servizio senza informazione di stato . . 1.1.3 Fault tollerance . . . . . . . . . . . . . 1.1.4 Conclusioni . . . . . . . . . . . . . . . . 1.2 Requisiti di un File System Distribuito . . . . 1.3 Semantica della consistenza . . . . . . . . . . 1.3.1 Semantica UNIX . . . . . . . . . . . . . 1.3.2 Semantica delle sessioni . . . . . . . . 1.3.3 Semantica dei le condivisi immutabili 1.3.4 Semantica debole . . . . . . . . . . . . 1.4 Problematiche . . . . . . . . . . . . . . . . . . 1.4.1 Problematiche di primo livello . . . . . 1.4.2 Problematiche di secondo livello . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 5 5 6 6 6 7 8 8 8 8 9 9 9 11 11 12 13 13 14 14 15 15 16 17 17 17 17 18 19 19 19 20 20 21 21 22 23 23 23
2 Andrew File System 2.1 Generalit . . . . . . . . . . . . . . . . . . . . . 2.2 Operazione su le e semantica della consistenza 2.3 Dettagli implementativi . . . . . . . . . . . . . . 2.3.1 Spazio dei nomi condiviso . . . . . . . . . 2.3.2 Kernel, server e cache manager . . . . . 2.4 Conclusioni . . . . . . . . . . . . . . . . . . . . . 3 Coda File System 3.1 Interazione dei componenti . . . 3.2 Caratteristiche . . . . . . . . . . 3.2.1 Scalabilit e performance 3.2.2 Robustezza . . . . . . . . 3.2.3 Consistenza e caching . . 3.3 Replicazione dei server . . . . . 3.4 Disconnected Operations . . . . 3.5 Conclusioni . . . . . . . . . . . . 4 InterMezzo File System 4.1 Linee progettuali . . . 4.2 Panoramica . . . . . . 4.3 File sets . . . . . . . . 4.4 Server and client . . . 4.5 Journaling e ltering 4.6 Dettagli sul caching . 4.6.1 Lento . . . . . 4.7 Conclusioni . . . . . . 4.8 Curiosit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 Rimozione dei Bottleneck 5.1 Panoramica . . . . . . . . . . . . . . 5.2 Consistenza dei dati . . . . . . . . . 5.3 Callback a livello kernel . . . . . . . 5.4 Write back caching a livello utente 5.5 Write back caching a livello kernel .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
24 24 25 26 27 27 28 28 30 32 34 34 34 35 38 39 40 41 42 42 43
6 Coda Client internals 6.1 La funzione coda_open() . . . . . . . . . . . . . . . . . . . . 6.1.1 Strutture di supporto alle routine contenute in upcall.c . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.1.2 coda_upcall() . . . . . . . . . . . . . . . . . . . . . . 6.2 Venus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Coda Server Internals 7.1 Volume Structure . . . 7.1.1 RVM structures 7.1.2 VM structures . 7.2 Callbacks . . . . . . . . 7.3 RPC processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A Mosix File System A.1 Direct File System Access . . . . . . . . . . . . . . . . . . . A.2 Caratteristiche di Mosix File System . . . . . . . . . . . . A.3 Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . .
Nel primo caso parleremo di servizio con informazione di stato (statefull), mentre nel secondo diremo che si tratta di un servizio senza informazione di stato (stateless). 1.1.1 Servizio con informazione di stato
Prima di accedere a un le, un client deve eseguire unoperazione di apertura su quel le. Il server preleva dal suo disco alcune informazioni sul le, le registra nella propria memoria e fornisce al client un identicatore di connessione, unico per quel client e quel le aperto. Questo identicatore viene usato per gli accessi successivi, no al termine della sessione. Un servizio con informazione di stato viene descritto come una connessione tra il client e il server durante una sessione. Alla chiusura del le, oppure tramite un meccanismo di garbage collection, il server pu reclamare lo spazio di memoria principale utilizzato da client che non sono pi attivi. Il vantaggio offerto dal servizio con informazione di stato dato dalle migliori prestazioni. Linformazione su di un le sottoposta a caching in memoria centrale ed possibile accedervi tramite lidenticatore di connessione, risparmiando cos accessi al disco. Inoltre un server con informazione di stato in grado di sapere se un le stato aperto per accesso sequenziale e pu quindi effettuare un pre-fetching dei blocchi successivi. 1.1.2 Servizio senza informazione di stato
Un server stateless evita linformazione di stato, rendendo ogni richiesta autocontenuta. Ci signica che ogni richiesta identica completamente il le e la posizione nel le (per accessi di lettura e scrittura). Il server non deve tenere in memoria principale una tabella di le aperti, anche se ci in effetti avviene per motivi di efcienza. Inoltre non necessario stabilire e terminare una connessione per mezzo delle operazioni di apertura e chiusura. Queste operazioni risultano del tutto superue, in quanto ogni operazione su le indipendente e non viene considerata parte di una sessione. Un processo client apre un le, ma tale apertura non causa la trasmissione di un messaggio remoto. Le letture e le scritture hanno luogo naturalmente come messaggi remoti, oppure come ricerche nella cache. La chiusura nale da parte del client (come la open()) soltanto unoperazione locale. Per ci che concerne invece le prestazioni, facile immaginare come queste possano essere inferiori a quelle di un server statefull; le motivazioni sono semplici: i messaggi di richiesta sono pi lunghi e quindi si ha pi overhead di rete Lelaborazione delle richieste pi lenta, in quanto non esiste alcuna informazione in memoria centrale utile al ne di accelerare lelaborazione
1.1.3
Fault tollerance
Come si pu facilmente immaginare, la tolleranza ai guasti dei due tipi di servizio alquanto diversa. Servizio statefull: in caso di guasti al server, si necessita di un protocollo di ripristino dello stato precedente, basato su un dialogo con i client o su un meno elegante abort di tutte le operazioni che erano in corso durante il vericarsi del guasto al server. Nel caso di guasti ai client, questi devono essere noticati al server, per dar via alla fase conosciuta come rilevamento ed eliminazione degli orfani. La conclusione che il fault tollerance risulta essere un processo alquanto tedioso. Servizio stateless: un server senza informazioni di stato non presenta gli stessi problemi di cui sopra ed in grado, subito dopo il ripristino, di rispondere senza problemi alle richieste, essendo esse stesse autocontenute. Una peculiarit che dal punto di vista dei client, non esiste alcuna differenza tra un server lento e uno in via di ripristino. 1.1.4 Conclusioni
Un server statefull risulta essere pi performante, ma a suo discapito giocano le procedure di fault tollerance troppo onerose in termini di tempo; daltro canto un server stateless pur non avendo particolari problemi con il fault tollerance, risulta essere prestazionalmente inferiore alla prima tipologia. Come in ogni caso, la scelta dettata dalla particolare esigenza del caso, anche se possiamo affermare che in gran parte si preferisce una migliore tolleranza ai guasti piuttosto che prestazioni estreme.
disponibilit del servizio di File Sharing anche in presenza di reti non perfettamente afdabili Ai requisiti appena elencati, se ne aggiunge uno particolarmente importante per un le system distribuito: la trasparenza. La crucialit di questo requisito dovuta al fatto che un DFS deve apparire ai client come un convenzionale le system centralizzato: la molteplicit e la dispersione dei server e dei dispositivi di memorizzazione devono essere rese trasparenti linterfaccia dei client di un DFS non deve distinguere tra i le locali e le remoti. Ci nei moderni sistemi operativi reso possibile dalla presenza del VFS (Virtual File System) La trasparenza una caratteristica poliedrica: compito del DFS localizzare i le e predisporre il trasporto dei dati trasparenza di piattaforma: il DFS deve permettere la condivisione a prescindere da sistema operativo e hardware delle singole unit di rete trasparenza di accesso: gli utenti non devono curarsi del tipo di accesso (locale o remoto) ad un le system trasparenza di locazione: il nome di un le non deve rivelare alcuna informazione sulleffettiva locazione sica del le e lURI non deve essere modicata se cambia la posizione sica dello stesso trasparenza di mobilit: i programmi devono funzionare anche se vengono spostati da un server allaltro (previa compatibilit di architettura e supporto per il formato eseguibile) trasparenza delle prestazioni: le prestazioni di un DFS, dal punto di vista del client, devono essere paragonabili a quelle di un le system locale; inoltre le prestazioni devono poter essere aumentate per far fronte ad aumenti di carico di lavoro (scalabilit)
1.3.1
Semantica UNIX
Nella semantica UNIX vige la politica last write wins: lultima scrittura sul le quella che prevale su tutte le altre e pertanto ogni lettura successiva rietter sempre lultima operazione di scrittura avvenuta. Punti cardine di tale semantica sono i seguenti: le scritture su un le aperto da parte di un processo sono immediatamente visibili ad altri processi che hanno aperto contemporaneamente lo stesso le il le associato ad una singola immagine sica, vista quindi come una risorsa esclusiva. Il contendersi delle risorse causa ovvi ritardi ai processi utente. Lo svantaggio di questa semantica rapportata ai DFS che risulta impossibile rafforzare la semantica per un miglior adattamento al caso distribuito (lunica soluzione consisterebbe nel fare in modo che tutti gli accessi avvengano al server; ci palesemente inaccettabile). I DFS che hanno adottato questa semantica sono: Sprite, DCE/DFS. 1.3.2 Semantica delle sessioni
Questa semantica utilizzata da moderni le system distribuiti, quali AFS, AFS2, Coda e InterMezzo. Le scritture di un utente su un le aperto non sono immediatamente visibili agli altri utenti che hanno aperto tale le in contemporanea; alla chiusura del le stesso, le modiche apportate saranno visibili solo nelle sessioni che inizieranno successivamente quella in chiusura. Questa semantica fa s che un le sia associato a pi immagini siche, probabilmente diverse, nello stesso momento. Ci favorisce gli accessi concorrenti in lettura/scrittura, riducendo cos i ritardi. 1.3.3 Semantica dei le condivisi immutabili
Questa una semantica di semplice implementazione: un le condiviso diviene immutabile nel nome e nel contenuto, ma resta possibile accedere contemporaneamente in sola lettura ai le condivisi. 1.3.4 Semantica debole
Si tratta di una semantica poco precisa e poco restrittiva, basata su criteri non troppo rafnati, come laging, il timeout, etc. Questo tipo di semantica utilizzata da le system di rete come NFS e SMB/CIFS.
1.4 Problematiche
Le problematiche inerenti alla progettazione e relativa implementazione di un le system distribuito si possono distinguere in due categorie: problematiche di primo livello e problematiche di secondo livello. Nella prima categoria rientrano tutte quelle problematiche che si incontrano nel voler implementare al meglio il le system, mentre nella seconda vi cadono le problematiche che sorgono dalla risoluzione dei problemi di primo livello (ad esempio, in seguito ad introduzioni di particolari features allinterno del DFS). Vediamo pi dettagliatamente cosa si intende. 1.4.1 Problematiche di primo livello
Massimizzazione delle prestazioni generali: possibile venire in contro a questa problematica facendo uso di caching e di servizi con informazione di stato. Massimizzare la disponibilit delle informazioni sul mapping (nome le, locazione di memoria): tale mapping necessario per limplementazione della nominazione trasparente. Per soddisfare tale esigenza possibile utilizzare metodi come la replicazione dei le oppure il caching locale. Mantenere gestibile il mapping (nome le, locazione di memoria): per fare ci possibile aggregare insieme di le in unit componenti pi grandi e fornire il mapping sulla base di tali componenti. In Unix si utilizza lalbero gerarchico delle directory per fornire il mapping: i le sono aggregati in directory in modo ricorsivo. 1.4.2 Problematiche di secondo livello
Lutilizzo di alcuni metodi per affrontare problematiche di primo livello (come il caching, la replicazione, etc.) inducono a problemi secondari, comunque non del tutto irrisolvibili. Il caching porta ad incappare nel problema di locazione della cache: quale il luogo migliore dove allocare una cache? Le possibilit sono due: cache su disco: questa locazione molto afdabile. Le modiche a dati sottoposti a caching non vanno perse in caso di guasti. Inoltre, dopo un ripristino non necessario ripopolare la cache, essendo essa non volatile. cache in memoria centrale: tale soluzione permette lutilizzo di stazioni diskless, un accesso pi veloce ai dati in cache e lutilizzo di un meccanismo unico per la gestione delle cache dei dati client e quelle dei dischi del server, il tutto a discapito dellafdabilit precedente.
Laltra problematica ancora una volta inerente al caching; nella fattispecie, si tratta dei problemi legati alla coerenza della cache. Un client deve decidere se una copia nella cache sia o meno coerente con la copia master. Qualora il client invalidasse i dati nella propria cache, i dati master dovranno essere sottoposti a un nuovo caching. Per vericare la validit dei dati sottoposti a caching possibile seguire due approcci: approccio iniziato dal client: il client inizia un controllo di validit nel quale contatta il server e controlla se i dati locali sono coerenti con la copia master. La frequenza del controllo di validit il fulcro di questo approccio e determina la conseguente semantica della consistenza. E possibile effettuare un controllo prima di ogni accesso, no a scendere a un solo controllo durante il primo accesso a un le (di solito allapertura del le). Ogni accesso che sia accoppiato a un controllo di validit risulta essere ritardato rispetto a un accesso servito immediatamente dalla memoria cache. In alternativa possibile iniziare un controllo a intervalli di tempo pressati. A seconda della frequenza di esecuzione il controllo di validit pu caricare sia la rete che il server. approccio iniziato dal server: il server registra le parti di le che sottopone a caching per ogni client. Quando il server individua una potenziale incoerenza, deve reagire. Tale potenziale incoerenza si verica quando un le viene sottoposto a caching da parte di due (o pi) client diversi con modalit conittuali. Se viene implementata la semantica delle sessioni (Paragrafo 1.4.2), ogni volta che un server riceve una richiesta per la chiusura di un le che stato modicato, deve reagire informando i client che i dati nella cache sono incoerenti e vanno scartati. I client che in quel momento hanno il le aperto scartano la loro copia non appena termina la sessione corrente. Altri client scartano instantaneamente la loro copia. Nel caso della semantica delle sessioni il server non deve essere informato delle aperture dei le gi sottoposti a caching. La reazione del server viene attivata solo dalla chiusura di una sessione di scrittura, e quindi viene ritardato solo questo tipo di sessione. In Andrew, come vedremo, essendo implementata proprio la semantica delle sessioni, viene utilizzato un approccio iniziato dal server, conosciuto col nome di callback. Inne, lultimo problema (da noi preso in esame) che cade in questa categoria di problematiche quello che nasce dallintroduzione della feature di le replication. Il problema dellaggiornamento delle repliche dei le, infatti, non pu essere minimamente tralasciato, poich dal punto di vista dellutente le repliche di un le indicano la stessa entit logica, e quindi laggiornamento apportato a una replica deve riettersi anche su tutte le altre. Pi precisamente, la relativa semantica della consistenza deve essere conservata quando gli accessi alle repliche sono considerati accessi virtuali al le logico originario. Se la coerenza non costituisce un fattore di importanza primaria, pu essere sacricata a vantaggio della disponibilit e 10
delle prestazioni. Si tratta della concretizzazione di un fondamentale compromesso nellambito della tolleranza ai guasti. Devessere fatta una scelta tra la conservazione della coerenza ad ogni costo, che implica la creazione di un potenziale blocco indenito, e il sacricio della coerenza nei casi di guasti catastroci a vantaggio di un procedere garantito.
2.1 Generalit
Andrew opera una distinzione tra macchine client (talvolta indicate col nome di workstation) e le macchine server dedicate. I server e i client utilizzano uno dei sistemi operativi supportati e sono collegati attraverso una LAN. I client sono prensentati con uno spazio di nomi di le partizionato: uno spazio di nomi locali e uno spazio di nomi condiviso. Server dedicati, chiamati nel loro insieme Vice (dal nome del software che eseguono), presentano ai client lo spazio dei nomi condivisi in forma di gerarchia di le: tale gerarchia omogenea e presenta caratteristiche di trasparenza di locazione. Lo spazio dei nomi locali il le system root di una stazione di lavoro, dal quale discende anche lo spazio dei nomi condiviso (a partire dal mountpoint /afs). Le workstation eseguono il protocollo Virtue per comunicare con i server Vice e devono possedere dischi locali in cui memorizzare il loro spazio di nomi locale. Linsieme dei server responsabile della memorizzazione e della gestione dello spazio dei nomi condiviso. Lo spazio dei nomi locale piccolo; ne esiste uno per ogni stazione di lavoro e ciascuno contiene programmi di sistema fondamentali per un funzionamento autonomo. Sono locali anche le temporanei e i le che il proprietario della stazione non vuole condividere.
11
Figura 1: Schema client/server di AFS Attraverso un esame pi ravvicinato, possibile notare che client e server sono strutturati in cluster interconnessi tramite una WAN. Ogni cluster formato da un insieme di stazioni di lavoro su una LAN e un rappresentante Vice, chiamato cluster server che collegato alla WAN. La decomposizione in cluster viene effettuata soprattutto in riferimento al problema di scala. Per ottenere delle prestazioni ottimali, le workstation devono utilizzare il server sul loro cluster per la maggior parte del tempo, cos da ridurre i riferimenti ai le intercluster.
Il caching viene ulteriormente sfruttato per aperture successive del le nella cache. Venus presuppone che gli elementi nella cache siano validi ntantoch non specicato diversamente; perci Venus, allapertura di un le, non deve contattare Vice per validare la copia della cache. Il meccanismo che supporta questa politica, chiamato callback, riduce drasticamente il numero delle richieste di validazione della cache ricevute dai server. Tale meccanismo funziona come segue: quando un client A sottopone a caching un elemento del le system, il server aggiorna la sua informazione di stato registrando lavvenuto caching; a questo punto il client A possiede un callback su quel le. Prima di permettere ad un altro client B di modicare il precedente le, il server informa il client A. Cos facendo, si dice che il server ha rimosso il callback per il client A. Un client pu effettuare una open() su un le nella cache solo se detiene un callback per lo stesso. Se un client chiude un le dopo averlo modicato, tutti gli altri client che stanno effettuando caching su questo le perdono i loro callback: quando questi client riapriranno il le dovranno ricevere dal server la versione aggiornata. Detto ci, palese che Venus contatta i server Vice solo allapertura di le non presenti nella cache (o i cui callback sono stati revocati) e alla chiusura di le modicati localmente. Sostanzialmente, AFS implementa la semantica delle sessioni.
Lo spazio di nomi condiviso di Andrew formato da unit componenti chiamate volumi. Generalmente i volumi di Andrew non sono piccoli, anzi, di norma sono associati ai le di un singolo client. Allinterno di una singola partizione del disco risiedono pochi volumi, che possono crescere e restringersi di dimensione. Dal punto di vista concettuale, i volumi vengono uniti tra loro per mezzo di un meccanismo simile al meccanismo di mount di UNIX, ma la differenza di granularit signicativa: in UNIX possibile montare soltanto unintera partizione. Un le o una directory Vice vengono identicati da un handle di basso livello, chiamatio d. Ogni elemento di directory mappa un path name su di un d. Un d una struttura dati lunga 96 bit, costitituita da tre elementi di uguale dimensione (32 bit): un numero di volume, un numero di vnode e un unicizzatore.
13
Figura 2: Schema della struttura di un d Il primo identica univocamente un volume, il secondo serve come puntatore alla tabella di inode di un volume, mentre il terzo elemento, lunicizzatore, permette di riutilizzare i numeri di vnode su tutti i volumi, mantenendo cos le strutture pi compatte. Cosa molto importante: i d sono trasparenti alla locazione, quindi lo spostamento di le da server a server non invalida il contenuto delle cache. 2.3.2 Kernel, server e cache manager
I processi client sono interfacciati ad un kernel con il solito set di system call. I kernel sono leggermenti modicati per individuare i riferimenti ai le Vice e per inviare richieste al processo Venus, il cache manager di Andrew. Venus e i processi server accedono ai le direttamente tramite inode, per evitare il costo della risoluzione del pathname. Poich linterfaccia inode non normalmente visibile ai processi, sono state aggiunte nuove system call. Venus incaricato in realt di gestire non una, ma due cache differenti: la prima utlizzata per i dati mentre la seconda per tenere traccia dello stato del sistema. Per contenere la dimensione di dette cache, viene utilizzato un semplice algortimo LRU (Least Recently Used). Per ci che concerne il server, esso consiste di un singolo processo multithreaded, capace quindi di servire concorrentemente le molteplici richieste inviate dalle macchine client. La scelta di un singolo processo multithreaded piuttosto di una soluzione a multiprocesso permette il caching delle strutture dati necessarie per soddisfare le richieste di servizio. Questo s un vantaggio in termini prestazionali, ma che purtroppo sacrica la tolleranza ai guasti: se il processo muore, il server si blocca.
2.4 Conclusioni
Giunti a questo punto, chiuderemo questa panoramica su AFS con un elenco dei vantaggi introdotti rispetto a le system come NFS, etc. Ogni client ha la stessa visione dei le, in qualsiasi punto si trovi, grazie alla radice comune di AFS. Ne segue la propriet di mobilit dei client: i client possono accedere da qualsiasi stazione di lavoro a qualsiasi le che si trovi nello spazio di nomi condiviso. Maggiori performance grazie alla cache locale responsabile della riduzione del carico di rete 14
Maggiore scalabilit Maggiore sicurezza ( utilizzato un sistema di autenticazione Kerberos, per brevit non trattato in questarticolo) Ammette replicazione dei volumi, garatendo maggiore disponibilit e sicurezza
15
Figura 4: Schema dellinvocazione di una system call open/close Osservando la gura, vediamo che, come ci aspettavamo, linterfaccia immediatamente disponibile allapplicazione quella del Virtual File System, ormai componenente standard di tutti i sistemi operativi. Una volta invocata la open() del VFS (1) su di un le facente parte di un le system Coda, allinterno del kernel viene eseguita limplementazione Coda di tale metodo (2); Coda contatta il cache manager Venus (3) per vericare se si sta aprendo un le gi sottoposto a caching, vericare quindi lo stato dei callback relativi e in ogni caso vericare la consistenza; nellesempio della gura, il le non in cache e Venus contatta un server Vice (4) per il prelievo dello stesso; il server invia il le al cache manager (5) che a sua volta ritorna alla routine di open di Coda; Coda, attraverso il VFS, ritorna il risultato della open() allapplicazione lato client. Da questo semplice esempio facile notare che la open() (e anche la close()) sono dei colli di bottiglia per il le system Coda; infatti, oltre ai due cambi di contesto classici per linvocazione di una system call (user->kernel e kernel->user), ad ogni invocazione di una open/close si deve effettuare un nuovo context switch per contattare il processo Venus e ancora un altro cambio di contesto per ritornare a livello kernel. Vedremo successivamente, nel capitolo dedicato ai Bottleneck, come questo overhead sia tuttaltro che trascurabile.
3.2 Caratteristiche
Coda stato progettato al ne di realizzare un le system che avesse delle ben determinate caratteristiche, in parte ereditate da AFS e in parte modicate e/o aggiunte al solo scopo di avere un le system distribuito pi moderno, essibile e scalabile dei suoi predecessori.
16
3.2.1
Scalabilit e performance
La scalabilit e le performance erano gi un obiettivo elegantemente raggiunto da AFS (progenitore di Coda). Come sempre, per, possibile fare di meglio. Oltre alla gi ottima scalabilit di AFS (ottenuta grazie al sistema di suddivisione della rete in cluster gi visto nel capitolo 2) Coda introduce delle nuove feature molto interessanti: le Disconnected Operations che, come vedremo pi avanti, permettono un migliore supporto alle reti con poca larghezza di banda e un supporto trasparente al lavoro off-line. 3.2.2 Robustezza
Coda raggiunge lobiettivo di aumentare la robustezza del sistema allo stesso modo di AFS, adottando una politica di replicazione dei server, ma fornendo una risoluzione migliore dei conitti server/server. Come vedremo nei paragra successivi, Coda utilizza come unit di replicazione base il volume, allo stesso modo del suo antenato. 3.2.3 Consistenza e caching
Il modello di consistenza lennesima caratteristica simile ad AFS; in ogni caso la semantica della consistenza adottata ancora la semantica delle sessioni. Il meccanismo di caching ancora il callback mentre, nelle ultime versioni di Coda, viene introdotto il write-back in luogo del write-through come metodo di copia dei dati dalla cache alla master copy. Unaltra innovazione di Coda sono gli sticky les in cache: possibile, per un client, specicare quali le non devono essere mai rimossi dalla cache, anche quando il principio di localit dei riferimenti suggerirebbe la rimozione del le.
17
no in time-out); verr reintegrato quando Venus riuscir a ristabilire la connessione. La strategia di replicazione adottata una variante dellapproccio readone, write-all. Quando viene chiuso un le che ha subito modiche, esso viene trasferito a tutti i membri dellAVSG a cui si sta facendo capo. Questo tipo di approccio massimizza la probabilt che ogni replica abbia sempre i dati aggiornati. Il rovescio della medaglia la latenza nella propagazione della sincronizzazione, che viene limitata adoperando un meccanismo di chiamate parallele a procedure remote (parallel-RPC).
Figura 5: Diagramma degli stati delle fasi di disconnessione/riconnessione Come possibile vedere anche dalla gura, la disconnessione pu avvenire in due punti: durante la fase di reintegrazione dei dati e durante la fase di tesaurizzazione (la fase di normale funzionamento connesso del le system). Ogniqualvolta si verica la disconnessione, il sistema passa nella fase di emulazione, che rende solitamente la disconnessione trasparente allutente. Non appena possibile ristabilire la connessione si passa nella fase di reintegrazione, che una volta completa lascia il posto alla fase 18
di comportamento normale, quella di tesaurizzazione. C da aggiungere che la disconnessione non permette soltanto di rendere trasparenti e meno ostacolanti taluni guasti di rete (o ai server), ma lascia la possibilit agli utenti di notebook connessi al sistema di potersi disconnettere volutamente e poter continuare ugualmente a lavorare restando isolati dai server Coda anche per un lungo periodo di tempo. Inne, grazie alle disconnected operations, Coda risolve un problema che il suo progenitore aveva rimasto irrisolto: possibile lavorare tranquillamente con reti a basse performance.
3.5 Conclusioni
Concludendo, Coda assolve molto bene ai suoi obiettivi primari, come lalta scalabilit e lalta disponibilit. La prima garantita dalle caratteristiche ereditate da AFS alle quali si aggiungono le Disconnected Operations, la Reintegrazione e il WriteBack Caching; la seconda garantita dal meccanismo di replicazione. E superuo dire che Coda non affatto perfetto nella sua implementazione. Uno degli svantaggi pi evidenti di questo le system distribuito stato gi citato precedentemente: si tratta delloverhead introdotto dallinvocazione delle system call di open() e di close(), che invocano sincronamente il cache manager ad ogni chiamata.
introduzione di metadati atti a supportare meglio le operazioni off-line creare un meccaniscmo unico per le due differenti politiche di caching (lato client e lato server) Pi avanti chiariremo meglio questi aspetti. Vediamo ora brevemente quali sono i servizi offerti da questo le system e quali sono le sue caratteristiche peculiari.
4.2 Panoramica
Innanzitutto InterMezzo, come gi detto, non elimina nessuna delle caratteristiche del suo le system di riferimento: Coda. Quello che invece tenta di fare di rendere il tutto pi performante con lobiettivo primario di portare InterMezzo ad essere un le system distribuito dalle prestazioni paragonabili a quelle di un le system centralizzato. In aggiunta alle gi viste e riviste caratteristiche di Coda e AFS (multiserver, sicurezza, etc.), InterMezzo aggiunge un miglioramento delle performance ottenuto anche attraverso la minimizzazione delle interazioni di rete, grazie soprattutto alla riduzione di comunicazione con il cache manager. Inoltre, per rendere pi efcienti le interazioni di rete che comunque restano dobbligo, stato anche ottimizzato il protocollo di messagistica. Inne, come vedremo nel seguito, allereditata ottima semantica di condivisione viene aggiunto un buon supporto al versioning e viene leggermento esteso il concetto di volume.
Quando intermezzo viene montato, Presto viene informato circa il tipo di le system che esso deve incapsulare, in modo tale da instanziare la giusta implementazione dei metodi del Virtual File System. La realizzazione lato kernel di InterMezzo (e quindi quella di Presto), prevede infatti limplementazione differenziata dei metodi del VFS (metodi delle strutture dentry, inode, le object, etc.) per ognuno dei le system centralizzati da incapsulare. Concludendo, il compito di Presto quello di ltrare tutti gli accessi e di effettuare il journaling di tutte le modiche svolte in cache, eccezion fatta per quelle fatte dal cache manager Lento (esse restano immuni dal ltering e dal journaling).
22
4.6.1
Lento
Le operazioni effettuate da client e server non sono del tutto simmetriche, pertanto Lento, in esecuzione sia sui client che sui server, deve essere in grado di offrire: File Service, ovvero fetching (nel caso di esecuzione su client) e backfetching (nel caso di esecuzione su server) di le e directory Reintegration Service, ovvero ricezione dei Client Modication Log (se in esecuzione su server) e notica delle modiche per la reintegrazione (se in esecuzione su client) Le richieste che Lento riceve sia da remoto che dallhost su cui in esecuzione, non vengono gestite secondo il modello di processo unico multi-threaded, ma mediante lutilizzo delle sessioni. Quando giunge una richiesta, viene istanziata una sessione per gestirla; una sessione non un thread, ma una struttura dati contenente stati e gestori di eventi. Le operazioni di I/O vengono eseguite in maniera asincrona e il kernel segnala il completamento di unoperazione tramite il dispatch di eventi. Il kernel, inoltre, attiva tutti i gestori di eventi ed anche responsabile del garbage collection delle sessioni che non possono essere raggiunte da alcun evento (a causa di anomalie presentatesi nella gestione delle stesse, per guasti o quanaltro).
4.7 Conclusioni
Come fatto nora, concluderemo riassumendo brevemente i vantaggi e gli svantaggi del le system. Per quanto concerne i primi, InterMezzo eredita tutti i vantaggi del le system distribuito a cui si ispira: Coda. A tali vantaggi duopo aggiungere laumento di performance dovuto allintroduzione di un nuovo livello1 di callback tra il kernel e il cache manager. Ci riduce notevolemente loverhead presente prima in Coda durante le chiamate di servizio open() e close(). Per quanto riguarda gli svantaggi, essi sono per lo pi da attribuire a Lento, il cache manager. Esso implementato in Perl, che un linguaggio interpretato. In pi la sua congurazione abbastanza difcoltosa e le operazione di rete leggermente lente.
4.8 Curiosit
Una curiosit che potrebbe nascere nel leggere i nomi delle componenti di InterMezzo, capire qual lorigine di questi termini. La risposta non cos difcile, soprattutto per chi si intende di musica. Infatti, tutti i nomi, compresi quello del le system stesso, sono termini utilizzati nel gergo musicale. Lintermezzo pu essere una breve composizione pianistica in forma
1 Questo nuovo layer vede la sua implementazione nel ltro Presto (Vivace, ricordiamo, per i sistemi Windows).
23
libera o comunque un interludio, mentre nomi come lento, presto o vivace indicano la velocit di esecuzione di una musica; i server portano il nome di Maestro.
5.1 Panoramica
Quando si mira ad un utilizzo read-only di un le system, il problema cruciale quello di ottenere delle performance ottime durante la fase di warming della cache, durante la quale avvengono tutti i cache miss iniziali3 . Purtroppo, si notato che Coda, anche con cache warmed, non riesce a raggiungere prestazioni paragonabili a quelle del le system ext2. Nel seguito mostreremo come una seconda relazione di callback tra kernel e cache manager (presente anche, come gi visto, nellimplementazione di InterMezzo) possa migliorare il comportamento di Coda visibilmente. Per quanto riguarda, invece, un utilizzo in lettura/scrittura del le system, il numero di bottleneck nei quali ci si imbatte sensibilmente maggiore. Questa volta sia il client caching che il server caching necessitano di opportune migliorie.
2 Il 3 Primo
le system locale preso di riferimento nel seguito ext2 del sistema operativo Linux accesso ai dati, prime risoluzioni di path name, etc.
24
Inoltre, la rete spesso coinvolta sincronamente e questo incide troppo sulle prestazioni generali; purtroppo anche lintroduzione del modello write-back in Coda non permette di raggiungere le performance ambite, nonostante il trafco RPC (e di conseguenza loverhead di rete) venga ridotto di molto. Ci dovuto ad altri fattori di rallentamento, come lo stesso Venus, il cache manager di Coda, che utilizza delle strutture proprietarie per il caching, invece di sfruttare il le system locale. La soluzione che porter allobiettivo ambito, come vedremo, consister nellutilizzare il le system locale come struttura dati per il caching e nel creare un modulo kernel che incapsuli il le system locale, permettendo quindi di creare il nuovo livello di callback tra kernel e cache manager. Tutto questo sfocer nella creazione del le system InterMezzo.
nel caso il controllo non termini con successo, il confronto viene ripetuto a livello di singolo le. Nella modalit con server replicati di Coda, inoltre, non basta memorizzare un solo version stamp, ma ogni client deve tenere un vettore di version stamp per ogni server del gruppo di replicazione. Il prezzo da pagare per lutilizzo di schemi a callback che il server deve mantenere in memoria virtuale lo stato circa quali client detengono quali callback.
26
ottimizzare ulteriormente Coda, a causa dei limiti intrinseci dovuti al progetto iniziale. Pertanto Peter J. Braam, sempre fermo sulla propria idea che un DFS potesse aspirare a performance vicine a quelle di un le system locale, decise di dare vita al progetto InterMezzo, ricalcando le stesse orme del progetto Coda. A vantaggio di InterMezzo ha giocato il fatto di essere nato come progetto ex-novo e non come semplice evoluzione di un precedente prodotto (come invece accaduto col passaggio da AFS a Coda). Grazie a questa peculiarit, stato possibile sin dalla progettazione iniziale tenere ben presenti le limitazioni di Coda, sia quelle gi risolte sia quelle ancora tuttora presenti (e di fatto non eliminabili). In realt le strutture dati che Coda utilizza per il caching frenano notevolmente le prestazioni5 . InterMezzo preferisce invece sperimentare luso di un le system locale come struttura dati per il persistent caching. Di fatto le strutture dati per il caching passano da un livello utente (dove tutto era incapsulato nel cache manager) a un livello kernel, senza per mai abbandonare la gura del cache manager user-level (cfr. paragrafo 4.6 e 4.6.1), che assume ovviamente fattezze diverse. Ricordiamo che InterMezzo non vuole assolutamente abbandonare ci che di vantaggioso presente in Coda: sono tuttora presenti in questo DFS il meccanismo dei write-back permit, lo schema a callback e i version stamp; questi ultimi, insieme alle informazioni di volume e alle Access Control List (ACL), vengono memorizzati nelle strutture dati del cache manager (Lento), non disponendo il le system locale di strutture atte a contenere tale informazioni sotto forma di metadati.
28
int coda_open(struct inode *coda_inode, struct file *coda_file) { struct file *host_file = NULL; struct inode *host_inode; /* altre variabili */ ... ... lock_kernel(); error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &host_file); ... /* controllo errori */ host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); host_inode = host_file->f_dentry->d_inode; ... unlock_kernel(); } La funzione coda_i2f(coda_inode) una funzione statica denita inline e viene mostrata di seguito: static __inline__ struct ViceFid *coda_i2f(struct inode *inode) { return &(ITOC(inode)->c_fid); }
Essa non fa altro che convertire un inode in un d (handle di basso livello per le e directory, introdotto gi in AFS). Come si evince dal codice appena riportato, il cuore della routine coda_open() la routine venus_open(). Tuttavia, prima di illustrare questultima funzione, bene parlare del contenuto del modulo upcall.c (al quale appartiene s detta funzione). In questo le troviamo un set di funzioni la cui rma della forma venus_<fileoperation>(); ne esiste una per ognuna delle coda_<fileoperation>() . Tutte queste funzioni richiamano al loro interno la funzione coda_upcall() che il cuore della connessione a Venus dal kernel e che comunica al cache manager loperazione giusta da fare, grazie ad una strut29
tura di tipo inputArgs opportunamente inizializzata dalle funzioni venus_<fileoperation>() e poi passata come parametro alla coda_upcall(). E possibile constatare quanto detto nella routine di seguito, la venus_open(). int venus_open(struct super_block *sb, struct ViceFid *fid, int flags, struct file **fh) { union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(open_by_fd); UPARG(CODA_OPEN_BY_FD); inp->coda_open.VFid = *fid; inp->coda_open.flags = flags; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); *fh = outp->coda_open_by_fd.fh; CODA_FREE(inp, insize); return error; }
Come si nota, gli inputArgs vengono opportunamente impostati al ne da identicare unoperazione di apertura le e poi vengono passati come parametro alla routine coda_upcall(). 6.1.1 Strutture di supporto alle routine contenute in upcall.c
Prima di mostrare la routine coda_upcall() bene mostrare alcune strutture utilizzate in molte delle routine contenute in upcall.c. typedef u_long VolumeId; typedef u_long VnodeId; typedef u_long Unique_t; typedef u_long FileVersion; typedef struct ViceFid { VolumeId Volume; VnodeId Vnode; Unique_t Unique; } ViceFid;
30
La struttura ViceFid rappresenta appunto il d, gi introdotto in AFS (cfr. paragrafo 2.3.1) ed ereditato da Coda senza alcuna modica. struct coda_sb_info { struct venus_comm * sbi_vcomm; struct super_block *sbi_sb; };
La struttura coda_sb_info appena mostrata mantiene informazioni sul superblocco ed un puntatore alla Venus wait queue. struct venus_comm { wait_queue_head_t vc_waitq; struct list_head vc_pending; struct list_head vc_processing; int vc_inuse; struct super_block *vc_sb; };
La struttura venus_comm incapsula - la wait queue del cache manager - la communication processing queue - la communication pending queue - vc_inuse indica se Venus ancora running La struttura upc_req incapsula un messaggio che CodaFS (kernel) e Venus si scambiano per la comunicazione e la cui dimensione deve essere pari ad almeno 5000 bytes. Abbiamo visto dalle strutture appena elencate, che la comunicazione tra Venus e la parte kernel di CodaFS avviene tramite uno scambio di messaggi. Limplementazione Unix di questo meccanismo stata fatta attraverso una pseudo-device a caratteri associata a Coda. Venus cattura i messaggi del kernel tramite una read() sulla device e risponde con una write() sulla stessa. Durante lo scambio di messaggi, il processo che ha chiamato la system call viene messo in uno stato di TASK_INTERRUPTIBLE.
31
struct upc_req { struct list_head uc_chain; caddr_t uc_data; u_short uc_flags; u_short uc_inSize; u_short uc_outSize; u_short uc_opcode; int uc_unique; wait_queue_head_t uc_sleep; unsigned long uc_posttime; }; 6.1.2 coda_upcall()
static int coda_upcall upcall(struct coda_sb_info *sbi,int inSize, int *outSize, union inputArgs *buffer) { struct venus_comm *vcommp; struct upc_req *req; vcommp = sbi->sbi_vcomm;
In questo primo frammento del codice relativo a coda_upcall() c da notare la dichiarazione e linizializzazione dei riferimenti alle code venus ed al messaggio che Venus e CodaFS si scambieranno. if ( !vcommp->vc_inuse ) { printk("No pseudo device in upcall comms at %p\n", vcommp); return -ENXIO; } Se Venus non risulta contattabile a causa di un crash o di qualche altro problema, si ritorna un errore.
32
req = upc_alloc(); if (!req) { printk("Failed to allocate upc_req structure\n"); return -ENOMEM; } req->uc_data = (void *)buffer; req->uc_flags = 0; req->uc_inSize = inSize; req->uc_outSize = *outSize ? *outSize : inSize; req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; req->uc_unique = ++vcommp->vc_seq; In questo frammento di codice viene mostrato come avviene lallocazione e la formattazione del messaggio da inviare a Venus; list_add(&(req->uc_chain), vcommp->vc_pending.prev); la chiamada a list_add() permette di aggiungere il messaggio alla coda di messaggi pending di Venus e di risvegliare il cache manager. wake_up_interruptible(&vcommp->vc_waitq);ing.prev); Il processo pu essere interrotto mentre si aspetta che Venus processi la sua richiesta: Se linterruzione avviene prima che Venus abbia letto la richiesta, questa viene eliminata dalla coda e si ritorna. Se linterruzione avviene dopo che Venus abbia preso atto della richiesta, viene ignorata In nessun caso la system call viene riavviata. Se Venus viene chiuso, si ritorna con ENODEV, coerentemente alla scelta che prevede lutilizzo di una pseudo-device come mezzo di scambio di messaggi. runtime = coda_waitfor_upcall(req, vcommp); CodaFS si mette in stato di attesa di segnali, che avranno comunque effetto solo dopo un timeout. La gestione degli errori nello specico viene omessa per brevit. Basti dire che vengono gestiti tutti i casi di interruzione sopra citati.
33
6.2 Venus
Dato che Venus non verr trattato negli internals, giusto spendere qualche parola in proposito. In relazione a quanto stato gi detto circa lo scambio di messaggi tra kernel e Venus c da aggiungere che una volta che Venus ha identicato il contenuto del messaggio, agisce di conseguenza, richiamando una routine correlata alloperazione incaricatagli. Tale routine effettua un controllo sulla coerenza della cache e, qualora fosse necessario, esegue una RPC del server Vice.
34
#define MAXVOLS 1024 struct camlib_recoverable_segment { bool_t already_initialized; struct VolHead VolumeList[MAXVOLS]; VnodeDiskObject *SmallVnodeFreeList[SMALLFREESIZE]; VnodeDiskObject *LargeVnodeFreeList[LARGEFREESIZE]; short SmallVnodeIndex; short LargeVnodeIndex; VolumeId MaxVolId; [] }; La costante MAXVOLS denisce il numero massimo di volumi in ogni partizione. La variabile booleana already_initialized indica se richiesta o meno linizializzazione del volume. Larray VolumeList rappresenta un array di headers di volumi. Le variabili SmallVnodeFreeList e LargeVnodeFreeList rappresentano delle liste di strutture vnode libere. MaxVolId rappresenta il massimo id di volume allocato su questo server. 7.1.1 RVM structures
La gura seguente mostra in maniera schematica alcune delle pi importanti strutture RVM:
35
Un volume viene identicato principalmente dal suo indice nellarray statico VolumeList. In alternativa si pu fare accesso ai volumi attraverso il loro id. La struttura VolHeader allinterno di VolHead permette di mappare un indice di VolumeList su un id di volume. struct VolHead { struct VolumeHeader header; struct VolumeData data; }; La struct VolumeHeader contiene delle informazioni che rappresentano metadati in RVM, mentre la struct VolumeData contiene informazioni utili a rappresentare il volume (ossia, informazioni sul versioning, id del volume, tipo del volume...). struct VolumeData { VolumeDiskData *volumeInfo; rec_smolist *smallVnodeLists; bit32 nsmallvnodes; bit32 nsmallLists; [...] };
Fatta eccezione per il campo volumeInfo, che punta ad una struct VolumeDiskData (descritta di seguito), tutti gli altri campi della struttura VolumeData possono essere compresi in maniera abbastanza intuitiva: il campo rec_smolist un puntatore ad un array di puntatori a liste di vnode il campo nsmallvnodes rappresenta il numero di vnode allocati sul volume il campo nsmallList rappresenta il numero di liste di vnode
36
typedef struct VolumeDiskData { struct versionStamp stamp; VolumeId id; [...] byte inUse; [...] byte blessed; [...] int type; VolumeId groupId; VolumeId cloneId; VolumeId backupId; byte needsCallback; [...] }
La struttura VolumeDiskData contiene informazioni di natura amministrativa che vengono memorizzate in RVM. I suoi campi possono essere cos descritti: stamp contiene informazioni utili al versioning id un identicativo del volume, univoco per tutti i sistemi inUse indica se il volume in uso (ossia on line) o se avvenuto un crash del sistema mentre lo si stava usando blessed una ag impostata da un utente con diritti amministrativi ed indica se il volume pu o meno essere messo on line type un intero i cui valori sono deniti dalle costanti RWVOL (volume read/write), ROVOL (volume read-only), BACKVOL (volume di backup) groupId rappresenta lidenticativo del gruppo di replicazione. Assume valore 0 se il volume non replicato cloneId rappresenta lidenticativo dellultimo clone read-only. Assume valore 0 se il volume non stato mai clonato backupId rappresenta lidenticativo dellultima copia di backup di questo volume read/write needsCallback una ag settata dal salvager se non cambiato niente sul volume
37
7.1.2
VM structures
In questo paragrafo focalizzeremo la nostra attenzione soltanto sulla struttura Volume, la cui descrizione risulta essere maggiormente propedeutica alla nostra analisi, rispetto a tutte le altre VM structures. struct Volume { VolumeId hashid; struct volHeader *header; struct DiskPartition *partition; [...] bit16 cacheCheck; short nUsers; [...] long updateTime; struct Lock lock; PROCESS writer; struct ResVolLock VolLock; [...] } Ad ogni volume associata una struct Volume che ne rappresenta il principale punto di accesso. Tali strutture vengono poi memorizzate tutte nellhashtable VolumeHashTable (cfr. paragrafo 7.2). I suoi campi possono essere cos descritti: hashid identicativo in VolumeHashTable
header un puntatore alla struttura volHeader che a sua volta contiene puntatori LRU e una struttura di tipo VolumeDiskData partition un puntatore ad una struttura contenente informazioni circa la partizione Unix su cui risiede il volume cacheCheck un sequence number utilizzato per invalidare la cache delle entry di vnode nel momento in cui il volume passa allo stato ofine nUsers rappresenta il numero di utenti di questo volume
updateTime il timestamp relativo a quando questo volume stato inserito nella lista dei volumi modicati lock rappresenta un lock a livello di volume utilizzato per il processo di resolution/repair writer lidenticativo del processo che ha acquisito il lock di scrittura 38
7.2 Callbacks
Il server tiene traccia degli host che sono up attraverso la tabella HostTable. Ogni entry della tabella contiene: una lista di connessioni un callback connection id timestamp dellultima chiamata da parte dellhost Il server tiene traccia delle callback concesse attraverso una hashtable di FileEntry e ogni qual volta viene concessa una callback ad un client, nella hashtable viene inserita una FileEntry che si riferisce al le relativo alla callback. Ogni File Entry contiene: un vice le id (ViceFid) il numero di utenti del le una lista di callback (struct CallbackEntry) Ogni CallbackEntry contiene una HostTable, attraverso la quale possibile noticare tutti i client che detengono la callback nel momento in cui il le viene modicato. Tutte le strutture relative alle callback sono gestite in VM. Di seguito descriveremo la routine AddCallBack che, come suggerisce il nome, richiamata nel momento in cui bisogna concedere ad un client una callback su un le. CallBackStatus AddCallBack(HostTable *client, ViceFid *afid) { char aVCB = (afid->Vnode == 0 && afid->Unique == 0);
Il primo parametro della funzione rappresenta lhostTable di un client a cui bisogna aggiungere la callback, mentre il secondo il vice le id del le a cui la callback si riferisce.
39
if (CheckLock(&tf->cblock)) { return(NoCallBack); }
struct FileEntry *tf = FindEntry(afid); if (!tf) { /* Create a new file entry. */ tf = GetFE(); tf->theFid = *afid; tf->users = 0; tf->callBacks = 0; long bucket = VHash(afid); tf->next = hashTable[bucket]; hashTable[bucket] = tf; } Verica se il server gi possiede (nella sua hashtable) un leEntry relativo ad afid. Se c, tf ne conserva il puntatore altrimenti viene creata una nuova FileEntry a cui tf punter che viene poi inserita nella hashtable. Non possibile invocare una AddCallBack annidata in una breackCallBack struct CallBackEntry *tc; for (tc = tf->callBacks; tc; tc = tc->next) if (tc->conn == client) return(CallBackSet); tf->users++; if (aVCB) VCBEs++; tc = GetCBE(); tc->next = tf->callBacks; tf->callBacks = tc; tc->conn = client; return(CallBackSet); } Scorre la lista di CallBackEntry relativa a tf per vericare se il client che si sta aggiungendo non sia gi presente ed ovviamente lo aggiunge soltanto se la ricerca ha dato esito negativo.
schematizzata nelle seguenti fasi: 1. Validazione dei parametri: questa fase (svolta dalla Routine ValidateParms() ) si occupa essenzialmente di vericare che i parametri passati via RPC siano compatibili con le strutture dati effettivamente utilizzate nella routine che mappa loperazione server associata a detta RPC. 2. GetObject: verica lintegrit del FID e recupero delloggetto corrispondete (routine GetFsObj() ) 3. Verica della semantica 4. Controllo sulla concorrenza 5. Controllo dellintegrit 6. Controllo sui permessi 7. Esecuzione delle operazioni: questa fase lunica contestuale alloperazione server 8. Inserimento oggetti: transazioni RVM, eliminazione i-node Tutte le operazioni server sono implementate da funzioni la cui rma ha la forma FS_Vice_<operation>() e per ognuna di queste funzioni, limplementazione dei punti 1, 2, 3, 5 sempre uguale. Ci che cambia, invece, limplementazione del punto 4 (perform operation). Ogni funzione suddetta richiama una Perform<operation>() diversa che svolge le operazioni speciche del caso. Tra le tante, si nota la particolarit della FS_Vice_Fetch() la cui perform operation consiste in uno stub vuoto, poich il fetch una conseguenza dellimplementazione del GetFsObj() (punto 2).
Mosix un estensione che permette a un cluster Linux o un computer grid di eseguire come se fosse un singolo computer multiprocessore. In questo capitolo, prenderemo come riferimento la versione Open Source di Mosix: OpenMosix. 7 La principale peculiarit del Mosix File System risiede nel fatto che non vi alcuna necessit di scrivere applicazioni ad hoc, poich tutte le estensioni risiedono nel kernel; pertanto tutte le applicazioni, mediante lintefaccia del VFS, godono automaticamente e trasparentemente dei beneci di OpenMosix. Il maggior punto di forza di OpenMOSIX rappresentato dallefcienza con cui esegue in maniera distribuita processi CPU-bound. Tuttavia, per
7 Tale
41
gestire in maniera altrettanto efciente anche i casi di processi I/O-bound, si possono utilizzare (sui singoli nodi) le system con supporto DFSA (Direct File System Access)
A.2
OpenMosix dotato di un proprio le system distribuito conforme alle speciche DFSA. Tale le system prende il nome di MFS (Mosix File System). La linea progettuale seguita dal creatore di Mosix File System consiste nello sviluppare un layer astratto che, poggiandosi sui le system residenti sui nodi, permetta di offrire agli utenti nali una visione unicata globale. Infatti Mosix File System non un un le system che scrive dati su un proprio disco ma, per lo storage, si basa su qualsiasi le system supportato da Linux. MFS permette un accesso parallelo ai le, mediante una distribuzione adeguata degli stessi. La differenza sostanziale tra MFS ed altri DFS (quali NFS, AFS, etc.) risiede nella migrazione dei processi e dei dati a cui essi fanno accesso: in MFS un processo migra verso i nodi che ospitano i le di cui necessita mentre con altri DFS sono i dati a seguire i processi. Come descritto dalla gura, con MFS, tutte le direcotry e le regolari di tutti i nodi sono disponibili da ogni nodo del cluster OpenMosix attraverso il mountpoint /mfs.
8 Tra
42
Figura 8: Struttura ad albero del le system di Mosix E possibile quindi copiare le tra i vari nodi o accedere a le residenti su nodi diversi, direttamente attraverso il suddetto mountpoint. Ci permette ad un processo migrato su un nodo remoto di poter eseguire chiamate di sistema (open, close, read, etc.) senza dover tornare sul nodo di origine. Al contrario di altri le system, MFS fornisce una consistenza per singolo nodo, mantenendo una sola cache sul (sui) server. Per implementare ci, le cache disco standard di Linux sono usate solo sul server e vengono bypassate sui client.
A.3 Conclusioni
Concludiamo questa breve panoramica su Mosix File Sysem elencando alcuni dei vantaggi e degli svantaggi a noi pervenuti durante la nostra analisi. Vantaggi: L approccio di caching, descritto nella precedente sezione, fornisce un semplice ma scalabile schema per la consistenza Le interazioni client-server avvengono a livello di system call; ci rende altamente performanti le operazioni di I/O molto grandi Svantaggi Nessun supporto per la alta disponibilit: il guasto di un nodo impedisce ogni accesso ai le del nodo stesso MFS nasce (e resta tale) per lutilizzo esclusivo in (Open)Mosix.
43
Le interazioni client-server a livello di system call sono a discapito di operazioni di I/O piccole, non essendo presenti cache sui client
Riferimenti bibliograci
[1] Distributed File Systems: Silberschatz, 1990 concepts and examples, E. Levy - A.
[2] Sistemi Operativi (Quinta Edizione), Silberschatz - Galvin, 1998 [3] Andrew: a distributed personal computing enviroment, J.H. Morris M. Satyanarayanan - M.H. Conner, 1986 [4] The MOSIX Direct File System Access Method for Supporting Scalable Cluster File Systems. Amar-Barak-Shiloh, 2003 [5] Removing Bottlnecks in Distributed File Systems: Coda & Intermezzo as examples, P. J. Braam - P. A. Nelson, 2000 [6] Coda: A Highly Available File System for a Distributed Worksation Environment, M. Satynarayanan, 1995 [7] The Coda Distributed File System, Linux Journal, June 1998 [8] Disconnected Operation in the Coda File System, James J. Kistler and M. Satyanarayanan, 1997 [9] Coda File System Web Site (http://www.coda.cs.cmu.edu) [10] The MOSIX Scalable Cluster File Systems for LINUX, Lior Amar et al., 1999 [11] Intermezzo Web Site (http://www.inter-mezzo.org)
44