X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileintro.tex;h=a195c7a4907246acd061982838c3f66abea9f8f8;hp=342cd8de5313089d90e77ca1e1aecaf7106dd700;hb=193d612d40c5f81f5559ea6e11e70f6b6e51fb39;hpb=ff2d0141751ed62ef56e5bfd226c589311b8b669 diff --git a/fileintro.tex b/fileintro.tex index 342cd8d..a195c7a 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -1,6 +1,6 @@ -% fileintro.tex +%% fileintro.tex %% -%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2011 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Prefazione", @@ -8,27 +8,29 @@ %% license is included in the section entitled "GNU Free Documentation %% 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 +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, +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\index{file!di dispositivo} (i \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. +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. +nei capitoli seguenti), per poi passare ad una descrizione più dettagliata +delle modalità con cui detto accesso viene realizzato dal sistema. @@ -37,15 +39,14 @@ delle modalit 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 +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 \ref{sec:file_arch_func}), essa poi -viene resa disponibile ai processi attraverso quello che viene chiamato il +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}. -% (approfondiremo tutto ciò in \secref{sec:file_arch_func}). -In questa sezione faremo una panormamica generica su come il sistema presenta +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. @@ -53,25 +54,26 @@ 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}\index{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{/}. +\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 boot loader l'indicazione di quale dispositivo contiene il +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 +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. @@ -81,50 +83,52 @@ 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 -\secref{sec:file_vfs_work}, è anch'essa un file, solo che è un file -particolare che il kernel riconosce come tale. Il suo scopo è quello di +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 directory in altre directory. +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 +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 \textit{nomi}.} 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\index{socket} e gli stessi file di dispositivo -\index{file!di dispositivo} (questi -ultimi, per convenzione, sono inseriti nella directory \file{/dev}). + 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{file name resolution} o \textit{pathname +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 \file{/} 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 -\secref{sec:file_access_control}) devono consentire l'accesso all'intero -\textit{pathname}. - -Se il \textit{pathname}\index{pathname} comincia per \file{/} la ricerca parte -dalla directory radice del processo; questa, a meno di un \func{chroot} (su -cui torneremo in \secref{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}\index{pathname!assoluto}. Altrimenti la -ricerca parte dalla directory corrente (su cui torneremo in -\secref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname - relativo}\index{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. +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} @@ -132,29 +136,29 @@ se stessa. 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:file_vfs_work}) e sono presenti in tutti i filesystem unix-like +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 -\textit{Virtual File System}\index{Virtual File System} è riportato in -\tabref{tab:file_file_types}. +\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. +oggetti; in particolare è da notare la presenza dei cosiddetti file speciali. Alcuni di essi, come le \textit{fifo} (che tratteremo in -\secref{sec:ipc_named_pipe}) ed i \textit{socket}\index{socket} (che -tratteremo in \capref{cha:socket_intro}) non sono altro che dei riferimenti -per utilizzare delle funzionalità di comunicazione fornite dal kernel. Gli -altri sono i \textsl{file di dispositivo}\index{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.} +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 @@ -165,22 +169,22 @@ in cui il dispositivo sottostante effettua le operazioni di I/O.\footnote{in \hline \hline \textit{regular file} & \textsl{file regolare} & - un file che contiene dei dati (l'accezione normale di file) \\ + 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 - \textit{inode}\index{inode} (vedi \secref{sec:file_vfs}). \\ + Un file che contiene una lista di nomi associati a degli + \index{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 \\ + 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 \\ + 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 \secref{sec:ipc_named_pipe}).\\ - \textit{socket}\index{socket} & \textsl{``presa''} & - un file speciale che identifica una linea di comunicazione software - bidirezionale (vedi \capref{cha:socket_intro}) \\ + 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} @@ -188,195 +192,143 @@ in cui il dispositivo sottostante effettua le operazioni di I/O.\footnote{in \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 +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 ``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 file di - dispositivo\index{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).} - -Una seconda differenza è nel formato dei file ASCII: in Unix la fine riga è -codificata in maniera diversa da Windows o Mac, 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.\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. +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 +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, come l'XFS della SGI, esiste la - possibilità di associare delle risorse ai file, 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. + 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 +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 -\acr{glibc} chiama interfaccia dei descrittori di file (o \textit{file - descriptor}). È un'interfaccia specifica dei sistemi unix-like e fornisce +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 -\capref{cha:file_unix_interface}. +cap.~\ref{cha:file_unix_interface}. -L'interfaccia è primitiva ed essenziale, l'accesso viene detto non +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 +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 \textit{file descriptor}\index{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 -\textit{stream}\index{file!stream}. Essa fornisce funzioni più evolute e un -accesso bufferizzato (controllato dalla implementazione fatta dalle -\acr{glibc}), la tratteremo in dettaglio nel \capref{cha:files_std_interface}. - -Questa è l'interfaccia standard specificata dall'ANSI C e perciò si trova -anche su tutti i sistemi non Unix. Gli \textit{stream}\index{file!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 \ctyp{FILE *}. L'interfaccia è definita nell'header -\file{stdio.h}. +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 \ctyp{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\index{socket}, device, sui quali torneremo -in dettaglio a tempo opportuno), ma per poter accedere alle operazioni di -controllo (descritte in \secref{sec:file_fcntl} e \secref{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 -\textit{file descriptor}\index{file!descriptor} se si vuole ricorrere a -modalità speciali di I/O come il \textit{file locking}\index{file!locking} o -l'I/O non-bloccante (vedi \capref{cha:file_advanced}). +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 +è 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 \textit{stream}\index{file!stream} dispongono di tutte le +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 +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 \textit{stream}\index{file!stream} ad un \textit{file - descriptor}\index{file!descriptor}. - -In generale, se non necessitano specificatamente le funzionalità di basso -livello, è opportuno usare sempre gli \textit{stream}\index{file!stream} per -la loro maggiore portabilità, essendo questi ultimi definiti nello standard -ANSI C; l'interfaccia con i \textit{file descriptor}\index{file!descriptor} -infatti 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} - -% Essendo un sistema multitasking e multiutente esistono alcune caratteristiche -% specifiche di un sistema unix-like che devono essere tenute in conto -% nell'accesso ai file. È infatti normale che più processi o programmi possano -% accedere contemporaneamente allo stesso file e devono poter eseguire le loro -% operazioni indipendentemente da quello che fanno gli altri processi. - -% Per questo motivo le strutture usate per all'accesso ai file sono relative al -% processo che effettua l'accesso. All'apertura di ogni file infatti viene -% creata all'interno del processo una apposita struttura in cui sono memorizzati -% tutti gli attributi del medesimo, che viene utilizzata per tutte le -% operazioni. Questa è una struttura che resta locale al processo stesso; in -% questo modo processi diversi possono usare le proprie strutture locali per -% accedere ai file (che può essere sempre lo stesso) in maniera assolutamente -% indipendente. - -% Questo ha delle conseguenze di cui è bene tenere conto; ad esempio in tutti i -% sistemi POSIX uno degli attributi di un file aperto è la posizione corrente nel -% file, cioè il punto nel file in cui verrebbe letto o scritto alla operazione -% successiva. Essa è rappresentata da un numero intero che indica il numero di -% byte dall'inizio del file, che viene (a meno che non si apra il file in -% append) inizializzato a zero all'apertura del medesimo. - -% Questo è uno dei dati che viene mantenuto nella suddetta struttura, per cui -% ogni processo avrà la sua posizione corrente nel file, che non sarà -% influenzata da quello che altri processi possono fare. Anzi, aprire un file -% significa appunto creare ed inizializzare una tale struttura, per cui se si -% apre due volte lo stesso file all'interno dello stesso processo, si otterranno -% due file descriptor o due stream che avranno ancora una posizione corrente nel -% file assolutamente indipendente. - -% Si tenga conto inoltre che un'altro dei dati contenuti nella struttura di -% accesso è un riferimento all'inode del file, pertanto anche se il file viene -% 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:file_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. - -% Ritorneremo su questo più avanti in \secref{sec:file_fd}, quando tratteremo -% l'input/output sui file, esaminando in dettaglio come tutto ciò viene -% realizzato. +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} -Per capire fino in fondo le proprietà di file e directory in un sistema -unix-like ed il comportamento delle relative funzioni di manipolazione, -occorre una breve introduzione al funzionamento gestione dei file da parte del -kernel e sugli oggetti su cui è basato un filesystem. 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 file in -Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo +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}. - -% 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:file_vfs}. +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} -% Questa sezione riporta informazioni sui dettagli di come il kernel gestisce i -% file. 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}. +% 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 -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 +\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 @@ -385,12 +337,12 @@ 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 routine del filesystem specifico a cui si fa riferimento. Saranno -queste a chiamare le funzioni di più basso livello che eseguono le operazioni +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 -\figref{fig:file_VFS_scheme}. +fig.~\ref{fig:file_VFS_scheme}. \begin{figure}[htb] \centering @@ -402,86 +354,87 @@ di I/O sul dispositivo fisico, secondo lo schema riportato in 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}, -\textit{inode}\index{inode} e \textit{file}, corrispondenti a tre apposite +\index{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 +filesystem tutto quello che occorre è chiamare la funzione \code{register\_filesystem} passandole un'apposita struttura -(\struct{file\_system\_type}) che contiene i dettagli per il riferimento -all'implementazione del medesimo, che sarà aggiunta alla citata tabella. +\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 \secref{sec:file_ext2}), inizializzare tutte le variabili +(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 routine specifiche per +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 +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ì +puntatori alle funzioni del kernel relative al filesystem. Il VFS può così usare le funzioni contenute nel \textit{filesystem descriptor} per accedere -alle routine specifiche di quel filesystem. +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 +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\index{inode} contiene i puntatori alle funzioni che possono essere +\index{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. +sui file già aperti. -\subsection{Il funzionamento del VFS} +\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 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 -pathname a una specifica \textit{dentry}. +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 -\textit{inode}\index{inode}; quest'ultimo è la struttura base che sta sul +\index{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 -dispositivo\index{file!di dispositivo}, o una qualsiasi altra cosa che possa -essere rappresentata dal VFS (i tipi di ``file'' riportati in -\tabref{tab:file_file_types}). A ciascuno di essi è associata pure una +\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 \textit{inode}\index{inode} invece +vengono usate per motivi di velocità, gli \index{inode} \textit{inode} invece stanno su disco e vengono copiati in memoria quando serve, ed ogni cambiamento -viene copiato all'indietro sul disco, gli inode\index{inode} che stanno in -memoria sono inode\index{inode} del VFS ed è ad essi che puntano le singole +viene copiato all'indietro sul disco (aggiornando i cosiddetti +\textsl{metadati} del file), gli \index{inode} inode che stanno in memoria +sono \index{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 -pathname il VFS deve creare una nuova \textit{dentry} e caricare -l'inode\index{inode} corrispondente in memoria. +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 \index{inode} l'inode corrispondente in memoria. -Questo procedimento viene eseguito dal metodo \code{lookup()} -dell'inode\index{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. +Questo procedimento viene eseguito dal metodo \code{lookup()} \index{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 -dell'inode\index{inode} e passarli in user space. +\index{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 @@ -489,9 +442,9 @@ una struttura di tipo \struct{file} in cui viene inserito un puntatore alla 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:file_fd}). Un elenco delle -operazioni previste dal kernel è riportato in -\tabref{tab:file_file_operations}. +(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 @@ -501,24 +454,26 @@ operazioni previste dal kernel \textbf{Funzione} & \textbf{Operazione} \\ \hline \hline - \textsl{\code{open}} & apre il file (vedi \secref{sec:file_open}). \\ - \textsl{\code{read}} & legge dal file (vedi \secref{sec:file_read}).\\ - \textsl{\code{write}} & scrive sul file (vedi \secref{sec:file_write}).\\ - \textsl{\code{llseek}} & sposta la posizione corrente sul file (vedi - \secref{sec:file_lseek}). \\ - \textsl{\code{ioctl}} & accede alle operazioni di controllo - (vedi \secref{sec:file_ioctl}).\\ - \textsl{\code{readdir}}& legge il contenuto di una directory \\ - \textsl{\code{poll}} & usata nell'I/O multiplexing (vedi - \secref{sec:file_multiplexing}). \\ - \textsl{\code{mmap}} & mappa il file in memoria (vedi - \secref{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 - \secref{sec:file_sync}). \\ - \textsl{\code{fasync}} & abilita l'I/O asincrono (vedi - \secref{sec:file_asyncronous_io}) sul file. \\ + \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.} @@ -526,40 +481,41 @@ operazioni previste dal kernel \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 routine dichiarata in \struct{f\_ops} appropriata al +(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 -normale un 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) è +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 \secref{sec:file_organization} Linux (ed ogni sistema +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. 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 \figref{fig:file_disk_filesys}; +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{blocks group} che replicano il -superblock (ma sulle caratteristiche di \acr{ext2} torneremo in -\secref{sec:file_ext2}). È comunque caratteristica comune di tutti i +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 -inode\index{inode} e lo spazio a disposizione per i dati e le directory. +\index{inode} inode e lo spazio a disposizione per i dati e le directory. \begin{figure}[htb] \centering @@ -574,7 +530,7 @@ 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 -\figref{fig:file_filesys_detail}. +fig.~\ref{fig:file_filesys_detail}. \begin{figure}[htb] \centering @@ -583,82 +539,107 @@ esemplificare la situazione con uno schema come quello esposto in \label{fig:file_filesys_detail} \end{figure} -Da \figref{fig:file_filesys_detail} si evidenziano alcune delle -caratteristiche di base di un filesystem, sulle quali è bene porre attenzione +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: +particolare è opportuno ricordare sempre che: \begin{enumerate} -\item L'\textit{inode}\index{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 \func{stat} fornisce provengono dall'\textit{inode}; dentro una - directory si troverà solo il nome del file e il numero - dell'\textit{inode}\index{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 \secref{sec:file_vfs}). +\item L'\textit{inode} \index{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 \index{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 \figref{fig:file_filesys_detail} si possono avere più +\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 (\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 ad eliminare la relativa voce da una - directory e decrementare il numero di riferimenti - nell'\textit{inode}\index{inode}. + 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 \index{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 \textit{inode}\index{inode} relativi ad altri filesystem. + nello stesso filesystem e non ci può essere una directory che contiene + riferimenti ad \index{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. + 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 l'\textit{inode}\index{inode} in questione e rimossa la - vecchia (questa è la modalità in cui opera normalmente il comando \cmd{mv} - attraverso la funzione \func{rename}). + nuova voce per \index{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 è bene avere presente che, essendo file pure loro, esiste un numero di -riferimenti anche per le directory; per cui, se a partire dalla situazione -mostrata in \figref{fig:file_filesys_detail} creiamo una nuova directory -\file{img} nella directory \file{gapil}, avremo una situazione come quella in -\figref{fig:file_dirs_link}, dove per chiarezza abbiamo aggiunto dei numeri di -inode\index{inode}. +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 \index{inode} inode. \begin{figure}[htb] \centering \includegraphics[width=14cm]{img/dir_links} - \caption{Organizzazione dei link per le directory.} + \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 \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 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 \file{..} di \file{img}. +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{Il filesystem \textsl{ext2}} +\subsection{I filesystem di uso comune} \label{sec:file_ext2} -Il filesystem standard usato da Linux è il cosiddetto \textit{second extended - filesystem}, identificato dalla sigla \acr{ext2}. Esso supporta tutte le -caratteristiche di un filesystem standard Unix, è in grado di gestire nomi di -file lunghi (256 caratteri, estendibili a 1012) con una dimensione massima di -4~Tb. +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 sugli altri filesystem Unix. Le principali sono le seguenti: +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 @@ -670,15 +651,15 @@ non sono presenti sugli altri filesystem Unix. Le principali sono le seguenti: 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 \secref{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). + 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 dell'inode\index{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). + non è salvato su un blocco, ma tenuto all'interno \index{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 @@ -686,15 +667,23 @@ non sono presenti sugli altri filesystem Unix. Le principali sono le seguenti: 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 \figref{fig:file_filesys_detail}, in cui la partizione -è divisa in gruppi di blocchi. +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. +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 \index{inode} inode. \begin{figure}[htb] \centering @@ -703,17 +692,49 @@ superblock principale. \label{fig:file_ext2_dirs} \end{figure} -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 -inode\index{inode}. - -Le directory sono implementate come una linked list con voci di dimensione -variabile. Ciascuna voce della lista contiene il numero di inode\index{inode}, -la sua lunghezza, il nome del file e la sua lunghezza, secondo lo schema in -\figref{fig:file_ext2_dirs}; in questo modo è possibile implementare nomi per -i file anche molto lunghi (fino a 1024 caratteri) senza sprecare spazio disco. - - +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 \index{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) + + +% LocalWords: everything is device kernel filesystem sez pathname root glibc +% LocalWords: path filename bootloader proc name components fifo socket dev LF +% LocalWords: resolution chroot parent Virtual System like tab cap l'I regular +% LocalWords: inode symbolic char block VFS VMS Windows dell'I raw access Mac +% LocalWords: CR dos HFS l'XFS SGI magic number descriptor system call int ext +% LocalWords: nell'header unistd stream dall'ANSI stdio locking POSIX fig type +% LocalWords: register superblock dell'inode stat entry cache dcache dentry ln +% LocalWords: l'inode lookup ops read write llseek ioctl readdir poll nell'I +% LocalWords: multiplexing mmap fsync fasync seek group dall' dell' img +% LocalWords: count unlink nell' rename gapil second Tb attributes BSD SVr gid +% LocalWords: sgid append only log fs linux extented linked list third MacOS %%% Local Variables: