X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileintro.tex;fp=fileintro.tex;h=995129189d236fba35bf549e48a1364276c2cba9;hp=374a87017cb9b7303cee2ab1ac5ea6d56d5307cd;hb=2414addb7861eb72315a3de58b6f2cb5c83ab6ed;hpb=ed54132fb0762894a86b100023f9d04fc4028975 diff --git a/fileintro.tex b/fileintro.tex index 374a870..9951291 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -9,720 +9,10 @@ %% License". %% -\chapter{L'architettura dei file} -\label{cha:file_intro} - -Uno dei concetti fondamentali dell'architettura di un sistema 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 dei normali -file di dati. - -Questo significa che si può accedere a qualunque periferica del computer, -dalla seriale, alla parallela, alla console, e agli stessi dischi attraverso i -cosiddetti \index{file!di~dispositivo} file di dispositivo (i cosiddetti -\textit{device file}). 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 una descrizione dell'architettura dei file in -Linux, iniziando da una panoramica sulle caratteristiche principali delle -interfacce con cui i processi accedono ai file (che tratteremo in dettaglio -nei capitoli seguenti), per poi passare ad una descrizione più dettagliata -delle modalità con cui detto accesso viene realizzato dal sistema. - - - -\section{L'architettura generale} -\label{sec:file_access_arch} - -Per poter accedere ai file, il kernel deve mettere a disposizione dei -programmi le opportune interfacce che consentano di leggerne il contenuto; il -sistema cioè deve provvedere ad organizzare e rendere accessibile in maniera -opportuna l'informazione tenuta sullo spazio grezzo disponibile sui dischi. -Questo viene fatto strutturando l'informazione sul disco attraverso quello che -si chiama un \textit{filesystem} (vedi sez.~\ref{sec:file_arch_func}), essa -poi viene resa disponibile ai processi attraverso quello che viene chiamato il -\textsl{montaggio} del \textit{filesystem}. - -In questa sezione faremo una panoramica generica su come il sistema presenta -i file ai processi, trattando l'organizzazione di file e directory, i tipi di -file ed introducendo le interfacce disponibili e le loro caratteristiche. - - -\subsection{L'organizzazione di file e directory} -\label{sec:file_organization} - -\itindbeg{pathname} -In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i -file vengono tenuti all'interno di un unico albero la cui radice (quella che -viene chiamata \textit{root directory}) viene montata all'avvio. Un file -viene identificato dall'utente usando quello che viene chiamato -\textit{pathname}\footnote{il manuale della \acr{glibc} depreca questa - nomenclatura, che genererebbe confusione poiché \textit{path} indica anche - un insieme di directory su cui effettuare una ricerca (come quello in cui si - cercano i comandi). Al suo posto viene proposto l'uso di \textit{filename} e - di componente per il nome del file all'interno della directory. Non - seguiremo questa scelta dato che l'uso della parola \textit{pathname} è - ormai così comune che mantenerne l'uso è senz'altro più chiaro - dell'alternativa proposta.}, cioè il percorso che si deve fare per accedere -al file a partire dalla \textit{root directory}, che è composto da una serie -di nomi separati da una ``\file{/}''. - -All'avvio del sistema, completata la fase di inizializzazione, il kernel -riceve dal bootloader l'indicazione di quale dispositivo contiene il -filesystem da usare come punto di partenza e questo viene montato come radice -dell'albero (cioè nella directory \file{/}); tutti gli ulteriori filesystem -che possono essere su altri dispositivi dovranno poi essere inseriti -nell'albero montandoli su opportune directory del filesystem montato come -radice. - -Alcuni filesystem speciali (come \file{/proc} che contiene un'interfaccia ad -alcune strutture interne del kernel) sono generati automaticamente dal kernel -stesso, ma anche essi devono essere montati all'interno dell'albero dei file. - -Una directory, come vedremo in maggior dettaglio in -sez.~\ref{sec:file_vfs_work}, è anch'essa un file, solo che è un file -particolare che il kernel riconosce come tale. Il suo scopo è quello di -contenere una lista di nomi di file e le informazioni che associano ciascun -nome al contenuto. Dato che questi nomi possono corrispondere ad un qualunque -oggetto del filesystem, compresa un'altra directory, si ottiene naturalmente -un'organizzazione ad albero inserendo nomi di directory in altre directory. - -Un file può essere indicato rispetto alla directory corrente semplicemente -specificandone il nome\footnote{il manuale delle \acr{glibc} chiama i nomi - contenuti nelle directory \textsl{componenti} (in inglese \textit{file name - components}), noi li chiameremo più semplicemente \textsl{nomi} o - \textsl{voci}.} da essa contenuto. All'interno dello stesso albero si -potranno poi inserire anche tutti gli altri oggetti visti attraverso -l'interfaccia che manipola i file come le fifo, i link, i socket e gli stessi -\index{file!di~dispositivo} file di dispositivo (questi ultimi, per -convenzione, sono inseriti nella directory \file{/dev}). - -Il nome completo di un file viene chiamato \textit{pathname} ed il -procedimento con cui si individua il file a cui esso fa riferimento è chiamato -risoluzione del nome (\textit{filename resolution} o \textit{pathname - resolution}). La risoluzione viene fatta esaminando il \textit{pathname} da -sinistra a destra e localizzando ogni nome nella directory indicata dal nome -precedente usando il carattere ``\texttt{/}'' come separatore\footnote{nel - caso di nome vuoto, il costrutto \file{//} viene considerato equivalente a - \file{/}.}: ovviamente, perché il procedimento funzioni, occorre che i nomi -indicati come directory esistano e siano effettivamente directory, inoltre i -permessi (si veda sez.~\ref{sec:file_access_control}) devono consentire -l'accesso all'intero \textit{pathname}. - -Se il \textit{pathname} comincia con il carattere ``\texttt{/}'' la ricerca -parte dalla directory radice del processo; questa, a meno di un \func{chroot} -(su cui torneremo in sez.~\ref{sec:file_chroot}) è la stessa per tutti i -processi ed equivale alla directory radice dell'albero dei file: in questo -caso si parla di un \textsl{pathname assoluto} \itindsub{pathname}{assoluto}. -Altrimenti la ricerca parte dalla directory corrente (su cui torneremo in -sez.~\ref{sec:file_work_dir}) ed il pathname è detto -\itindsub{pathname}{relativo} \textsl{pathname relativo}. - -I nomi ``\file{.}'' e ``\file{..}'' hanno un significato speciale e vengono -inseriti in ogni directory: il primo fa riferimento alla directory corrente e -il secondo alla directory \textsl{genitrice} (o \textit{parent directory}) -cioè la directory che contiene il riferimento alla directory corrente; nel -caso la directory corrente coincida con la directory radice, allora il -riferimento è a se stessa. - -\itindend{pathname} - - -\subsection{I tipi di file} -\label{sec:file_file_types} - -Come detto in precedenza, in Unix esistono vari tipi di file; in Linux questi -sono implementati come oggetti del \textit{Virtual File System} (vedi -sez.~\ref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like -utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal -\itindex{Virtual~File~System} \textit{Virtual File System} è riportato in -tab.~\ref{tab:file_file_types}. - -Si tenga ben presente che questa classificazione non ha nulla a che fare con -la classificazione dei file (che in questo caso sono sempre file di dati) in -base al loro contenuto, o tipo di accesso. Essa riguarda invece il tipo di -oggetti; in particolare è da notare la presenza dei cosiddetti file speciali. -Alcuni di essi, come le \textit{fifo} (che tratteremo in -sez.~\ref{sec:ipc_named_pipe}) ed i \textit{socket} (che tratteremo in -cap.~\ref{cha:socket_intro}) non sono altro che dei riferimenti per utilizzare -delle funzionalità di comunicazione fornite dal kernel. Gli altri sono i -\index{file!di~dispositivo} \textsl{file di dispositivo} (o \textit{device - file}) che costituiscono una interfaccia diretta per leggere e scrivere sui -dispositivi fisici; essi vengono suddivisi in due grandi categorie, \textsl{a - blocchi} e \textsl{a caratteri} a seconda delle modalità in cui il -dispositivo sottostante effettua le operazioni di I/O.\footnote{in sostanza i - dispositivi a blocchi (ad esempio i dischi) corrispondono a periferiche per - le quali è richiesto che l'I/O venga effettuato per blocchi di dati di - dimensioni fissate (ad esempio le dimensioni di un settore), mentre nei - dispositivi a caratteri l'I/O viene effettuato senza nessuna particolare - struttura.} - -\begin{table}[htb] - \footnotesize - \centering - \begin{tabular}[c]{|l|l|p{7cm}|} - \hline - \multicolumn{2}{|c|}{\textbf{Tipo di file}} & \textbf{Descrizione} \\ - \hline - \hline - \textit{regular file} & \textsl{file regolare} & - Un file che contiene dei dati (l'accezione normale di file).\\ - \textit{directory} & \textsl{cartella o direttorio} & - Un file che contiene una lista di nomi associati a degli - \itindex{inode} \textit{inode} (vedi sez.~\ref{sec:file_vfs}).\\ - \textit{symbolic link} & \textsl{collegamento simbolico} & - Un file che contiene un riferimento ad un altro file/directory.\\ - \textit{char device} & \textsl{dispositivo a caratteri} & - Un file che identifica una periferica ad accesso a caratteri.\\ - \textit{block device} & \textsl{dispositivo a blocchi} & - Un file che identifica una periferica ad accesso a blocchi.\\ - \textit{fifo} & ``\textsl{coda}'' & - Un file speciale che identifica una linea di comunicazione software - unidirezionale (vedi sez.~\ref{sec:ipc_named_pipe}).\\ - \textit{socket} & ``\textsl{presa}''& - Un file speciale che identifica una linea di comunicazione software - bidirezionale (vedi cap.~\ref{cha:socket_intro}).\\ - \hline - \end{tabular} - \caption{Tipologia dei file definiti nel VFS} - \label{tab:file_file_types} -\end{table} - -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 byte. 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 ``\textsl{accesso diretto}'' come nel caso del -VMS.\footnote{questo vale anche per i dispositivi a blocchi: la strutturazione - dell'I/O in blocchi di dimensione fissa avviene solo all'interno del kernel, - ed è completamente trasparente all'utente. Inoltre talvolta si parla di - \textsl{accesso diretto} riferendosi alla capacità, che non ha niente a che - fare con tutto ciò, di effettuare, attraverso degli appositi - \index{file!di~dispositivo} file di dispositivo, operazioni di I/O - direttamente sui dischi senza passare attraverso un filesystem, il - cosiddetto \textit{raw access}, introdotto coi kernel della serie 2.4.x ed - in sostanziale disuso.} - -Una seconda differenza è nel formato dei file di testo: in Unix la fine riga è -codificata in maniera diversa da Windows o dal vecchio MacOS, in particolare -il fine riga è il carattere \texttt{LF} (o \verb|\n|) al posto del \texttt{CR} -(\verb|\r|) del vecchio MacOS e del \texttt{CR LF} di Windows.\footnote{per - questo esistono in Linux dei programmi come \cmd{unix2dos} e \cmd{dos2unix} - che effettuano una conversione fra questi due formati di testo.} Questo può -causare alcuni problemi qualora nei programmi si facciano assunzioni sul -terminatore della riga. - -Si ricordi infine che un kernel Unix non fornisce nessun supporto per la -tipizzazione dei file di dati e che non c'è nessun supporto del sistema per le -estensioni come parte del filesystem.\footnote{non è così ad esempio nel - filesystem HFS dei Mac, che supporta delle risorse associate ad ogni file, - che specificano fra l'altro il contenuto ed il programma da usare per - leggerlo. In realtà per alcuni filesystem esiste la possibilità di - associare delle risorse ai file con gli \textit{extended attributes} (vedi - sez.~\ref{sec:file_xattr}), ma è una caratteristica tutt'ora poco - utilizzata, dato che non corrisponde al modello classico dei file in un - sistema Unix.} Ciò nonostante molti programmi adottano delle convenzioni per -i nomi dei file, ad esempio il codice C normalmente si mette in file con -l'estensione \file{.c}; un'altra tecnica molto usata è quella di utilizzare i -primi 4 byte del file per memorizzare un \textit{magic number} che classifichi -il contenuto; entrambe queste tecniche, per quanto usate ed accettate in -maniera diffusa, restano solo delle convenzioni il cui rispetto è demandato -alle applicazioni stesse. - - -\subsection{Le due interfacce ai file} -\label{sec:file_io_api} - -In Linux le modalità di accesso ai file e le relative interfacce di -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 -\textsl{glibc} chiama interfaccia dei descrittori di file (o \textit{file - descriptor}). È un'interfaccia specifica dei sistemi unix-like e fornisce -un accesso non bufferizzato; la tratteremo in dettaglio in -cap.~\ref{cha:file_unix_interface}. - -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 -interno alcune bufferizzazioni per aumentare l'efficienza nell'accesso ai -dispositivi); i \index{file!descriptor} \textit{file descriptor} sono -rappresentati da numeri interi (cioè semplici variabili di tipo \ctyp{int}). -L'interfaccia è definita nell'header \file{unistd.h}. - -La seconda interfaccia è quella che il manuale della \acr{glibc} chiama degli -\index{file!stream} \textit{stream}.\footnote{in realtà una interfaccia con lo - stesso nome è stata introdotta a livello di kernel negli Unix derivati da - \textit{System V}, come strato di astrazione per file e socket; in Linux - questa interfaccia, che comunque ha avuto poco successo, non esiste, per cui - facendo riferimento agli \index{file!stream} \textit{stream} useremo il - significato adottato dal manuale delle \acr{glibc}.} Essa fornisce funzioni -più evolute e un accesso bufferizzato (controllato dalla implementazione fatta -dalle \acr{glibc}), la tratteremo in dettaglio nel -cap.~\ref{cha:files_std_interface}. - -Questa è l'interfaccia standard specificata dall'ANSI C e perciò si trova -anche su tutti i sistemi non Unix. Gli \index{file!stream} \textit{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 \type{FILE *}. L'interfaccia è definita -nell'header \file{stdio.h}. - -Entrambe le interfacce possono essere usate per l'accesso ai file come agli -altri oggetti del VFS (fifo, socket, dispositivi, sui quali torneremo in -dettaglio a tempo opportuno), ma per poter accedere alle operazioni di -controllo (descritte in sez.~\ref{sec:file_fcntl} e sez.~\ref{sec:file_ioctl}) -su un qualunque tipo di oggetto del VFS occorre usare l'interfaccia standard -di Unix con i \textit{file descriptor}. Allo stesso modo devono essere usati i -\index{file!descriptor} \textit{file descriptor} se si vuole ricorrere a -modalità speciali di I/O come il \index{file!locking} \textit{file locking} o -l'I/O non-bloccante (vedi cap.~\ref{cha:file_advanced}). - -Gli \textit{stream} forniscono un'interfaccia di alto livello costruita sopra -quella dei \textit{file descriptor}, che permette di poter scegliere tra -diversi stili di bufferizzazione. Il maggior vantaggio degli \textit{stream} -è che l'interfaccia per le operazioni di input/output è enormemente più ricca -di quella dei \textit{file descriptor}, che forniscono solo funzioni -elementari per la lettura/scrittura diretta di blocchi di byte. In -particolare gli \index{file!stream} \textit{stream} dispongono di tutte le -funzioni di formattazione per l'input e l'output adatte per manipolare anche i -dati in forma di linee o singoli caratteri. - -In ogni caso, dato che gli stream sono implementati sopra l'interfaccia -standard di Unix, è sempre possibile estrarre il \textit{file descriptor} da -uno stream ed eseguirvi operazioni di basso livello, o associare in un secondo -tempo uno \index{file!stream} \textit{stream} ad un \index{file!descriptor} -\textit{file descriptor}. - -In generale, se non necessitano specificatamente le funzionalità di basso -livello, è opportuno usare sempre gli \index{file!stream} \textit{stream} per -la loro maggiore portabilità, essendo questi ultimi definiti nello standard -ANSI C; l'interfaccia con i \index{file!descriptor} \textit{file descriptor} -infatti segue solo lo standard POSIX.1 dei sistemi Unix, ed è pertanto di -portabilità più limitata. - - - -\section{L'architettura della gestione dei file} -\label{sec:file_arch_func} - -In questa sezione esamineremo come viene implementato l'accesso ai file in -Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo -prima le caratteristiche generali di un filesystem di un sistema unix-like, -per poi trattare in maniera un po' più dettagliata il filesystem più usato con -Linux, l'\acr{ext2} (e derivati). - - -\subsection{Il \textit{Virtual File System} di Linux} -\label{sec:file_vfs} - -% articolo interessante: -% http://www.ibm.com/developerworks/linux/library/l-virtual-filesystem-switch/index.html?ca=dgr-lnxw97Linux-VFSdth-LXdW&S_TACT=105AGX59&S_CMP=GRlnxw97 - -\itindbeg{Virtual~File~System} - -In Linux il concetto di \textit{everything is a file} è stato implementato -attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è uno -strato intermedio che il kernel usa per accedere ai più svariati filesystem -mantenendo la stessa interfaccia per i programmi in user space. Esso fornisce -un livello di indirezione che permette di collegare le operazioni di -manipolazione sui file alle operazioni di I/O, e gestisce l'organizzazione di -queste ultime nei vari modi in cui i diversi filesystem le 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 utilizzerà poi la chiamata alle -opportune funzioni 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 -fig.~\ref{fig:file_VFS_scheme}. - -\begin{figure}[!htb] - \centering - \includegraphics[width=7cm]{img/vfs} - \caption{Schema delle operazioni del VFS.} - \label{fig:file_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 file; -le operazioni sono suddivise su tre tipi di oggetti: \textit{filesystem}, -\itindex{inode} \textit{inode} e \textit{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 è chiamare la funzione -\code{register\_filesystem} passandole un'apposita struttura -\code{file\_system\_type} che contiene i dettagli per il riferimento -all'implementazione del 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 sez.~\ref{sec:file_ext2}), inizializzare tutte le variabili -interne e restituire uno speciale descrittore dei filesystem montati al VFS; -attraverso quest'ultimo diventa possibile accedere alle funzioni 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 \textit{filesystem descriptor} per accedere -alle funzioni 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 -\itindex{inode} 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 \textit{Virtual File System}} -\label{sec:file_vfs_work} - -La funzione più importante implementata dal VFS è la system call \func{open} -che permette di aprire un file. Dato un \itindex{pathname} \textit{pathname} -viene eseguita una ricerca dentro la \textit{directory entry cache} (in breve -\textit{dcache}), una tabella che contiene tutte le \textit{directory entry} -(in breve \textit{dentry}) che permette di associare in maniera rapida ed -efficiente il \textit{pathname} a una specifica \textit{dentry}. - -Una singola \textit{dentry} contiene in genere il puntatore ad un -\itindex{inode} \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, un link simbolico, una FIFO, un file di -\index{file!di~dispositivo} dispositivo, o una qualsiasi altra cosa che possa -essere rappresentata dal VFS (i tipi di file riportati in -tab.~\ref{tab:file_file_types}). A ciascuno di essi è associata pure una -struttura che sta in memoria, e che, oltre alle informazioni sullo specifico -file, contiene anche il riferimento alle funzioni (i \textsl{metodi} del VFS) -da usare per poterlo manipolare. - -Le \textit{dentry} ``vivono'' in memoria e non vengono mai salvate su disco, -vengono usate per motivi di velocità, gli \itindex{inode} \textit{inode} invece -stanno su disco e vengono copiati in memoria quando serve, ed ogni cambiamento -viene copiato all'indietro sul disco (aggiornando i cosiddetti -\textsl{metadati} del file), gli \itindex{inode} inode che stanno in memoria -sono \itindex{inode} inode del VFS ed è ad essi che puntano le singole -\textit{dentry}. - -La \textit{dcache} costituisce perciò una sorta di vista completa di tutto -l'albero dei file, ovviamente per non riempire tutta la memoria questa vista è -parziale (la \textit{dcache} cioè contiene solo le \textit{dentry} per i file -per i quali è stato richiesto l'accesso), quando si vuole risolvere un nuovo -\itindex{pathname} \textit{pathname} il VFS deve creare una nuova -\textit{dentry} e caricare \itindex{inode} l'inode corrispondente in memoria. - -Questo procedimento viene eseguito dal metodo \code{lookup()} \itindex{inode} -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 \textit{dentry} (ed il relativo -\textit{inode}) diventa possibile accedere alle varie operazioni sul file come -la \func{open} per aprire il file o la \func{stat} per leggere i dati -\itindex{inode} dell'inode e passarli in user space. - -L'apertura di un file richiede comunque un'altra operazione, l'allocazione di -una struttura di tipo \struct{file} in cui viene inserito un puntatore alla -\textit{dentry} e una struttura \struct{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 sez.~\ref{sec:file_fd}). Un elenco delle -operazioni previste dal kernel è riportato in -tab.~\ref{tab:file_file_operations}. - -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|p{8cm}|} - \hline - \textbf{Funzione} & \textbf{Operazione} \\ - \hline - \hline - \textsl{\code{open}} & Apre il file (vedi sez.~\ref{sec:file_open}).\\ - \textsl{\code{read}} & Legge dal file (vedi sez.~\ref{sec:file_read}).\\ - \textsl{\code{write}} & Scrive sul file (vedi - sez.~\ref{sec:file_write}).\\ - \textsl{\code{llseek}} & Sposta la posizione corrente sul file (vedi - sez.~\ref{sec:file_lseek}).\\ - \textsl{\code{ioctl}} & Accede alle operazioni di controllo - (vedi sez.~\ref{sec:file_ioctl}).\\ - \textsl{\code{readdir}}& Legge il contenuto di una directory (vedi - sez.~\ref{sec:file_dir_read}).\\ - \textsl{\code{poll}} & Usata nell'I/O multiplexing (vedi - sez.~\ref{sec:file_multiplexing}).\\ - \textsl{\code{mmap}} & Mappa il file in memoria (vedi - sez.~\ref{sec:file_memory_map}).\\ - \textsl{\code{release}}& Chiamata quando l'ultimo riferimento a un file - aperto è chiuso.\\ - \textsl{\code{fsync}} & Sincronizza il contenuto del file (vedi - sez.~\ref{sec:file_sync}).\\ - \textsl{\code{fasync}} & Abilita l'I/O asincrono (vedi - sez.~\ref{sec:file_asyncronous_io}) sul file.\\ - \hline - \end{tabular} - \caption{Operazioni sui file definite nel VFS.} - \label{tab:file_file_operations} -\end{table} - -In questo modo per ciascun file diventano possibili una serie di operazioni -(non è detto che tutte siano disponibili), che costituiscono l'interfaccia -astratta del VFS. Qualora se ne voglia eseguire una, il kernel andrà ad -utilizzare l'opportuna funzione dichiarata in \struct{f\_ops} appropriata al -tipo di file in questione. - -Pertanto è possibile scrivere allo stesso modo sulla porta seriale come su un -normale file di dati; ovviamente certe operazioni (nel caso della seriale ad -esempio la \code{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. -\itindend{Virtual~File~System} - - -\subsection{Il funzionamento di un filesystem Unix} -\label{sec:file_filesystem} - -Come già accennato in sez.~\ref{sec:file_organization} Linux (ed ogni sistema -unix-like) 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 per il momento non entreremo nei dettagli di un -filesystem specifico, ma daremo una descrizione a grandi linee che si adatta -alle caratteristiche comuni di qualunque filesystem di sistema unix-like. - -Lo spazio fisico di un disco viene usualmente diviso in partizioni; ogni -partizione può contenere un filesystem. La strutturazione tipica -dell'informazione su un disco è riportata in fig.~\ref{fig:file_disk_filesys}; -in essa si fa riferimento alla struttura del filesystem \acr{ext2}, che -prevede una separazione dei dati in \textit{block group} che replicano il -superblock (ma sulle caratteristiche di \acr{ext2} e derivati torneremo in -sez.~\ref{sec:file_ext2}). È comunque caratteristica comune di tutti i -filesystem per Unix, indipendentemente da come poi viene strutturata nei -dettagli questa informazione, prevedere una divisione fra la lista degli -\itindex{inode} inode e lo spazio a disposizione per i dati e le directory. - -\begin{figure}[!htb] - \centering - \includegraphics[width=14cm]{img/disk_struct} - \caption{Organizzazione dello spazio su un disco in partizioni e - filesystem.} - \label{fig:file_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 -fig.~\ref{fig:file_filesys_detail}. - -\begin{figure}[!htb] - \centering - \includegraphics[width=14cm]{img/filesys_struct} - \caption{Strutturazione dei dati all'interno di un filesystem.} - \label{fig:file_filesys_detail} -\end{figure} - -Da fig.~\ref{fig:file_filesys_detail} si evidenziano alcune delle -caratteristiche di base di un filesystem, sulle quali è bene porre attenzione -visto che sono fondamentali per capire il funzionamento delle funzioni che -manipolano i file e le directory che tratteremo nel prossimo capitolo; in -particolare è opportuno ricordare sempre che: - -\begin{enumerate} - -\item L'\textit{inode} \itindex{inode} contiene tutte le informazioni (i - cosiddetti \textsl{metadati}) 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 \func{stat} - fornisce provengono dall'\textit{inode}; dentro una directory si troverà - solo il nome del file e il numero \itindex{inode} dell'\textit{inode} ad esso - associato, cioè quella che da qui in poi chiameremo una \textsl{voce} (come - traduzione dell'inglese \textit{directory entry}, che non useremo anche per - evitare confusione con le \textit{dentry} del kernel di cui si parlava in - sez.~\ref{sec:file_vfs}). - -\item Come mostrato in fig.~\ref{fig:file_filesys_detail} si possono avere più - voci che puntano allo stesso \textit{inode}. Ogni \textit{inode} ha un - contatore che contiene il numero di riferimenti che sono stati fatti ad esso - (il cosiddetto \textit{link count}); 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 ad eliminare la relativa voce - da una directory e decrementare il numero di riferimenti \itindex{inode} - 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 \itindex{inode} \textit{inode} 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 viene spostato fisicamente, viene semplicemente creata una - nuova voce per \itindex{inode} 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}). Questa operazione non modifica - minimamente neanche l'\textit{inode} del file dato che non si opera su - questo ma sulla directory che lo contiene. - -\item Gli \textit{inode} dei file, che contengono i \textsl{metadati} ed i - blocchi di spazio disco, che contengono i dati, sono risorse indipendenti ed - in genere vengono gestite come tali anche dai diversi filesystem; è pertanto - possibile sia esaurire lo spazio disco (caso più comune) che lo spazio per - gli \textit{inode}, nel primo caso non sarà possibile allocare ulteriore - spazio, ma si potranno creare file (vuoti), nel secondo non si potranno - creare nuovi file, ma si potranno estendere quelli che ci sono. - -\end{enumerate} - -Infine si noti che, essendo file pure loro, il numero di riferimenti esiste -anche per le directory; per cui, se a partire dalla situazione mostrata in -fig.~\ref{fig:file_filesys_detail} creiamo una nuova directory \file{img} -nella directory \file{gapil}, avremo una situazione come quella in -fig.~\ref{fig:file_dirs_link}, dove per chiarezza abbiamo aggiunto dei numeri -di \itindex{inode} inode. - -\begin{figure}[!htb] - \centering - \includegraphics[width=14cm]{img/dir_links} - \caption{Organizzazione dei \textit{link} per le directory.} - \label{fig:file_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 \texttt{img}) e dalla voce ``\texttt{.}'' che -è sempre inserita in ogni directory; questo vale sempre per ogni directory che -non contenga a sua volta altre directory. Al contempo, la directory da cui si -era partiti avrà un numero di riferimenti di almeno tre, in quanto adesso sarà -referenziata anche dalla voce ``\texttt{..}'' di \texttt{img}. - - -\subsection{I filesystem di uso comune} -\label{sec:file_ext2} - -Il filesystem standard più usato con Linux è il cosiddetto \textit{third - extended filesystem}, identificato dalla sigla \acr{ext3}.\footnote{si fa - riferimento al momento della stesura di questo paragrafo, l'inizio del - 2010.} Esso nasce come evoluzione del precedente \textit{second extended - filesystem}, o \acr{ext2}, di cui eredita gran parte delle caratteristiche -di base, per questo motivo parleremo anzitutto di questo, dato che molto di -quanto diremo si applica anche ad \acr{ext3}. A partire dal kernel 2.6.XX è -stato dichiarato stabile il nuovo filsesystem \textit{ext4}, ulteriore -evoluzione di \textit{ext3} dotato di molte caratteristiche avanzate, che sta -iniziando a sostituirlo gradualmente. - -Il filesystem \acr{ext2} nasce come filesystem nativo di Linux a partire dalle -prime versioni del kernel e supporta tutte le caratteristiche di un filesystem -standard Unix: è in grado di gestire nomi di file lunghi (256 caratteri, -estensibili a 1012) e supporta una dimensione massima dei file fino a 4~Tb. I -successivi filesystem \acr{ext3} ed \acr{ext4} sono evoluzioni di questo -filesystem, e sia pure con molti miglioramenti ed estensioni significative ne -mantengono in sostanza le caratteristiche fondamentali. - -Oltre alle caratteristiche standard, \acr{ext2} fornisce alcune estensioni che -non sono presenti su un classico filesystem di tipo Unix; le principali 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 impostati 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 SVr4 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 SVr4 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 \acr{sgid} impostato (per una descrizione dettagliata del significato di - questi termini si veda sez.~\ref{sec:file_access_control}), nel qual caso - file e subdirectory ereditano sia il \acr{gid} che lo \acr{sgid}. -\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 \itindex{inode} 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 \acr{ext2} è stata ispirata a quella del filesystem di BSD: un -filesystem è composto da un insieme di blocchi, la struttura generale è quella -riportata in fig.~\ref{fig:file_filesys_detail}, in cui la partizione è divisa -in gruppi di blocchi.\footnote{non si confonda questa definizione con - quella riportata in fig.~\ref{fig:file_dirent_struct}; in quel caso si fa - riferimento alla struttura usata in user space per riportare i dati - contenuti in una directory generica, questa fa riferimento alla struttura - usata dal kernel per un filesystem \acr{ext2}, definita nel file - \texttt{ext2\_fs.h} nella directory \texttt{include/linux} dei sorgenti del - kernel.} - -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. L'utilizzo di raggruppamenti di blocchi ha inoltre -degli effetti positivi nelle prestazioni dato che viene ridotta la distanza -fra i dati e la tabella degli \itindex{inode} inode. - -\begin{figure}[!htb] - \centering - \includegraphics[width=9cm]{img/dir_struct} - \caption{Struttura delle directory nel \textit{second extented filesystem}.} - \label{fig:file_ext2_dirs} -\end{figure} - -Le directory sono implementate come una \itindex{linked~list} \textit{linked - list} con voci di dimensione variabile. Ciascuna voce della lista contiene -il numero di inode \itindex{inode}, la sua lunghezza, il nome del file e la sua -lunghezza, secondo lo schema in fig.~\ref{fig:file_ext2_dirs}; in questo modo -è possibile implementare nomi per i file anche molto lunghi (fino a 1024 -caratteri) senza sprecare spazio disco. - -Con l'introduzione del filesystem \textit{ext3} sono state introdotte anche -alcune modifiche strutturali, la principale di queste è quella che -\textit{ext3} è un filesystem \textit{jounrnaled}, è cioè in grado di eseguire -una registrazione delle operazioni di scrittura su un giornale (uno speciale -file interno) in modo da poter garantire il ripristino della coerenza dei dati -del filesystem\footnote{si noti bene che si è parlato di dati \textsl{del} - filesystem, non di dati \textsl{nel} filesystem, quello di cui viene - garantito un veloce ripristino è relativo ai dati della struttura interna - del filesystem, non di eventuali dati contenuti nei file che potrebbero - essere stati persi.} in brevissimo tempo in caso di interruzione improvvisa -della corrente o di crollo del sistema che abbia causato una interruzione -della scrittura dei dati sul disco. - -Oltre a questo \textit{ext3} introduce ulteriori modifiche volte a migliorare -sia le prestazioni che la semplicità di gestione del filesystem, in -particolare per le directory si è passato all'uso di alberi binari con -indicizzazione tramite hash al posto delle \textit{linked list}, ottenendo un -forte guadagno di prestazioni in caso di directory contenenti un gran numero -di file. - -% TODO portare a ext3, ext4 e btrfs ed illustrare le problematiche che si -% possono incontrare (in particolare quelle relative alla perdita di contenuti -% in caso di crash del sistema) +%\chapter{L'architettura dei file} +%\label{cha:file_intro} +% capitolo eliminato, inglobando altrove % LocalWords: everything is device kernel filesystem sez pathname root glibc % LocalWords: path filename bootloader proc name components fifo socket dev LF