22 Aug 2023, 1:32 PM
22 Aug 2023, 1:32 PM

12. File System

Il file system fornisce il meccanismo per la memorizzazione e l’accesso di dati e programmi. Consiste di una collezione di file e della struttura di cartelle (directory).

Interfaccia del file system

Concetto di file

Il sistema operativo astrae dalle caratteristiche fisiche dei supporti di memorizzazione fornendo una loro visione logica. Si considera un file come uno spazio di indirizzamento logico e contiguo rappresentante un insieme di informazioni correlate identificate da un nome. I file possono essere dati di qualsiasi tipo e programmi.

Attributi di un file

Su disco, nella struttura della directory, sono salvati per ogni file il nome (unica informazione in formato leggibile), tipo, posizione (puntatore allo spazio fisico sul dispositivo), dimensione, protezione (controllo sui permessi), tempo, data e identificazione dell’utente.

Operazioni sui file

Struttura dei file

I tipi di file possono essere usati per indicare la struttura interna del file. Di seguito 3 esempi di struttura di file.

  1. Nessuna struttura: si considera un file come una sequenza di parole o bytes, come avviene ad esempio in Unix.
  2. Struttura a record semplice: un record è una riga di lunghezza fissa o variabile.
  3. Struttura complessa: come accade nei documenti formattati e i formati ricaricabili (load module).

Le ultime due si possono emulare con la prima usando caratteri di controllo.

Metodi di accesso

Sequenziale

Questo metodo viene usato da editor e compilatori, permettono le operazioni read next, write next, reset (rewind). Non è permesso il rewrite in quanto si rischia inconsistenza se si scrive qualcosa a metà del file in quanto si potrebbe eliminare ciò che sta dopo.

Diretto

Come accade nel database in cui un file è una sequenza numerata di blocchi detti record. Le operazioni permesse sono read n, write n, position to n, read next, write next, rewrite n.

Struttura delle directory

Le directory sono una collezione di nodi contenenti informazioni sui file. Si trovano entrambi sul disco e determinano la struttura del file system. Per ogni file contengono il nome, tipo, indirizzo, lunghezza attuale, massima lunghezza, data di ultimo accesso, data di ultima modifica, proprietario e informazioni di protezione.

Operazioni sulla directory

Organizzazione logica

I vantaggi dell’organizzazione logica delle directory sono l’efficienza (rapido accesso ad un file), nomenclatura conveniente agli utenti in quanto permette stessi nomi per file e utenti diversi e nomi diversi per lo stesso file e raggruppamento: i file vengono classificati logicamente per un criterio come il tipo o la protezione.

Grazie alle directory il file system può assumere diverse strutture, definite durante l'implementazione. Vediamone alcune.

Directory a un livello

In questo metodo si trova una singola directory per tutti gli utenti. Nascono problemi di nomenclatura, in quanto è difficile ricordare se un nome esiste già e inventarne sempre di nuovi. Nascono inoltre problemi di raggruppamento.

Directory a due livelli

In questo metodo si trova una directory separata per ogni utente. Nasce il concetto di percorso (path), è possibile usare lo stesso nome di file per utenti diversi e la ricerca è efficiente. Non esiste comunque raggruppamento e si pone il problema di dove mettere i programmi di sistema condivisi dagli utenti (in Unix si usa PATH).

Directory ad albero

In questo metodo la directory viene implementata come un albero permettendo una ricerca efficiente e la possibilità di raggruppamento. Nasce il concetto di working directory e i nomi di percorso possono essere assoluti o relativi. Tuttavia manca ancora la possibilità di condivisione di file e directory.

Directory a grafo aciclico

In questo metodo si espande la versione ad albero a grafo aciclico per permettere la condivisione di file.
La condivisione avviene:

Directory a grafo generico

Questo metodo nasce come estensione della directory a grafo aciclico e si deve garantire che le ricerche terminino per evitare loop infiniti nell’attraversamento del grafo (visto che in questo caso può avere cicli). Per risolvere questo problema si può permettere di collegare solo file non directory o usare un algoritmo di controllo di esistenza di un ciclo ogni volta che si crea un nuovo collegamento, che può essere costoso.

Mount di un file system

Il mount di un file system è il processo attraverso il quale un file system viene aggiunto al sistema operativo e reso accessibile. Quando si crea un file system, è possibile renderlo modulare, consentendo di collegare (mount) e scollegare (unmount) interi file system a file system esistenti.
Prima di poter accedere a un file system però, è necessario montarlo. Il processo di montaggio richiede che un file system sia associato a un punto specifico del sistema operativo, noto come "mount point". Il mount point è una directory esistente nel sistema di file che funge da punto di accesso al file system che viene montato. Una volta montato, il file system diventa parte integrante del sistema operativo e può essere utilizzato per leggere o scrivere dati.

Condivisione di file

La condivisione di file è importante in sistemi multiutente ed è realizzabile tramite uno schema di protezione. Nei sistemi distribuiti, i file possono essere condivisi attraverso una rete. Per esempio, il Network File System (NFS) è un tipico schema di condivisione di file via rete.

Protezione

Il possessore di un file deve poter controllare cosa è possibile fare su un file e da parte di chi. Per farlo si può implementare una lista di accesso per ogni file o directory che lista chi può fare cosa.
Gli utenti si possono raggruppare in tre classi con una perdita di generalità: il proprietario, il gruppo (utenti appartenenti allo stesso gruppo del proprietario) e gli altri. Per ogni classe i permessi possono essere di read(r), write(w) ed execute(x).

CHMOD

In Unix per esempio, è possibile cambiare i permessi di un file utilizzando il comando chmod.
Un esempio di utilizzo può essere il seguente:

chmod 754 nome_file

dove le 3 cifre rappresentano rispettivamente il livello di permessi per l'utente, il livello di permessi del gruppo e il livello di permessi generale. In base alla cifra si ha una serie di permessi. La tabella seguente indica il significato dei singoli valori:

Valore decimale Permessi
7 lettura, scrittura ed esecuzione
6 lettura e scrittura
5 lettura ed esecuzione
4 solo lettura
3 scrittura ed esecuzione
2 solo scrittura
1 solo esecuzione
0 nessuno

Dunque nel nostro esempio il proprietario ha i permessi di read, write ed execution, il gruppo non ha la write, e gli altri solo la read.

Implementazione di un file system

Per gestire un file system si usano diverse strutture dati in parte su disco e in parte in memoria. Le caratteristiche, pur avendo una base comune sono fortemente dipendenti dal sistema operativo e dal tipo di file system.

Strutture su disco

Strutture in memoria

Allocazione dello spazio su disco

I blocchi su disco possono essere allocati in modi diversi con l’obiettivo di minimizzare i tempi di accesso e massimizzare l’utilizzo dello spazio.

Allocazione contigua

In questo metodo ogni file occupa un insieme di blocchi contigui su disco. L’entry della directory è semplice in quanto contiene l’indirizzo del blocco di partenza e la lunghezza del file.

FileSystem-AllocContigua.png|600

Vantaggi
Svantaggi
Variante

Alcuni file system moderni usano uno schema modificato di allocazione contigua come Linux ext2fs basato sull’extent, una serie di blocchi contigui su disco. Il file system alloca extent invece di blocchi singoli che in generale non sono contigui e si prestano pertanto per l’allocazione a lista.

Allocazione a lista

In questo metodo ogni file è costituito da una lista di blocchi concatenati, che possono essere sparsi ovunque nel disco.
La directory contiene puntatori al primo e all’ultimo blocco e ogni blocco contiene un puntatore al blocco successivo. Considerando X l’indirizzo logico e N la dimensione del blocco, X(N1) è il numero
del blocco nella lista, mentre Xmod(N1) è l’offset all’interno del blocco.

FileSystem-AllocLista.png|600

Vantaggi
Svantaggi
Variante - FAT (file allocation table)

Una variante che migliora l'accesso casuale fa uso della File Allocation Table (FAT). Questa è una tabella che occupa i primi blocchi del volume e contiene una lista di tutti i blocchi allocati. Inoltre, per ogni blocco si registra anche la posizione del suo blocco successivo. Purtroppo le dimensioni della FAT (spesso FAT32 perchè con entry di 32 bit) impediscono una scansione efficiente e cominciano ad occupare una porzione significativa di memoria con l'aumentare delle dimensioni del disco. Questi svantaggi rendono oggi l'uso della FAT proibitivo.
L’accesso diretto ai file di grandi dimensioni, per esempio utilizzando la system call lseek, può essere inefficiente nei file system di tipo FAT a causa del modo in cui i dati vengono organizzati e gestiti. In un file system FAT, i dati vengono memorizzati in cluster di dimensioni fisse. Quando si accede a un file, il sistema operativo deve seguire una catena di cluster per trovare il cluster corretto che contiene i dati richiesti. Per i file di grandi dimensioni, questo può comportare il passaggio attraverso molti cluster, il che può richiedere molto tempo. Inoltre, se il file è frammentato (cioè i suoi cluster non sono contigui), il tempo necessario per trovare il cluster corretto può aumentare ulteriormente. Questo può rendere l’accesso diretto ai file di grandi dimensioni utilizzando lseek inefficiente nei file system di tipo FAT.

Allocazione indicizzata

In questo metodo ogni file ha un blocco indice (index block) che contiene la tabella degli indirizzi dei blocchi fisici, ossia il blocco indice punta a tutti gli altri blocchi dello stesso file. La directory contiene l’indirizzo del blocco indice. Se X è l’indirizzo logico e N la dimensione del blocco XN è l’offset nella index table e XmodN è l’offset all’interno del blocco dati.

FileSystem-AllocIndicizzata.png|600

Vantaggi
Svantaggi
Indici multilivello

Il blocco indice punta ad altri blocchi indici, che punteranno ai dati dei file veri e propri.
Sia X l’indirizzo logico e N la dimensione del blocco in parole. Xn N è il blocco della index table di primo livello e Xmod(NN)=R, dove RN è l’offset nel blocco della index table di secondo livello e RmodN è l’offset nel blocco dati.
Per esempio, blocchi da 4KB consentono 1K indici da 4 byte, mentre due livelli di indici consentono file da 4GB.

Schema concatenato

Si usano più blocchi indice collegati tramite una lista concatenata: l’ultimo degli indici di un blocco indice punta a un altro blocco indice. XN(N1) è il numero del blocco indice all’interno della lista dei blocchi indice e Xmod(N(N1))=R, dove RN1 è l’offset nel blocco indice e RmodN è l’offset nel blocco dati.

Esempio

N = 1KB = 256 parole (parola=32bit)

Max file = 256 blocchi da 1KB = 256KB

Schema combinato

Unix usa lo schema combinato in cui ad ogni file è associato un i-node (index-node) che contiene gli attributi del file e fa da blocco indice. Gli i-node sono gestiti dal sistema operativo e memorizzati in modo permanente in una porzione riservata al sistema operativo di solito all’inizio del disco. Per memorizzare i blocchi di dati del file, ogni i-node contiene:

SchemaCombinato.png|700

Implementazione delle directory

Le directory vengono implementate con lo stesso meccanismo usato per memorizzare i file. Non contengono dati, ma una lista di file e directory. Questo spazio può essere memorizzato in due modi:

Gestione dello spazio libero

Per tenere traccia dello spazio libero su disco si mantiene una mappa dei blocchi liberi. Per creare un file si cercano blocchi liberi nella mappa e per rimuovere un file si aggiungono i suoi blocchi a tale mappa. Vediamo ora diverse alternative per implementare la mappa.

Vettore di bit

Si mantiene un vettore in cui ogni posizione indica se un blocco è occupato o no. Bit[i]=0 implica che il blocco i è libero e Bit[i]=1 implica che è occupato. La mappa di bit richiede spazio extra ed è efficiente solo se il vettore è mantenibile tutto in memoria. Risulta comunque facile ottenere blocchi contigui.

Lista concatenata di blocchi liberi (free list)

Ogni blocco libero punta ad un altro blocco libero. Permette spreco minimo(solo per la testa della lista) ma lo spazio contiguo non è ottenibile.

Raggruppamento

Il concetto è simile a quello della lista concatenata, ma qui un blocco contiene la lista di n1 indirizzi di blocchi liberi, e l'ultima entry punta ad un altro blocco usato come lista. Fornisce rapidamente un gran numero di blocchi liberi.

Conteggio

Si usa una lista che contiene ad ogni entry un blocco libero e quanti blocchi liberi consecutivi seguono.
La lista risulta più corta se il contatore è maggiore di 1 per ogni gruppo di blocchi liberi.

Efficienza e prestazioni

Efficienza

Il disco è un collo di bottiglia e l’efficienza dipende dall'algoritmo di allocazione dello spazio su disco e dal tipo di dati contenuti nella directory.

Prestazioni

Il controller del disco possiede una piccola cache che è in grado di contenere un’intera traccia ma non basta per garantire prestazioni elevate, pertanto si usano dischi virtuali (RAM disk) e cache del disco o buffer cache.

Dischi virtuali

Parte della memoria viene gestita come se fosse un disco: il driver di un RAM disk accetta tutte le operazioni standard dei dischi eseguendole in memoria. È veloce ma supporta solo file temporanei. Viene gestito dall’utente che scrive sul RAM disk invece che sul disco.

Cache del disco

È una porzione di memoria che memorizza blocchi usati di frequente, simile alla cache tra memoria e CPU.
Viene gestita dal sistema operativo e sfrutta il principio di località spaziale e temporale. Il trasferimento di dati nella memoria del processo utente non richiede spostamento di byte. Nascono problematiche riguardanti la politica di rimpiazzamento del blocco (se la cache è piena devo scegliere il blocco da togliere usando LRU, LFU, RANDOM, ecc.) e la politica di scrittura. Cioè se devo scrivere sul blocco usato di recente, intanto scrivo su quello in cache ma quando aggiorno quello originale che è memorizzato su disco?
Posso decidere di fare write-back, ovvero scrivere solo quando devo rimuovere il blocco dalla cache (può generare problemi di affidabilità in caso di crash) oppure write-through, scrivendo sempre (meno efficiente, la cache è praticamente in sola lettura).

Recupero

I problemi di consistenza tra disco e cache possono essere risolti attraverso un controllo di consistenza che confronta i dati nella directory con i dati su disco e sistema le inconsistenze, oppure attraverso l’uso di programmi di sistema per fare il backup del disco su memoria di massa come i nastri che permettono il recupero di file persi tramite il restore dei dati di backup.

File system log structured

Si registra ogni cambiamento del file system come una transazione. Tutte le transazioni sono scritte su log e considerate completate quando vengono scritte su log (anche se il file system può non essere aggiornato). Le transazioni sono scritte in modo asincrono nel file system e quando il file system è modificato la transazione viene cancellata dal log. Se il sistema va in crash le transazioni non avvenute sono quelle presenti sul log.
In questo modo si ottimizza il numero di seek.