|
Appunti informatica |
|
Visite: 1436 | Gradito: | [ Grande appunti ] |
Leggi anche appunti:Il computerIL COMPUTER ll personal computer (in italiano elaboratore personale), Architettura 8086dArchitettura 8086d Le operazioni aritmetiche e di comparazione si applicano La terza generazione: dal 60' al 68'La terza generazione: dal 60' al 68' La terza generazione di elaboratori |
BIOS, Partizioni e MBR
La partizione di un disco consiste nella suddivisione di un'unità fisica in più unità logiche, viste dal SO come unità virtualmente separate, da formattare e gestire eventualmente in modo indipendente.
Il BIOS (Basic Input Output System) è il primo programma eseguito all'accensione (nelle architetture PC IBM compatibili), scritto solitamente nell'assembly nativo della famiglia di CPU utilizzata, oggigiorno memorizzato su sopporti EEPROM (quindi aggiornabile) e normalmente considerato parte integrante del firmware (istruzioni o software integrati direttamente in un componente hardware). Il BIOS si occupa normalmente di eseguire test diagnostici dell'hardware, localizzare il SO e caricarlo in RAM, fornire una interfaccia di basso livello per l'accesso alle periferiche.
Come noto un disco è diviso in settori. Nel settore 0 o settore di avvio del disco (nelle architetture PC IBM compatibili) c'è il Master Boot Record (MBR) che in 512 byte contiene la sequenza di comandi necessaria ad avviare il SO dalla partizione segnata come attiva e, in coda, la tabella dei descrittori delle partizioni presenti su disco. Il primo settore di ogni partizione contiene le sue specifiche informazioni di inizializzazione ed è detto boot block; all'avvio il BIOS carica il MBR in RAM e lo esegue trasferendogli il controllo - se il disco è partizionato il MBR esegue un codice di selezione della partizione attiva che carica a sua volta il boot block di questa e le trasferisce il controllo - dopodichè viene lanciato il SO (il SO viene caricato quindi automaticamente ovunque si trovi all'interno di una qualunque partizione
File System
Il termine File (dall'inglese Archivio, Raccoglitore, Dossier) designa comunemente un insieme di dati, tipicamente correlati, trattati come un'entità unitaria residente in memoria secondaria. In realtà il file è un concetto logico realizzato mediante un meccanismo di astrazione: l'utente salva insiemi di dati sulla memoria secondaria designandoli con nomi logici univoci e distintivi, non gli interessa come ciò avvenga, vede e tratta solo nomi di file e può non aver bisogno di conoscerne l'effettiva struttura fisica sul supporto che le memorizza; le applicazioni che operano sui file richiedono essenzialmente la persistenza dei dati, la possibilità di condivisione dei dati tra applicazioni diverse, l'assenza di limiti (fissati a priori, almeno in teoria) nella dimensione dei dati.
Il File System (o FS) è la parte del SO preposta alla realizzazione, all'accesso, all'organizzazione e alla gestione dei file: esso definisce la struttura logica/fisica dei file, le operazioni ammissibili e le modalità di accesso ad essi, e dovrebbe essere sempre progettato in modo da fornire il supporto ai file in modo efficiente, economico e trasparente (garantendo cioè la massima indipendenza dall'architettura hardware sottostante) oltre a soddisfare le citate esigenze delle applicazioni. Il FS distingue tipicamente i file regolari (regular) - eseguibili (binari), contenenti testo (ASCII) o altro - su cui l'utente può operare normalmente, i file catalogo (directory) o cartella (folder) con i quali il FS realizza l'organizzazione di gruppi di file e i file speciali con i quali il FS rappresenta logicamente dispositivi orientati a carattere (porta seriale, terminale, ), dispositivi orientati a blocchi (porta parallela, disco, ) o altre entità speciali (pipe o socket): le directory in particolare hanno (come vedremo) un ruolo importante nella organizzazione del FS. Un FS è memorizzato su un disco e se il disco è partizionato ogni partizione può contenere un distinto FS: in DOS ogni supporto ha il suo indipendente FS e c'è quindi un'intera foresta di distinti FS, in UNIX il FS è un unico albero e ogni nuovo dispositivo collegato (indipendentemente dal tipo di supporto) viene ad innestarsi (si parla di mounting) su di esso. La stessa struttura interna di una partizione dipende dal FS adottato, secondo il seguente schema generale ricorrente
[ Boot Block - Superblock - Gestione Spazio Libero -
Gestione Spazio Occupato - Root Directory - File e Directory ]
in cui il boot block (come già accennato) carica il SO e lo esegue, il super block contiene informazioni sul tipo di FS adottato e i parametri fondamentali della sua organizzazione, una o più tabelle sono usate per la gestione dello spazio libero, una o più tabelle (non in tutti SO) sono usate per la gestione dello spazio occupato e, infine, seguono la cosiddetta directory radice e tutti gli altri file e directory.
Le strutture dati che costituiscono il contenuto di un file possono essere considerate a 3 distinti livelli: a livello utente un'applicazione associa in modo autonomo un signficato al contenuto grezzo di un file, a livello di struttura logica (a monte dell'interpretazione data dall'utente) il SO organizza i dati grezzi in strutture logiche (record nella fattispecie), a livello di struttura fisica il SO mappa le strutture logiche sulle strutture fisiche della memoria secondaria (per esempio settori e blocchi / cluster su disco
Un file è identificato da un nome, cioè una stringa di caratteri alfanumerici anche speciali (massimo 8 per DOS/base di Win9X, massimo 255 per altri Windows/UNIX) case insensitive (DOS e Windows) o case sensitive (UNIX), spesso seguito (separato da un punto) da un'estensione (in DOS massimo 3 caratteri). Il tipo di un file ne definisce implicitamente la qualità del contenuto e l'applicazione preposta al suo utilizzo: in DOS/Windows l'estensione è designante ovvero indica da sè il tipo del file (COM ed EXE eseguibili, BAT batch, ); in Unix l'estensione è viceversa solo informativa e il tipo è indicato dal valore dei primi 2 byte del file stesso, denominati magic number; in Mac OS infine il tipo è descritto all'interno di metadati (dati che descrivono altri dati) associati al file. Ad un file è in generale associato un Descrittore che ne contiene gli attributi - tipicamente la dimensione corrente, la data di creazione/ultima modifica, l'identificatore del processo creatore e del processo proprietario, un contatore di utilizzo che tiene nota degli utenti che condividono il file, i permessi di accesso (lettura, scrittura, esecuzione) eventualmente protetti con password, le modalità di accesso consentite indicate spesso da flag (Archive, Read Only, Hidden, System, Locked, Directory, Temporary, Contenuto ASCII / Binario, Accesso sequenziale / Random) - e chiaramente le informazioni di allocazione (o campo locazione) del file sul dispositivo di memorizzazione (più o meno articolate in base al tipo di allocazione fisica prescelta, vedi più avanti
Le possibili strutture logiche di un file (sequenza di byte, record a struttura fissa, record a struttura variabile) e le possibili modalità di accesso (sequenziale, diretto, indicizzato) sono tra loro interdipendenti. La sequenza di byte è la scelta (UNIX e Windows) più semplice, la meno onerosa per il SO e la più flessibile per l'utente: l'accesso ai dati avviene attraverso un puntatore al byte corrente, lettura e scrittura fondamentalmente operano a blocchi in modo sequenziale (a partire dalla posizione indicata dal puntatore RW), il significato dei blocchi di byte viene attribuito direttamente a livello applicativo. Il record a struttura (e quindi lunghezza) fissa è una scelta oggi obsoleta legata a vecchie architetture: la formattazione dei dati in record richiede che gli spazi vuoti siano riempiti da caratteri speciali (NULL o Space), l'accesso ai dati avviene attraverso un puntatore al record corrente, lettura e scrittura operano sul singolo record, il SO deve conoscere a priori la struttura interna del file. Il record a struttura (e quindi lunghezza) variabile è una scelta abbastanza diffusa in sistemi mainframe: la struttura di ogni record viene descritta/identificata da una chiave univoca, una tabella contiene le corrispondenze ordinate tra singola chiave e puntatore all'inizio di ciascun record, ogni accesso avviene per chiave. Con un accesso sequenziale, un puntatore indirizza il gruppo di byte o il record corrente e ad ogni lettura/scrittura il puntatore avanza indirizzando il gruppo/record successivo: la lettura può avvenire in qualunque posizione del file purchè vi si acceda sequenzialmente, la scrittura avviene in coda al file (Append Mode). Con un accesso diretto è possibile operare in una posizione arbitraria del file settando l'opportuno puntatore attraverso un offset definito rispetto alla base (offset = 0 punta all'inizio del file). Con un accesso indicizzato (in IBM denominato ISAM, Indexed Sequential Access Method) l'informazione di navigazione tra i dati non è più nei dati stessi ma in una struttura a parte, la ricerca binaria in una tabella ad accesso veloce (hash) fornisce la corrispondenza chiave offset cui segue un accesso diretto.
Le operazioni ammesse comunemente su un file sono riconducibili (anche le più complesse, come la copia) a operazioni elementari o loro combinazioni. In principio c'è la creazione, che produce un file inizialmente vuoto settando gli attributi (in mancanza di differenti specificazioni) ai valori di default. L'apertura deve precedere ogni uso e predispone delle strutture ausiliarie di controllo per l'accesso al file: il descrittore del file viene trasferito dalla directory entry (vedi più avanti) che lo contiene (o che lo punta) alla tabella dei file aperti gestita dal SO in RAM (e contenente appunto i descrittori di tutti i file aperti), viene allocato un buffer per i dati in transito da/verso il file e viene restituito al processo che ha aperto il file un handle, cioè un identificatore simbolico di accesso al file o un equivalente indirizzo fisico necessario ai successivi accessi. Il seek o ricerca posizione consente di ridefinire il puntatore di RW ed è utile solo ai fini dell'accesso casuale. Le operazioni di manipolazione del contenuto del file consistono in lettura (Read), scrittura (Write), scrittura in coda (Append) e azzeramento del contenuto del file senza la sua cancellazione (Trunc). La chiusura produce il rilascio (dalla RAM) delle strutture ausiliare di controllo e la rimozione del descrittore dalla tabella dei file aperti con conseguente aggiornamento della directory entry su disco. Le operazioni di get/set attributi e di rename operano sugli attributi e sul nome del file (il rename può comportare uno spostamento logico del file all'interno del FS). La cancellazione, infine, rimuove il file liberando spazio in memoria secondaria. Si osservi che un file risiede normalmente in memoria secondaria ma un SO può mappare un file anche in memoria virtuale: il file continua a risiedere su disco, tuttavia all'indirizzo di ogni suo dato si fa corrispondere una coppia base / offset (in una GDM a segmentazione si può assegnare ad ogni file un intero segmento distinto), le principali operazioni avvengono in RAM (chiamata di indirizzo page fault demanding page rimpiazzo di pagina operazione sui dati) e a fine sessione tutte le modifiche vanno salvate in memoria secondaria: questo tipo di approccio ha l'indubbio vantaggio di velocizzare le operazioni, ma pone problemi con la condivisione (la versione aggiornata dei dati è in RAM o su disco?) e con i file di grande dimensione (se il file è più grande del segmento?). Si noti che le operazioni di Open e Close di un file potrebbero non essere presenti come statement specifici a livello di linguaggio di programmazione, ma vengono in ogni caso eseguite dal SO, rispettivamente prima e dopo le operazioni di accesso. Relativamente all'operazione di Seek, il SO può prevedere un unico puntatore RW o due distinti puntatori: in tal caso anche a livello di linguaggio sarà prevista una routine di seek per la lettura e una per la scrittura. Oltre alle classiche Read_Next e Write_Next, alcuni SO (non UNIX) mettono a disposizione routine SVC di Read (pos,n) e Write (pos,n) dirette, che inglobano l'operazione di seeking (utilissimo se il SO riconosce per i file la struttura logica a record) implementando la lettura/scrittura dei successivi N byte/record.
La più piccola unità informativa teoricamente indirizzabile, leggibile e scrivibile in una memoria secondaria (disco) è il settore: a livello fisico un file occupa un insieme di settori. Tuttavia per motivi di efficienza le operazioni di lettura e scrittura vengono effettuate a blocchi di settori o cluster (grappolo), nonostante il prevedibile rischio di frammentazione interna che ciò comporta: un file occupa sempre un numero intero di cluster, minimo uno. Esistono inoltre almeno 3 diverse strategie di allocazione a blocchi per i file, ovvero 3 distinti criteri con i quali si decide quali blocchi assegnare ad uno specifico file e come tenere traccia di essi.
Con l'allocazione contigua un file occupa cluster consecutivi - viene descritto dall'indirizzo del primo cluster e dal numero di cluster occupati - il che consente facilmente un accesso sia sequenziale che diretto con un unico accesso (ideale per CD-ROM e DVD); in realtà ogni modifica del file produce potenzialmente una frammentazione che rende necessaria una onerosa ricompattazione periodica (tecnica oggi abbandonata) oppure in alternativa si può adottare una accorta gestione dei blocchi liberi: si può mantenere una lista dei blocchi liberi (su cui applicare un algoritmo di ricerca Best Fit del blocco libero da utilizzare) oppure si può fare una stima anticipata della dimensione massima del file (rischioso perchè in caso di sottostima non si risolve comunque il problema); tale tecnica rimane comunque (solo in linea di principio) la più conveniente per l'allocazione di immagini di processi la cui dimensione nel tempo non varia e ben si concilia con tecniche di mappatura in memoria virtuale che prevedono la definizione di segmenti di dimensione fissata.
Con l'allocazione a lista concatenata un file occupa cluster non consecutivi concatenati tra loro in una lista, viene identificato dal puntatore al primo cluster (in alcuni SO anche dal puntatore all'ultimo cluster) e ogni cluster contiene un puntatore al cluster successivo (o un marcatore di fine lista): allocato un primo blocco in uno spazio libero idoneo, la restante parte del file viene allocata segnalando iterativamente un'extent, cioè un puntatore ad un'altra regione del disco che contiene il prossimo blocco; questa strategia non causa frammentazione esterna, rende ancora semplice l'accesso sequenziale ma rende quello diretto molto più complesso, e comunque per ambedue i tipi di accesso si richiedono generalmente più operazioni su disco; si noti infine che la perdita di anche solo un metadato di puntamento (da un cluster all'altro) corrompe l'intero file (per questo si usano talvolta anche puntatori per percorrere la lista concatenata all'indietro
Con l'allocazione a lista indicizzata un file occupa ancora cluster non consecutivi concatenati tra loro, ma ogni cluster del file contiene solo dati e le informazioni di concatenazione non sono più interne ad essi: l'insieme ordinato dei puntatori ai cluster di uno specifico file può essere organizzato in forma tabellare (FAT) o in forma indicizzata (i-node).
La FAT - File Allocation Table (usata da DOS e Windows) è schematizzabile nella sua forma più generale come un array di puntatori, uno per ogni cluster della partizione, ed ha una ampiezza chiaramente crescente con la dimensione della partizione stessa; il descrittore di un file ne associa il nome al numero del suo Primo_Cluster, il cluster successivo è indicato da Secondo_Cluster = FAT [Primo_Cluster] e così via fino a che FAT [Ultimo_Cluster] non contiene un marcatore convenzionale di EOF (end of file): un file è identificato mediante la catena dei puntatori ai suoi cluster e la porzione di FAT relativa ai file in uso deve sempre risiedere completamente in RAM; si tenga presente che i puntatori ai cluster liberi (cioè non associati ad alcun file) possono essere essi stessi linkati tra loro, implementando in maniera banale una lista di blocchi di liberi che viene erosa (cominciando tipicamente dalla sua testa, senza bisogno di visitarla completamente) quando viene allocato spazio per un file e viene ingrossata quando viene liberato spazio; si noti infine che la FAT può venire, in toto o in parte, caricata in RAM (caching) per velocizzare gli accessi ad essa.
I nodi indice o i-node (usati da UNIX) sono strutture allocate - ciascuno - in un cluster dedicato, contenente gli attributi di uno specifico file e un certo numero (limitato, in UNIX ce ne sono 12) di puntatori ai suoi cluster, detti puntatori a blocchi diretti; se il file è frammentato al punto che il numero dei blocchi diretti indicati è insufficiente, il nodo indice mette a disposizione un puntatore, detto indiretto singolo, ad un altro nodo indice, nel quale saranno indicizzati i cluster supplementari; per esigenze legate a file di dimensioni molto grandi o in grave stato di frammentazione, il nodo indice mette a disposizione anche un puntatore indiretto doppio nodo intermedio nodi intermedi di 2° livello nodi indice e un puntatore indiretto triplo nodo intermedio nodi intermedi di 2° livello nodi intermedi di 3° livello nodi indice questo tipo di gestione si dice basata su puntatori multilivello); per gestire rapidamente gli accessi, in RAM risiede una tabella di i-node per i soli file aperti, dimensionata sul numero massimo di file apribili contemporeanemente.
La gestione dei blocchi liberi deve avvenire in modo coerente con la tecnica di allocazione dello spazio occupato e può essere implementata in 3 modi distinti. La tecnica bitmap consente di mappare in modo semplice ed intuitivo lo stato dell'intero disco, prevede di utilizzare un vettore di bit dove ciascuno indica lo stato (1 se occupato, 0 se libero) di un singolo blocco e tale vettore va tipicamente conservato in RAM compatibilmente con la sua dimensione (dimensione in KB = numero di cluster / 8 / 1024), che può comunque essere notevole per dischi di grandi dimensioni; si noti che è utile adottare un algoritmo di gestione della bitmap leggero ed è auspicabile che la CPU abbia istruzioni ad hoc per gestirla: normalmente infatti la bitmap andrebbe acceduta almeno a byte, caricando gli 8 bit in un registro, verificando se contenga almeno un 1 ed individuando il primo 0 con ripetute operazioni di rotate shift; i processori Intel 80386 (e successivi) e Motorola 68020 (e successivi) hanno istruzioni dedicate per trovare l'offset del primo bit alto/basso in una word. Tecnica alternativa è la lista concatenata, già accennata a proposito della FAT si integra perfettamente con quest'ultima e prevede che i blocchi liberi siano linkati tra loro: il principale svantaggio è l'inefficienza del metodo di accesso (sempre indiretto) quando si desidera accedere ad un gruppo di blocchi liberi piuttosto che ad un singolo blocco. Un miglioramento della tecnica precedente è dato dalla tecnica della lista concatenata con raggruppamento, in cui ogni blocco della lista è strutturato in modo da puntare direttamente ad un certo numero di blocchi liberi e contiene inoltre un puntatore al blocco della lista successivo; questa tecnica facilita in generale l'accaparramento di blocchi liberi multipli ma non di blocchi liberi adiacenti (non è detto infatti che i blocchi liberi puntati dallo stesso blocco siano tra loro consecutivi), per questo è possibile introdurre la variante del conteggio con la quale, data una sequenza di blocchi liberi consecutivi per indirizzi crescenti, solo il primo di essi viene mappato nella lista mentre gli altri vi compaiono implicitamente, dal momento che insieme ad ogni puntatore a blocco libero viene indicato anche il numero di blocchi liberi che lo seguono: ciò rende più snella la lista concatenata e più efficiente l'allocazione dello spazio libero in blocchi.
Un FS usa le directory per tenere traccia dei suoi file regolari, allo scopo di soddisfare alcuni requisiti fondamentali a livello dell'utente: trovare un file deve essere semplice (efficienza), più utenti devono poter usare lo stesso nome ciascuno per il proprio file e lo stesso file deve poter essere chiamato in modi diversi da utenti diversi (libertà di denominazione), deve essere possibile creare gruppi logici di file sulla base di proprietà considerate significative dall'utente (libertà di raggruppamento). Un FS può utilizzare un direttorio a livello singolo, a due livelli, ad albero, a grafo aperto (aciclico) o a grafo generalizzato (ciclico), implementando ogni volta un diverso grado di organizzazione dei file (con conseguente differente grado di soddisfazione dei requisiti sopra indicati). Con directory a livello singolo tutti i file sono elencati in un'unica lista lineare, ciascuno col proprio nome: l'efficienza è solo realizzativa (e comunque diminuisce all'aumentare del numero dei file) ma non d'uso, manca la libertà di denominazione (ogni nome deve essere univoco) e di raggruppamento (ovvio, essendoci un'unica directory). Con directory a due livelli il FS prevede una Root Directory contenente una distinta User File Directory (UFD) per ciascun utente di sistema, quindi ogni utente vede i file della propria UFD (quella degli altri solo se espressamente autorizzato), ogni file è localizzato tramite un path name (percorso) e le applicazioni possono essere copiate in tutte le UFD o (meglio) poste in una directory di sistema condivisa: l'efficienza di ricerca è garantita dai path names ma solo nell'ambito della propria UFD, anche la libertà di denominazione è soddisfatta parzialmente perchè non è possibile associare nomi diversi allo stesso file, manca infine la libertà di raggruppamento. Con directory ad albero il FS prevede una root e un'organizzazione gerarchica a numero arbitrario di livelli, ad ogni livello possono esserci dei file regolari o directory di livello inferiore, è possibile spostarsi da una directory all'altra o puntare ad un qualunque file utilizzando un cammino assoluto (espresso rispetto alla root) o relativo (espresso rispetto alla posizione corrente): l'efficienza di ricerca è garantita in modo completo, la libertà di denominazione è ancora soddisfatta parzialmente (di nuovo non è possibile associare nomi diversi allo stesso file), la libertà di raggruppamento è pienamente soddisfatta. Con directory a grafo (ciclico o aciclico) non c'è più limite ai collegamenti che è possibile instaurare tra gli elementi dell'albero, per cui uno stesso file può appartenere simultaneamente a più directory: in particolare, in un grafo aciclico due directory possono puntare uno stesso file regolare (condivisione dei file), in un grafo ciclico invece una directory può puntare ad un'altra directory remota e sono altresì consentiti anche riferimenti circolari tra directory (che andrebbero comunque in generale evitati), per cui una directory può puntare ad una directory che la punta (condivisione sia di file che di directory
Una directory è in pratica un file speciale che contiene o punta i descrittori dei file in essa contenuti: in DOS tale file speciale è strutturato come un array di record (uno per ogni file contenuto nella directory), ciascuno dei quali costituisce una directory entry contenente il nome, gli attributi e le informazioni di allocazione del singolo file (in DOS, l'informazione di allocazione è il numero del primo cluster del file, come detto riguardo alla FAT); in UNIX il file speciale directory ha forma tabellare e in ciascuna directory entry (riga della tabella) c'è una coppia nome (del file) i-node (che ne contiene attributi e lista dei cluster). Si noti che mentre attributi e informazioni di allocazione occupano uno spazio fisso (noto a priori) la gestione di nomi di file di lunghezza variabile può costituire un problema: riservare in anticipo uno spazio di dimensione fissa può determinare uno spreco di memoria (se il nome è mediamente molto più piccolo dello spazio riservato) oppure costringere ad usare nomi brevi (se lo spazio riservato è troppo piccolo, per esempio in DOS) e questo è insoddisfacente; una lunghezza realmente variabile può essere implementata in due modi: nel file speciale directory il primo campo "file entry length" di ogni directory entry (che memorizza la dimensione complessiva individuale del nome del file) consente di delimitare la stringa del nome del file contenuta nell'ultimo campo (a lunghezza variabile); in alternativa nel file speciale directory i record continuano ad avere una dimensione fissa, ma il primo campo "pointer to file's name" di ciascuno di essi punta al primo carattere del nome del file - contenuto in un Heap (mucchio) di caratteri posizionato alla fine del file directory - terminato da un carattere marcatore di EOF. Altro aspetto fondamentale riguarda la ricerca (nel file system) di un file all'interno di una directory (attraverso un path), che altresì può essere implementata in due modi: una ricerca lineare è di facile realizzazione ma poco efficiente se la directory contiene molti file, una ricerca mediante tabelle hash è viceversa più veloce ma richiede una struttura tabellare più complessa, tendenzialmente di grandi dimensioni, oltre a potersi dimostrare inefficiente comunque in caso vi siano molte collisioni. In generale, dunque, un file creato (o spostato) dentro una directory determina l'aggiunta di una corrispondente directory entry (record in un array di record o voce in una tabella) che collega il nome del file ai suoi attributi e ai suoi cluster: si parla di hard link o collegamento fisico.
In un FS a grafo (aciclico) la condivisione "richiede" che uno stesso file, inizialmente creato in una precisa directory, sia accessibile da una o più directory differenti. Le modalità con cui può essere realizzato un puntamento remoto ad un file (un puntamento cioè distinto da quello naturalmente implementato da una directory che "contiene" quel file) sono essenzialmente due: l'hard link e il soft (o symbolic) link o collegamento simbolico. Come abbiamo visto, un hard link o collegamento fisico è un puntatore diretto, ad un file regolare, inserito in una directory sotto forma di descrittore (directory entry), e realizzare con esso un puntamento remoto significa inserire in una directory remota (purchè interna al medesimo FS che contiene il file da condividere) lo stesso descrittore (directory entry) contenuto nella directory originaria, in modo da creare di fatto 2 vie d'accesso distinte, sebbene indistinguibili, allo stesso file: le stesse informazioni relative al file sono presenti in due directory e non si può dire quale sia l'hard link locale e l'hard link remoto, nè si può distinguere la directory originaria dalla directory remota, nè ha senso fare queste distinzioni Un soft (symbolic) link o collegamento simbolico consiste in uno speciale file di collegamento, creato nella directory remota (che conterrà quindi, come da prassi, un hard link ad esso), al cui interno c'è il path name del file puntato (che può risiedere anche in un FS remoto), per cui con questo meccanismo si conserva un'unica via d'accesso al file condiviso: accedendo al file condiviso dalla directory remota, all'apertura (che comporta una prima ricerca nel FS) si verifica che è solo un link, il link viene risolto (seconda ricerca nel FS) e l'accesso avviene direttamente mediante l'hard link contenuto nella directory (indicata nel path) che contiene effettivamente il file. Ricapitolando con il meccanismo dei sym link (adottato da DOS, Windows e UNIX) si mantiene unica la directory contenente il file, esiste un unico descrittore del file originale, l'accesso per condivisione avviene tramite un cammino sul FS, la cancellazione del link non ha effetto sul file puntato e la cancellazione del file dalla directory originaria non ha effetti sui link ad esso, anche se li rende non più risolvibili; con il meccanismo degli hard link (adottato da UNIX) invece ci sono più directory contenenti lo stesso file, esistono più descrittori del file originale, l'accesso per condivisione avviene in modo diretto e, finché ci sono altri descrittori remoti, deve essere impedita la cancellazione del file: più directory che condividono uno stesso file possiedono lo stesso hard link al medesimo i-node nel quale, per preservare la consistenza del file, vengono contenuti tutti gli attributi del file e anche un counter delle directory che lo condividono (da incrementare ogni volta che una nuova directory condivide quel file), perciò finché tale counter > 1 nessun processo (nemmeno il possessore) può fisicamente eliminare da una directory il file e il FS si limita a rimuovere (dalla directory in oggetto) il corrispondente descrittore, mentre il counter dell'i-node viene decrementato.
Sempre allo scopo di preservare la consistenza, il SO può gestire dei lock (blocchi) sui file condivisi a vari livelli. Per esempio, per due processi che condividano l'accesso ad un file, occorre impedire che essi eseguano operazioni contemporanee e conflittuali sugli stessi blocchi dati: relativamente al primo caso (operazioni contemporanee) gli accessi ad uno o più cluster del file devono essere sequenziali tra processi, ovvero l'accesso ai cluster sarà concesso al secondo processo solo quando il primo avrà terminato di manipolarli o leggerli; relativamente al secondo caso (operazioni conflittuali), un esempio classico è quello dello spostamento di un file da parte di un processo mentre un altro ci sta lavorando sopra (per evitare problemi il file deve risultare bloccato alla copia). Inoltre, considerando che ogni volta che un processo "apre" un file esso ne carica il descrittore nella tabella dei file aperti, e che due processi che condividono l'accesso ad un file caricano in RAM due volte lo stesso descrittore, il SO può prevedere un meccanismo per gestire le informazioni descrittive del file in modo differenziato a seconda che i processi cooperino o competano, minimizzando in tutti i casi la duplicazione (e la necessaria sincronizzazione che ne consegue per garantirne la consistenza) delle informazioni: in particolare, in UNIX la tabella dei file aperti è strutturata in particolare su due livelli di informazioni, al primo livello ci sono informazioni del file comuni a famiglie di processi (handle attributi, posizione su disco, puntatore di R/W), al secondo livello i dati specifici del particolare processo (con puntatore alla corrispondente voce del primo livello), con il primo livello strutturato su 2 tabelle (per un totale di 3 tabelle
Di grande importanza è l'adozione di tecniche che preservino l'integrità del FS. La gestione del blocchi danneggiati può avvenire via hardware, creando e gestendo direttamente nel disco un'area che indicizza i blocchi danneggiati e i loro sostituti, ma anche via software, ricorrendo ad un dummy file che occupi tutti i blocchi danneggiati. Operazioni di caching utili a velocizzare gli accessi e le modifiche al FS possono produrre inconsistenza del FS, per esempio al verificarsi di una mancanza di alimentazione dopo la modifica in cache ma prima dell'effettivo salvataggio su disco (il DOS prevede in realtà che ad ogni operazione in cache segua la corrispondente scrittra su disco, viceversa UNIX adotta un processo sync che solo periodicamente effettua la sincronizzazione, ed è quindi più esposto al rischio di inconsistenza); un SO che non gestisca il FS in modo transazionale (cioè ricorrendo ad un log e al rollback delle operazioni eseguite solo parzialmente) non può evitare che l'inconsistenza si presenti, ma può verificarla a posteriori: data una lista dei blocchi occupati e una lista dei blocchi liberi su disco, la verifica di consistenza si ottiene accertando che ciascun blocco appartenga al più ad una lista (consistenza), che ciascun blocco appartenga almeno ad una lista (perdita) e che in ciascuna lista il blocco sia mappato al più una volta (duplicazione): le tecniche adottate per correggere l'inconsistenza sono peculiari del singolo SO.
In sintesi, può essere utile considerare l'architettura interna del FS come organizzata a livelli. Al livello 0 l'applicazione richiede l'accesso ad un file mediante opportune SVC. Al livello 1 il file system logico accetta richieste di Open, Read, Write, Close, e così via accettando come operando per esse il path name del file/directory (a questo livello file e directory sono viste indistintamente come file) e una descrizione (posizione logica relativa e numero) dei blocchi dati da accedere. Al livello 2 il modulo gestione tipi di file viene implementata la ricerca nel FS vera e propria, estrapolando i dati del file dalla corrispondente directory entry che ne contiene (o punta a) il descrittore, trasformando la posizione relativa dei blocchi da accedere in una posizione assoluta e (nota la particolare tecnica di allocazione usata) passando a considerare dal blocco logico i blocchi fisici corrispondenti. Al livello 3 il file system di base delinea il cilindro, la traccia e il settore (per eseguire la trasformazione occorre che il SO conosca le caratteristiche fisiche tridimensionali del disco) da accedere, emettendo poi i comandi necessari a pilotare il driver I/O (si noti che spesso il livello 3 non fa parte del Kernel perchè i dischi hanno propri controllori che effettuano la traduzione indirizzo logico indirizzo fisico). Al livello 4 il driver richiede l'I/O attraverso il gestore della risorsa virtualizzata e interagendo con il gestore degli interrupt. All'ultimo livello c'è chiaramente l'hardware, ovvero il drive.
In MS-DOS il FS è non multiprogrammato, cioè ogni utente vede tutto il FS, è gerarchico senza limite di profondità e senza condivisione, prevede un massimo di 4 partizioni per disco, directory a lunghezza variabile con nomi di 8+3 caratteri e directory entry di 32B. La FAT è del tipo FAT-X con 12 X 32 dove X indica il numero di bit per indirizzo di blocco, ogni blocco ha una dimensione multipla di 512B (0.5KB, 1KB, 2KB, 4KB, 8KB, 16KB e 32KB): ad esempio, in FAT-16 file e partizioni limitati a 2GB, poichè 2^16 64K puntatori x blocchi di 32KB (caso migliore) = 2GB, mentre la FAT-32 ha un limite intrinseco di capacità di partizione pari a 2TB, poichè 2^32 4'096M puntatori x blocchi di 0.5KB (caso peggiore) = 2TB.
In UNIX il FS ha struttura a grafo aciclico (condivisione dei file), nomi di file fino a 14 caratteri, ogni directory contiene entry di estensione pari a 16B, ciascuna con nome del file (14B) e I-NUMBER (puntatore a 16 bit al rispettivo i-node), per un massimo di 2^16 64K i-node distinti (quindi il numero massimo di file memorizzabili su FS è proprio 64K). Il singolo i-node ha un'estensione di 64B di cui (10+3) x 3B 39B occupati dal complesso dei puntatori (anche indiretti) ai blocchi (ciascun blocco è di 4KB) e 25B per attributi vari: ID del proprietario, ID del gruppo, tipi di accesso consentiti (9bit), dimensione del file, data di ultimo accesso/modifica, tipo di file e contatore di hard link. Il superblock contiene il numero totale di i-node, numero di cluster del disco e loro dimensione, puntatore al primo blocco libero (i blocchi liberi sono linkati in una lista concatenata
Appunti su: |
|