X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileintro.tex;h=966625f1c12f88f0cc64ec2ae74bb8eecb16af4e;hp=a2735a7dd2e5473902dfe5b9c949deffe8c4de82;hb=d99b4995b23505a9afde30adf3a716aa7a55f0e9;hpb=66765a9be9a61085dd00abd92d99a24b23dc844b diff --git a/fileintro.tex b/fileintro.tex index a2735a7..966625f 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -1,45 +1,47 @@ -\chapter{I files: introduzione} +\chapter{I files: l'architettura} \label{cha:files_intro} - + Uno dei concetti fondamentali della architettura di unix è il cosiddetto \textit{everything is a file}, cioè il fatto che l'accesso ai vari dispositivi di input/output del computer viene effettuato attraverso un'interfaccia -astratta che tratta le periferiche allo stesso modo degli usuali file di -dati. +astratta che tratta le periferiche allo stesso modo degli usuali file di dati. -Questo significa che si può accedere cioè a qualunque periferica del computer, +Questo significa che si può accedere a qualunque periferica del computer, dalla seriale, alla parallela, alla console, e agli stessi dischi attraverso i cosiddetti file di dispositivo (i \textit{device files}). Questi sono dei file speciali agendo sui quali i programmi possono leggere, scrivere e compiere operazioni direttamente sulle periferiche, usando le stesse funzioni che si usano per i normali file di dati. -In questo capitolo forniremo un'introduzione alle principali caratteristiche -di questa interfaccia, su come essa viene implementata in Linux e su come sono -organizzati i file nel sistema. +In questo capitolo forniremo un'introduzione all'architettura della gestione +dei file, sia nelle sue caratteristiche generiche comuni a tutti gli unix, che +nelle particolarità che ha la specifica implementazione usata da Linux. Al +contempo tratteremo l'organizzazione dei file in un sistema unix-like, e le +varie caratteristiche distintive. + +\section{L'organizzazione di files e directories} +\label{sec:fileintr_organization} +Il primo passo nella trattazione dell'achitettura della gestione dei file in +un sistema unix-like, è quello dell'esame di come essi vengono organizzati e +di quale è la struttura che hanno all'interno del sistema. -\section{I file in un sistema unix-like} -\label{sec:fileintr_overview} -Visto il ruolo fondamentale che i files vengono ad assumere in un sistema -unix, è anzitutto opportuno fornire un'introduzione dettagliata su come essi -vengono trattati dal sistema. In particolare occorre tenere presente dov'è che -si situa il limite fondamentale fra kernel space e user space che tracciavamo -al \capref{cha:intro_unix}. +\subsection{La struttura di files e directory} +\label{sec:fileintr_filedir_struct} Partiamo allora da come viene strutturata nel sistema la disposizione dei file: per potervi accedere il kernel usa una apposita interfaccia che permetta -di strutturare l'informazione tenuta sullo spazio grezzo disponibile sui -dischi, cioè quello che si chiama un \textit{filesystem} (useremo per brevità -questo nome al posto della più prolissa traduzione italiana sistema di file). +di accedere all'informazione tenuta sullo spazio grezzo disponibile sui +dischi, cioè quello che si chiama un \textit{filesystem}\footnote{useremo per + brevità questo nome al posto della più prolissa traduzione italiana sistema + di file}, che descriviremo in dettaglio in \secref{sec:fileintr_vfs}. Sarà attraverso quest'ultimo che il kernel andrà a gestire l'accesso ai dati memorizzati all'interno del disco stesso, strutturando l'informazione in files -e directory (su questo aspetto torneremo con maggiori dettagli in -\secref{sec:filedir_filesystem}). Per poter accedere ai file contenuti in un -disco occorrerà perciò attivare il filesystem, questo viene fatto -\textsl{montando} il disco (o la partizione del disco). +e directory. Per poter accedere ai file contenuti in un disco occorrerà +perciò attivare il filesystem, questo viene fatto \textsl{montando} il disco +(o la partizione del disco). %In generale un filesystem piazzerà opportunamente sul disco dei blocchi di %informazioni riservate che tengono conto degli inodes allocati, di quelli @@ -66,166 +68,74 @@ oggetti visti attraverso l'interfaccia che manipola i files come le FIFO, i link, i socket e gli stessi i file di dispositivo (questi ultimi, per convenzione, sono inseriti nella directory \texttt{/dev}). -\subsection{Il \textit{virtual filesystem} di Linux} -\label{sec:fileintr_vfs} - -Esamineremo adesso come viene implementato l'accesso ai files in Linux. Questa -sezione riporta informazioni sui dettagli di come il kernel gestisce i files, -ed è basata sul documento di Richard Goochs distribuito coi sorgenti del -kernel (nella directory \texttt{linux/Documentation/vfs.txt}). - -L'argomento è abbastanza ``esoterico'' e questa sezione può essere saltata ad -una prima lettura; è bene però tenere presente che vengono introdotti qui -alcuni termini che potranno comparire in seguito, come \textit{inode}, -\textit{dentry}, \textit{dcache}. - -In Linux il concetto di \textit{everything is a file} è stato implementato -attraverso il \textit{virtual filesystem} (da qui in avanti VFS) che è -l'interfaccia astratta che il kernel rende disponibile ai programmi in user -space attraverso la quale vengono manipolati i files; esso provvede anche -un'astrazione delle operazioni di manipolazione sui files che permette la -coesistenza di diversi filesystem all'interno dello stesso albero. - -La funzione più importante implementata dal VFS è la system call \texttt{open} -che permette di aprire un file. Dato un pathname viene eseguita una ricerca -dentro la \textit{directory entry cache} (in breve \textit{dcache}), -una tabella di hash che contiene tutte le \textit{directory entry} (in breve -\textit{dentry}) che permette di associare in maniera rapida ed efficiente il -pathname a una specifica dentry. - -Una singola dentry contiene in genere il puntatore ad un \textit{inode}; -quest'ultimo è la struttura base che sta sul disco e che identifica un singolo -oggetto del VFS sia esso un file ordinario, una directory, una FIFO, un file -di dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal -VFS (sui tipi di ``files'' possibili torneremo in seguito). A ciascuno di essi -è associata pure una struttura che sta in memoria, e che oltre alle -informazioni sullo specifico file contiene pure il riferimento alle funzioni -(i \textsl{metodi}) da usare per poterlo manipolare. - -Le dentries ``vivono'' in memoria e non vengono mai salvate su disco, vengono -usate per motivi di velocità, gli inodes invece stanno su disco e vengono -copiati in memoria quando serve, ed ogni cambiamento viene copiato -all'indietro sul disco, gli inodes che stanno in memoria sono inodes del VFS -ed è ad essi che puntano le singole dentry. - -La dcache costituisce perciò una sorta di vista completa di tutto l'albero dei -files, ovviamente per non riempire tutta la memoria questa vista è parziale -(la dcache cioè contiene solo le dentry per i file per i quali è stato -richiesto l'accesso), quando si vuole risolvere un nuovo pathname il VFS deve -creare una nuova dentry e caricare l'inode corrispondente in memoria. - -Questo procedimento viene eseguito dal metodo \texttt{lookup()} dell'inode -della directory che contiene il file; questo viene installato nelle relative -strutture in memoria quando si effettua il montaggio lo specifico filesystem -su cui l'inode va a vivere. - -Una volta che il VFS ha a disposizione la dentry (ed il relativo inode) -diventa possibile accedere alle varie operazioni sul file come la -\texttt{open} per aprire il file o la \texttt{stat} per leggere i dati -dell'inode e passarli in user space. - -L'apertura di un file richiede comunque un'altra operazione, l'allocazione di -una struttura di tipo \texttt{file} in cui viene inserito un puntatore alla -dentry e una struttura \verb|f_ops| che contiene i puntatori ai metodi che -implementano le operazioni disponibili sul file. In questo modo i processi in -user space possono accedere alle operazioni attraverso detti metodi, che -saranno diversi a seconda del tipo di file (o dispositivo) aperto (su questo -torneremo in dettaglio in \secref{sec:fileunix_fd}). Un elenco delle operazioni -previste dal kernel è riportato in \ntab. - -\begin{table}[htb] - \centering - \begin{tabular}[c]{c p{7cm}} - \textbf{funzione} & \textbf{operazione} \\ - \hline - \textit{open} & apre il file \\ - \textit{read} & legge dal file \\ - \textit{write} & scrive sul file \\ - \textit{llseek} & sposta la posizione corrente sul file \\ - \textit{ioctl} & accede alle operazioni di controllo - (tramite la \texttt{ioctl})\\ - \textit{readdir} & per leggere il contenuto di una directory \\ - \textit{poll} & \\ - \textit{mmap} & chiamata dalla system call \texttt{mmap}. - mappa il file in memoria\\ - \textit{release} & chiamata quando l'ultima referenza a un file - aperto è chiusa\\ - \textit{fsync} & chiamata dalla system call \texttt{fsync} \\ - \textit{fasync} & chiamate da \texttt{fcntl} quando è abilitato - il modo asincrono per l'I/O su file. \\ - \hline - \end{tabular} - \caption{Operazioni sui file definite nel VFS.} - \label{tab:fileintr_file_operations} -\end{table} +L'organizzazione dei nomi dei file deriva direttamente dall'organizzazione dei +medesimi nell'albero descritto in precedenza; una directory comunque, come già +specificato in \secref{sec:fileintr_vfs}, è solo un particolare tipo di file +che contiene le informazioni che associano un nome al contenuto. + +% Per questo, anche se è usuale parlare di ``file in una directory'' in realtà +% una directory contiene solo delle etichette per fare riferimento ai file +% stessi. + +I manuale delle glibc chiama i nomi contenuti nelle directory +\textsl{componenti} (in inglese \textit{file name components}), noi li +chiameremo più semplicemente nomi. Un file può essere indicato rispetto alla +directory corrente semplicemente specificando il nome da essa contenuto. Una +directory contiene semplicemente un elenco di questi nomi, che possono +corrispondere a un qualunque oggetto del filesystem, compresa un'altra +directory; l'albero viene appunto creato inserendo directory in altre +directory. + +Il nome completo di file generico è composto da una serie di questi +\textsl{componenti} separati da una \texttt{/} (in Linux più \texttt{/} +consecutive sono considerate equivalenti ad una sola). Il nome completo di un +file viene usualmente chiamato \textit{pathname}, e anche se il manuale della +glibc depreca questo nome (poiché genererebbe confusione, dato che con +\textit{path} si indica anche un insieme di directory su cui effettuare una +ricerca, come quello in cui si cercano i comandi); l'uso è ormai così comune +che è senz'altro più chiaro dell'alternativa proposta. + +Il processo con cui si associa ad un pathname uno specifico file è chiamato +risoluzione del nome (\textit{file name resolution} o \textit{pathname + resolution}). La risoluzione viene fatta esaminando il pathname da destra a +sinistra e localizzando ogni nome nella directory indicata dal nome +precedente: ovviamente perché il procedimento funzioni occorre che i nomi +indicati come directory esistano e siano effettivamente directory, inoltre i +permessi devono consentire l'accesso. + +Se il pathname comincia per \texttt{/} la ricerca parte dalla directory radice +del processo; questa, a meno di un \textit{chroot} (su cui torneremo in +seguito, vedi \secref{sec:xxx_chroot}) è la stessa per tutti i processi ed +equivale alla directory radice dell'albero (come descritto in +\secref{sec:fileintr_organization}): in questo caso si parla di un pathname +\textsl{assoluto}. Altrimenti la ricerca parte dalla directory corrente (su +cui torneremo più avanti in \secref{sec:filedir_work_dir}) ed il pathname è +detto \textsl{relativo}. + +I nomi \texttt{.} e \texttt{..} hanno un significato speciale e vengono +inseriti in ogni directory, il primo fa riferimento alla directory corrente e +il secondo alla directory \textsl{genitore} (\textit{parent directory}) cioè +la directory che contiene il riferimento alla directory corrente; nel caso +questa sia la directory radice allora il riferimento è a se stessa. -In questo modo per ciascun file diventano utilizzabili una serie di operazioni -(non è dette che tutte siano disponibili), che costituiscono l'interfaccia -astratta del VFS, e qualora se ne voglia eseguire una il kernel andrà ad -utilizzare la opportuna routine dichiarata in \verb|f_ops| appropriata al tipo -di file in questione. - -Così sarà possibile scrivere sulla porta seriale come su un file di dati -normale; ovviamente certe operazioni (nel caso della seriale ad esempio la -\textit{seek}) non saranno disponibili, però con questo sistema l'utilizzo di -diversi filesystem (come quelli usati da Windows o MacOs) è immediato e -(relativamente) trasparente per l'utente ed il programmatore. - -\subsection{Il controllo di accesso} -\label{sec:fileintr_access_ctrl} - -In unix è implementata da qualunque filesystem standard una forma elementare -(ma adatta alla maggior parte delle esigenze) di controllo di accesso ai -files. Torneremo sull'argomento in dettaglio più avanti (vedi -\secref{sec:filedir_access_control}), qui ci limitiamo ad una introduzione dei -concetti essenziali. - -Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo Unix, -e non è detto che sia applicabile (ed infatti non è vero per il filesystem di -Windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono -di implementare le ACL (\textit{Access Control List}) che sono un meccanismo -di controllo di accesso molto più sofisticato. - -Ad ogni file Unix associa sempre l'utente che ne è proprietario (il cosiddetto -\textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli uid e -gid accennato in \secref{sec:intro_usergroup}, e un insieme di permessi che -sono divisi in tre classi, e cioè attribuiti rispettivamente al proprietario, -a qualunque utente faccia parte del gruppo cui appartiene il file, e a tutti -gli altri utenti. - -I permessi sono espressi da un insieme di 12 bit: di questi i nove meno -significativi sono usati a gruppi di tre per indicare i permessi base di -lettura, scrittura ed esecuzione (indicati rispettivamente con le lettere -\textit{w}, \textit{r} \textit{x}) applicabili rispettivamente al -proprietario, al gruppo, a tutti (una descrizione più dettagliata dei vari -permessi associati ai file è riportata in \secref{sec:filedir_suid_sgid}). I -restanti tre bit sono usati per indicare alcune caratteristiche più complesse -(\textit{suid}, \textit{sgid}, e \textit{sticky}) su cui pure torneremo in -seguito (vedi \secref{sec:filedir_suid_sgid} e \secref{sec:filedir_sticky}). - -Tutte queste informazioni sono tenute per ciascun file nell'inode. Quando un -processo cerca l'accesso al file esso controlla i propri uid e gid -confrontandoli con quelli del file e se l'operazione richiesta è compatibile -con i permessi associati al file essa viene eseguita, altrimenti viene -bloccata ed è restituito un errore di \texttt{EPERM}. Questo procedimento non -viene eseguito per l'amministratore di sistema (il cui uid è zero) il quale ha -pertanto accesso senza restrizione a qualunque file del sistema. - -In realtà il procedimento è più complesso di quanto descritto in maniera -elementare qui; inoltre ad un processo sono associati diversi identificatori, -torneremo su questo in maggiori dettagli in seguito in \secref{sec:proc_perms}. \subsection{I tipi di files} \label{sec:fileintr_file_types} -Come detto in precedenza esistono vari tipi di oggetti implementati del VFS -per i quali è disponibile l'interfaccia astratta da esso provveduta. Un elenco -dei vari tipi di file è il seguente: - +Come detto in precedenza in unix esistono vari tipi di file, in Linux questi +sono implementati come oggetti del \textit{Virtual File System} (vedi +\secref{sec:fileintr_vfs}) e sono presenti in tutti i filesystem unix-like +utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal Virtual +File System è riportato in \ntab. + +Si tenga ben presente che questa classificazione non ha nulla a che fare con +la classificazione sui tipi di file (che in questo caso sono sempre file di +dati) in base al loro contenuto, o tipo di accesso. + \begin{table}[htb] \begin{center} \begin{tabular}[c]{l l p{7cm}} - \multicolumn{2}{c}{\textbf{Nome}} & \textbf{Descrizione} \\ + \multicolumn{2}{c}{\textbf{Tipo di file}} & \textbf{Descrizione} \\ \hline \textit{regular file} & \textsl{file normale} & un file che contiene dei dati (l'accezione normale di file) \\ @@ -250,43 +160,35 @@ dei vari tipi di file \end{center} \end{table} -Tutto ciò non ha ovviamente nulla a che fare con la classificazione sui tipi -di file (in questo caso file di dati) in base al loro contenuto, o tipo di -accesso. Una delle differenze principali con altri sistemi operativi (come il +Infatti una delle differenze principali con altri sistemi operativi (come il VMS o Windows) è che per Unix tutti i file di dati sono identici e contengono -un flusso continuo di bytes; non esiste cioè differenza per come vengono visti +un flusso continuo di bytes. Non esiste cioè differenza per come vengono visti dal sistema file di diverso contenuto o formato (come nel caso di quella fra file di testo e binari che c'è in Windows) né c'è una strutturazione a record -per il cosiddetto ``accesso diretto'' come nel caso del VMS. -% (con i kernel -% della serie 2.4 è disponibile una forma di accesso diretto ai dischi il -% \textit{raw access} che però non ha nulla a che fare con questo). +per il cosiddetto ``accesso diretto'' come nel caso del VMS\footnote{con i + kernel della serie 2.4 è disponibile una forma di accesso diretto ai dischi + (il \textit{raw access}) attraverso dei device file appositi, che però non + ha nulla a che fare con questo}. Una seconda differenza è nel formato dei file ASCII; in Unix la fine riga è codificata in maniera diversa da Windows o MacIntosh, in particolare il fine riga è il carattere \texttt{LF} (o \verb|\n|) al posto del \texttt{CR} (\verb|\r|) del mac e del \texttt{CR LF} di Windows. Questo può causare alcuni -problemi qualora si facciano assunzioni sul terminatore della riga. - - -\section{Una panoramica sull'uso dei file} -\label{sec:fileintr_io_overview} +problemi qualora nei programmi si facciano assunzioni sul terminatore della +riga. -Per poter accedere al contenuto dei file occorre anzitutto aprirlo. Questo -crea un canale di comunicazione che permette di eseguire una serie di -operazioni. Una volta terminate le operazioni, il file dovrà essere chiuso, e -questo chiuderà il canale di comunicazione impedendo ogni ulteriore -operazione. \subsection{Le due interfacce ai file} \label{sec:fileintr_io_api} In unix le modalità di accesso ai file e le relative interfacce di -programmazione sono due, basate su due diversi meccanismi di connessione. +programmazione sono due, basate su due diversi meccanismi con cui è possibile +accedere al loro contenuto. La prima è l'interfaccia standard di unix, quella che il manuale delle glibc -chiama interfaccia dei descrittore di file (o \textit{file descriptor}). È +chiama interfaccia dei descrittori di file (o \textit{file descriptor}). È un'interfaccia specifica di unix e provvede un accesso non bufferizzato. + L'interfaccia è primitiva ed essenziale, l'accesso viene detto non bufferizzato in quanto la lettura e la scrittura vengono eseguite chiamando direttamente le system call del kernel (in realtà il kernel effettua al suo @@ -298,11 +200,11 @@ nell'header \texttt{unistd.h}. La seconda interfaccia è quella che il manuale della glibc chiama degli \textit{stream}, essa provvede funzioni più evolute e un accesso bufferizzato (controllato dalla implementazione fatta dalle librerie del C). Questa è -l'interfaccia standard usata dal linguaggio C e perciò si trova anche su tutti -i sistemi non Unix. Gli stream sono oggetti complessi e sono rappresentati da -puntatori ad un opportuna struttura definita dalle librerie del C, si accede -ad essi sempre in maniera indiretta utilizzando il tipo \texttt{FILE *}. -L'interfaccia è definita nell'header \texttt{stdio.h}. +l'interfaccia standard specificata dall'ANSI C e perciò si trova anche su +tutti i sistemi non Unix. Gli stream sono oggetti complessi e sono +rappresentati da puntatori ad un opportuna struttura definita dalle librerie +del C, si accede ad essi sempre in maniera indiretta utilizzando il tipo +\texttt{FILE *}. L'interfaccia è definita nell'header \texttt{stdio.h}. Entrambe le interfacce possono essere usate per l'accesso ai file come agli altri oggetti del VFS (pipes, socket, device), ma per poter accedere alle @@ -333,6 +235,7 @@ essendo questi ultimi definiti nello standard ANSI C; l'interfaccia con i file descriptor invece segue solo lo standard POSIX.1 dei sistemi unix ed è pertanto di portabilità più limitata. + \subsection{Caratteristiche specifiche dei file in unix} \label{sec:fileint_unix_spec} @@ -371,7 +274,7 @@ accesso cancellato da un altro processo, sarà sempre possibile mantenere l'accesso ai dati, e lo spazio su disco non verrà rilasciato fintanto che il file non sarà chiuso e l'ultimo riferimento cancellato. È pertanto possibile (come vedremo -in dettaglio in \secref{sec:filedir_link}) aprire un file provvisorio per +in dettaglio in \secref{sec:fileintr_link}) aprire un file provvisorio per cancellarlo immediatamente dopo; in questo modo all'uscita del programma il file scomparirà definitivamente dal disco, ma il file ed il suo contenuto saranno disponibili per tutto il tempo in cui il processo è attivo. @@ -385,3 +288,363 @@ programmi adottano delle convenzioni per i nomi dei file, ad esempio il codice C normalmente si mette in file con l'estensione .c, ma questa è, appunto, solo una convenzione. + + +\section{L'architettura della gestione dei file} +\label{sec:fileintr_architecture} + +Per capire fino in fondo le proprietà di files e directories in un sistema +unix ed il funzionamento delle relative funzioni di manipolazione occorre una +breve introduzione sulla gestione dei medesimo e sugli oggetti su cui è basato +un filesystem unix. In particolare occorre tenere presente dov'è che si situa +la divisione fondamentale fra kernel space e user space che tracciavamo al +\capref{cha:intro_unix}. + +In questa sezione esamineremo come viene implementato l'accesso ai files in +Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo +poi in maniera un po' più dettagliata il filesystem standard di Linux, +l'\texttt{ext2}, come esempio di un filesystem unix-like. + + +% in particolare si riprenderà, approfondendolo sul piano +% dell'uso nelle funzioni di libreria, il concetto di \textit{inode} di cui +% abbiamo brevemente accennato le caratteristiche (dal lato dell'implementazione +% nel kernel) in \secref{sec:fileintr_vfs}. + +\subsection{Il \textit{virtual filesystem} di Linux} +\label{sec:fileintr_vfs} + +% Questa sezione riporta informazioni sui dettagli di come il kernel gestisce i +% files. L'argomento è abbastanza ``esoterico'' e questa sezione può essere +% saltata ad una prima lettura; è bene però tenere presente che vengono +% introdotti qui alcuni termini che potranno comparire in seguito, come +% \textit{inode}, \textit{dentry}, \textit{dcache}. + +In Linux il concetto di \textit{everything is a file} è stato implementato +attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è +l'interfaccia che il kernel rende disponibile ai programmi in user space +attraverso la quale vengono manipolati i files; esso provvede un livello di +indirezione che permette di collegare le operazioni di manipolazione sui files +alle operazioni di I/O e gestisce l'organizzazione di questi ultimi nei vari +modi in cui diversi filesystem la effettuano, permettendo la coesistenza +di filesystem differenti all'interno dello stesso albero delle directory + +Quando un processo esegue una system call che opera su un file il kernel +chiama sempre una funzione implementata nel VFS; la funzione eseguirà le +manipolazioni sulle strutture generiche e utilizzaerà poi la chiamata alla +opportune routine del filesystem specifico a cui si fa riferimento. Saranno +queste a chiamare le funzioni di più basso livello che eseguono le operazioni +di I/O sul dispositivo fisico, secondo lo schema riportato in \nfig. + +\begin{figure}[htb] + \centering + \includegraphics[width=7cm]{img/vfs.eps} + \caption{Schema delle operazioni del VFS} + \label{fig:fileintr_VFS_scheme} +\end{figure} + +Il VFS definisce un insieme di funzioni che tutti i filesystem devono +implementare. L'interfaccia comprende tutte le funzioni che riguardano i +files; le operazioni sono suddivise su tre tipi di oggetti: filesystem, inode +e file, corrispondenti a tre apposite strutture definite nel kernel. + +Il VFS usa una tabella mantenuta dal kernel che contiene il nome di ciascun +filesystem supportato, quando si vuole inserire il supporto di un nuovo +filesystem tutto quello che occorre è una chiamata alla funzione +\func{register\_filesystem} passando un'apposita struttura che +(\var{file\_system\_type}) contiene l'implementazione edl medesimo, che sarà +aggiunta alla citata tabella. + + +In questo modo quando viene effettuata la richiesta di montare un nuovo disco +(o qualunque altro \textit{block device} che può contenere un filesystem), il +VFS può ricavare dalla citata tabella il puntatore alle funzioni da chiamare +nelle operazioni di montaggio. Quest'ultima è responsabile di leggere da disco +il superblock (vedi \ref{sec:fileintr_ext2}), inizializzare tutte le +variabili interne e restituire uno speciale descrittore dei filesystem montati +al VFS; attraverso quest'ultimo diventa possible accedere alle routine +specifiche per l'uso di quel filesystem. + +Il primo oggetto usato dal VFS è il descrittore di filesystem, un puntatore ad +una apposita struttura che contiene vari dati come le informazioni comuni ad +ogni filesystem, i dati privati relativi a quel filesystem specifico, e i +puntatori alle funzioni del kernel relative al filesystem. Il VFS può così +usare le funzioni contenute nel filesystem decriptor per accedere alle routine +specifiche di quel filesystem. + +Gli altri due descrittori usati dal VFS sono relativi agli altri due oggetti +su cui è strutturata l'interfaccia. Ciascuno di essi contiene le informazioni +relative al file in uso, insieme ai puntatori alle funzioni dello specifico +filesystem usate per l'accesso dal VFS; in particolare il descrittore +dell'inode contiene i puntatori alle funzioni che possono essere usate su +qualunque file (come \func{link}, \func{stat} e \func{open}), mentre il +descrittore di file contiene i puntatori alle funzioni che vengono usate sui +file già aperti. + + +\subsection{Il funzionamento del VFS} +\label{sec:fileintr_vfs_work} + +La funzione più fondamentale implementata dal VFS è la system call +\texttt{open} che permette di aprire un file. Dato un pathname viene eseguita +una ricerca dentro la \textit{directory entry cache} (in breve +\textit{dcache}), una tabella di hash che contiene tutte le \textit{directory + entry} (in breve \textit{dentry}) che permette di associare in maniera +rapida ed efficiente il pathname a una specifica dentry. + +Una singola dentry contiene in genere il puntatore ad un \textit{inode}; +quest'ultimo è la struttura base che sta sul disco e che identifica un singolo +oggetto del VFS sia esso un file ordinario, una directory, una FIFO, un file +di dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal +VFS (sui tipi di ``files'' possibili torneremo in seguito). A ciascuno di essi +è associata pure una struttura che sta in memoria, e che oltre alle +informazioni sullo specifico file contiene pure il riferimento alle funzioni +(i \textsl{metodi}) da usare per poterlo manipolare. + +Le dentries ``vivono'' in memoria e non vengono mai salvate su disco, vengono +usate per motivi di velocità, gli inodes invece stanno su disco e vengono +copiati in memoria quando serve, ed ogni cambiamento viene copiato +all'indietro sul disco, gli inodes che stanno in memoria sono inodes del VFS +ed è ad essi che puntano le singole dentry. + +La dcache costituisce perciò una sorta di vista completa di tutto l'albero dei +files, ovviamente per non riempire tutta la memoria questa vista è parziale +(la dcache cioè contiene solo le dentry per i file per i quali è stato +richiesto l'accesso), quando si vuole risolvere un nuovo pathname il VFS deve +creare una nuova dentry e caricare l'inode corrispondente in memoria. + +Questo procedimento viene eseguito dal metodo \texttt{lookup()} dell'inode +della directory che contiene il file; questo viene installato nelle relative +strutture in memoria quando si effettua il montaggio lo specifico filesystem +su cui l'inode va a vivere. + +Una volta che il VFS ha a disposizione la dentry (ed il relativo inode) +diventa possibile accedere alle varie operazioni sul file come la +\texttt{open} per aprire il file o la \texttt{stat} per leggere i dati +dell'inode e passarli in user space. + +L'apertura di un file richiede comunque un'altra operazione, l'allocazione di +una struttura di tipo \texttt{file} in cui viene inserito un puntatore alla +dentry e una struttura \verb|f_ops| che contiene i puntatori ai metodi che +implementano le operazioni disponibili sul file. In questo modo i processi in +user space possono accedere alle operazioni attraverso detti metodi, che +saranno diversi a seconda del tipo di file (o dispositivo) aperto (su questo +torneremo in dettaglio in \secref{sec:fileunix_fd}). Un elenco delle operazioni +previste dal kernel è riportato in \ntab. + +\begin{table}[htb] + \centering + \begin{tabular}[c]{|c|p{7cm}|} + \hline + \textbf{funzione} & \textbf{operazione} \\ + \hline + \hline + \textit{open} & apre il file \\ + \textit{read} & legge dal file \\ + \textit{write} & scrive sul file \\ + \textit{llseek} & sposta la posizione corrente sul file \\ + \textit{ioctl} & accede alle operazioni di controllo + (tramite la \texttt{ioctl})\\ + \textit{readdir} & per leggere il contenuto di una directory \\ + \textit{poll} & \\ + \textit{mmap} & chiamata dalla system call \texttt{mmap}. + mappa il file in memoria\\ + \textit{release} & chiamata quando l'ultima referenza a un file + aperto è chiusa\\ + \textit{fsync} & chiamata dalla system call \texttt{fsync} \\ + \textit{fasync} & chiamate da \texttt{fcntl} quando è abilitato + il modo asincrono per l'I/O su file. \\ + \hline + \end{tabular} + \caption{Operazioni sui file definite nel VFS.} + \label{tab:fileintr_file_operations} +\end{table} + +In questo modo per ciascun file diventano utilizzabili una serie di operazioni +(non è dette che tutte siano disponibili), che costituiscono l'interfaccia +astratta del VFS, e qualora se ne voglia eseguire una il kernel andrà ad +utilizzare la opportuna routine dichiarata in \verb|f_ops| appropriata al tipo +di file in questione. + +Così sarà possibile scrivere sulla porta seriale come su un file di dati +normale; ovviamente certe operazioni (nel caso della seriale ad esempio la +\textit{seek}) non saranno disponibili, però con questo sistema l'utilizzo di +diversi filesystem (come quelli usati da Windows o MacOs) è immediato e +(relativamente) trasparente per l'utente ed il programmatore. + + +\subsection{Il funzionamento di un filesystem unix} +\label{sec:fileintr_filesystem} + +Come già accennato in \secref{sec:fileintr_organization} Linux (ed ogni unix +in generale) organizza i dati che tiene su disco attraverso l'uso di un +filesystem. Una delle caratteristiche di Linux rispetto agli altri unix è +quella di poter supportare grazie al VFS una enorme quantità di filesystem +diversi, ognuno dei quali ha una sua particolare struttura e funzionalità +proprie; per questo non entreremo nei dettagli di un filesystem specifico, ma +daremo una descrizione a grandi linee che si adatta alle caratteristiche +comuni di un qualunque filesystem standard unix. + +Dato un disco lo spazio fisico viene usualmente diviso in partizioni; ogni +partizione può contenere un filesystem; la strutturazione tipica +dell'informazione su un disco è riportata in \nfig; in essa si fa riferimento +alla struttura del filesystem ext2, che prevede una separazione dei dati in +\textit{blocks group} che replicano il superblock (ma sulle caratteristiche di +ext2 torneremo in \secref{sec:fileintr_ext2}). È comunque caratteristica +comune di tutti i filesystem unix, indipendentemente da come poi viene +strutturata nei dettagli questa informazione, prevedere una divisione fra la +lista degli inodes e lo spazio a disposizione per i dati e le directory. + +\begin{figure}[htb] + \centering + \includegraphics[width=9cm]{img/disk_struct.eps} + \caption{Organizzazione dello spazio su un disco in partizioni e filesystem} + \label{fig:fileintr_disk_filesys} +\end{figure} + +Se si va ad esaminare con maggiore dettaglio la strutturazione +dell'informazione all'interno del singolo filesystem (tralasciando i dettagli +relativi al funzionamento del filesystem stesso come la strutturazione in +gruppi dei blocchi, il superblock e tutti i dati di gestione) possiamo +esemplificare la situazione con uno schema come quello esposto in \nfig. + +\begin{figure}[htb] + \centering + \includegraphics[width=11cm]{img/filesys_struct.eps} + \caption{Strutturazionne dei dati all'interno di un filesystem} + \label{fig:fileintr_filesys_detail} +\end{figure} + +Da \curfig\ si evidenziano alcune caratteristiche base di ogni filesystem su +cui è bene porre attenzione in quanto sono fondamentali per capire il +funzionamento delle funzioni che manipolano i file e le directory su cui +torneremo in seguitp; in particolare è opportuno ricordare sempre che: + +\begin{enumerate} + +\item L'\textit{inode} contiene tutte le informazioni riguardanti il file: il + tipo di file, i permessi di accesso, le dimensioni, i puntatori ai blocchi + fisici che contengono i dati e così via; le informazioni che la funzione + \texttt{stat} fornisce provengono dall'\textit{inode}; dentro una directory + si troverà solo il nome del file e il numero dell'\textit{inode} ad esso + associato, cioè quella che da qui in poi chiameremo una \textsl{voce} + (traduzione approssimata dell'inglese \textit{directory entry}, che non + useremo anche per evitare confusione con le \textit{dentries} del kernel di + cui si parlava in \secref{sec:fileintr_vfs}). + +\item Come mostrato in \curfig si possono avere più voci che puntano allo + stesso \textit{inode}. Ogni \textit{inode} ha un contatore che contiene il + numero di riferimenti (\textit{link count}) che sono stati fatti ad esso; + solo quando questo contatore si annulla i dati del file vengono + effettivamente rimossi dal disco. Per questo la funzione per cancellare un + file si chiama \func{unlink}, ed in realtà non cancella affatto i dati del + file, ma si limita a eliminare la relativa voce da una directory e + decrementare il numero di riferimenti nell'\textit{inode}. + +\item Il numero di \textit{inode} nella voce si riferisce ad un \textit{inode} + nello stesso filesystem e non ci può essere una directory che contiene + riferimenti ad \textit{inodes} relativi ad altri filesystem. Questo limita + l'uso del comando \cmd{ln} (che crea una nuova voce per un file + esistente, con la funzione \func{link}) al filesystem corrente. + +\item Quando si cambia nome ad un file senza cambiare filesystem il contenuto + del file non deve essere spostato, viene semplicemente creata una nuova voce + per l'\textit{inode} in questione e rimossa la vecchia (questa è la modalità + in cui opera normalmente il comando \cmd{mv} attraverso la funzione + \func{rename}). + +\end{enumerate} + +Infine è bene avere presente che essendo file pure loro, esiste un numero di +riferimenti anche per le directories; per cui se ad esempio a partire dalla +situazione mostrata in \curfig\ creiamo una nuova directory \texttt{img} nella +directory \file{gapil}: avremo una situazione come quella in \nfig, dove per +chiarezza abbiamo aggiunto dei numeri di inode. + +\begin{figure}[htb] + \centering + \includegraphics[width=11cm]{img/dir_links.eps} + \caption{Organizzazione dei link per le directory} + \label{fig:fileintr_dirs_link} +\end{figure} + +La nuova directory avrà allora un numero di riferimenti pari a due, in quanto +è referenziata dalla directory da cui si era partiti (in cui è inserita la +nuova voce che fa riferimento a \file{img}) e dalla voce \file{.} +che è sempre inserita in ogni directory; questo vale sempre per ogni directory +che non contenga a sua volta altre directories. Al contempo la directory da +cui si era partiti avrà un numero di riferiementi di almeno tre, in quanto +adesso sarà referenziata anche dalla voce \file{..} di \file{img}. + +\subsection{Il filesystem \texttt{ext2}} +\label{sec:fileintr_ext2} + +Il filesystem standard usato da Linux è il cosidetto \textit{second extended + filesystem}, identificato dalla sigla \texttt{ext2}. Esso supporta tutte le +caratteristiche di un filesystem standard unix, è in grado di gestire +filenames lunghi (256 caratteri, estendibili a 1012), una dimensione fino a +4~Tb. + +Oltre alle caratteristiche standard ext2 fornisce alcune estensioni che non +sono presenti sugli altri filesystem unix. Caratteristiche particolari di ext2 +sono le seguenti'' + +\begin{itemize} +\item i \textit{file attributes} consentono di modificare il comportamento del + kernel quando agisce su gruppi di file. Possono essere settati su file e + directory e in quest'ultimo caso i nuovi file creati nella directory + ereditano i suoi attributi. +\item sono supportate entrambe le semantiche di BSD e SysV come opzioni di + montaggio. La semantica BSD comporta che i file in una directory sono creati + con lo stesso identificatore di gruppo della directory che li contiene. La + semantica SysV comporta che i file vengono creati con l'identificatore del + gruppo primario del processo, eccetto il caso in cui la directory ha il bit + di setgid settata (per una descrizione dettagliata del sigificato di questi + termini si veda \secref{sec:filedir_access_control}), nel qual caso file e + sottodirectory ereditano sia il group id che il setgid. +\item l'amministratore può scegliere la dimensione dei blocchi del filesystem + in fase di creazione, a seconda delle sue esigenze (blocchi più grandi + permettono un accesso più veloce, ma sprecano più spazio disco). +\item il filesystem implementa link simbolici veloci, in cui il nome del file + non è salvato su un blocco, ma tenuto all'interno dell'inode (evitando + letture multiple e spreco di spazio), non tutti i nomi però possono essere + gestiti così per limiti di spazio (il limite è 60 caratteri). +\item vengono supportati i file immutabili (che possono solo essere letti) per + la protezione di file di configurazione sensibili, o file + \textit{append-only} che possono essere aperti in scrittura solo per + aggiungere dati (caratteristica utilizzabile per la protezione dei file di + log). +\end{itemize} + +La struttura di ext2 è stata ispirata a quella del filesystem di BSD, un +filesystem è composto da un insieme di blocchi, la struttura generale è quella +riportata in \figref{fig:fileintr_filesys_detail}, in cui la partizione è +divisa in gruppi di blocchi. + +Ciascun gruppo di blocchi contiene una copia delle informazioni essenziali del +filesystem (superblock e descrittore del filesystem sono quindi ridondati) per +una maggiore affidabilità e possibilità di recupero in caso di corruzione del +superblock principale. + + +\begin{figure}[htb] + \centering + \includegraphics[width=9cm]{img/dir_struct.eps} + \caption{Struttura delle directory nel \textit{second extented filesystem}.} + \label{fig:fileintr_ext2_dirs} +\end{figure} + +L'utilizzo di raggrupamenti di blocchi ha inoltre degli effetti positivi nelle +performance dato che viene ridotta la distanza fra i dati e la tabella degli +inodes. + +Le directory sono implementate come una linked list con voci di dimensione +variabile. Ciascuna voce della lista contiene il numero di inode, la sua +lunghezza, il nome del file e la sua lunghezza, secondo lo schema in \curfig; +in questo modo è possibile implementare nomi per i file anche molto lunghi +(fino a 1024 caratteri) senza sprecare spazio disco. + + + + +