X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileio.tex;h=9e7e960569f0ebc65beb52717d5c8601a10daade;hp=c5f805e9da412961fcf45878acc9347cd0cfd8b5;hb=7b43a7843d483c826a6ed13224208c615a23c4d6;hpb=9b7af600ff0f73bc946c9d160c320667c7a91347 diff --git a/fileio.tex b/fileio.tex index c5f805e..9e7e960 100644 --- a/fileio.tex +++ b/fileio.tex @@ -64,32 +64,34 @@ file viene aperto la funzione \func{open} restituisce questo numero, tutte le ulteriori operazioni dovranno essere compiute specificando questo stesso numero come argomento alle varie funzioni dell'interfaccia. +\itindbeg{process~table} +\itindbeg{file~table} + Per capire come funziona il meccanismo occorre spiegare a grandi linee come il kernel gestisce l'interazione fra processi e file. Abbiamo già accennato in sez.~\ref{sec:proc_hierarchy} come il kernel mantenga un elenco di tutti -processi nella cosiddetta \itindex{process~table} \textit{process table}. Lo -stesso, come accennato in sez.~\ref{sec:file_vfs_work}, vale anche per tutti i -file aperti, il cui elenco viene mantenuto nella cosiddetta -\itindex{file~table} \textit{file table}. - -La \itindex{process~table} \textit{process table} è una tabella che contiene -una voce per ciascun processo attivo nel sistema. Ciascuna voce è costituita -dal puntatore a una struttura di tipo \kstruct{task\_struct} nella quale sono -raccolte tutte le informazioni relative al processo, fra queste informazioni -c'è anche il puntatore ad una ulteriore struttura di tipo +processi nella cosiddetta \textit{process table}. Lo stesso, come accennato in +sez.~\ref{sec:file_vfs_work}, vale anche per tutti i file aperti, il cui +elenco viene mantenuto nella cosiddetta \textit{file table}. + +La \textit{process table} è una tabella che contiene una voce per ciascun +processo attivo nel sistema. Ciascuna voce è costituita dal puntatore a una +struttura di tipo \kstruct{task\_struct} nella quale sono raccolte tutte le +informazioni relative al processo, fra queste informazioni c'è anche il +puntatore ad una ulteriore struttura di tipo \kstruct{files\_struct},\footnote{la definizione corrente di questa struttura si trova nel file \texttt{include/linux/fdtable.h} dei sorgenti del kernel, quella mostrata in fig.~\ref{fig:file_proc_file} è una versione pesantemente semplificata.} che contiene le informazioni relative ai file che il processo ha aperto. -La \itindex{file~table} \textit{file table} è una tabella che contiene una -voce per ciascun file che è stato aperto nel sistema. Come accennato in -sez.~\ref{sec:file_vfs_work} per ogni file aperto viene allocata una struttura -\kstruct{file} e la \textit{file table} è costituita da un elenco di puntatori -a ciascuna di queste strutture, che, come illustrato in -fig.~\ref{fig:kstruct_file}, contengono le informazioni necessarie per la -gestione dei file, ed in particolare: +La \textit{file table} è una tabella che contiene una voce per ciascun file +che è stato aperto nel sistema. Come accennato in sez.~\ref{sec:file_vfs_work} +per ogni file aperto viene allocata una struttura \kstruct{file} e la +\textit{file table} è costituita da un elenco di puntatori a ciascuna di +queste strutture, che, come illustrato in fig.~\ref{fig:kstruct_file}, +contengono le informazioni necessarie per la gestione dei file, ed in +particolare: \begin{itemize*} \item i flag di stato \itindex{file~status~flag} del file nel campo \var{f\_flags}. @@ -115,9 +117,9 @@ gestione dei file, ed in particolare: In fig.~\ref{fig:file_proc_file} si è riportato uno schema semplificato in cui è illustrata questa architettura, ed in cui si sono evidenziate le -interrelazioni fra la \itindex{file~table} \textit{file table}, la -\itindex{process~table} \textit{process table} e le varie strutture di dati -che il kernel mantiene per ciascun file e ciascun processo. +interrelazioni fra la \textit{file table}, la \textit{process table} e le +varie strutture di dati che il kernel mantiene per ciascun file e ciascun +processo. Come si può notare alla fine il collegamento che consente di porre in relazione i file ed i processi è effettuato attraverso i dati mantenuti nella @@ -134,11 +136,14 @@ essenziali come: In questa infrastruttura un \textit{file descriptor} non è altro che l'intero positivo che indicizza quest'ultima tabella, e che consente di recuperare il puntatore alla struttura \kstruct{file} corrispondente al file aperto dal -processo a cui era stato assegnato questo indice. Una volta ottenuta grazie -al \textit{file descriptor} la struttura \kstruct{file} corrispondente al file -voluto nella \itindex{file~table} \textit{file table}, il kernel potrà usare -le funzioni messe disposizione dal VFS per eseguire sul file tutte le -operazioni necessarie. +processo a cui era stato assegnato questo indice. Una volta ottenuta grazie al +\textit{file descriptor} la struttura \kstruct{file} corrispondente al file +voluto nella \textit{file table}, il kernel potrà usare le funzioni messe +disposizione dal VFS per eseguire sul file tutte le operazioni necessarie. + +\itindend{process~table} +\itindend{file~table} + Il meccanismo dell'apertura dei file prevede che venga sempre fornito il primo \textit{file descriptor} libero nella tabella, e per questo motivo essi @@ -467,11 +472,11 @@ sez.~\ref{sec:ipc_file_lock}). Si tenga presente che questa opzione è supportata su NFS solo a partire da NFSv3 e con il kernel 2.6, nelle versioni precedenti la funzionalità viene emulata controllando prima l'esistenza del file per cui usarla per creare \index{file!di lock} un file di lock potrebbe -dar luogo a una \itindex{race~condition} \textit{race condition}.\footnote{un - file potrebbe venir creato fra il controllo la successiva apertura con - \const{O\_CREAT}, la cosa si può risolvere comunque creando un file con un - nome univoco ed usando la funzione \func{link} per creare il \index{file!di - lock} file di lock, (vedi sez.~\ref{sec:ipc_file_lock}).} +dar luogo a una \textit{race condition}.\footnote{un file potrebbe venir + creato fra il controllo la successiva apertura con \const{O\_CREAT}, la cosa + si può risolvere comunque creando un file con un nome univoco ed usando la + funzione \func{link} per creare il \index{file!di lock} file di lock, (vedi + sez.~\ref{sec:ipc_file_lock}).} Se si usa \const{O\_EXCL} senza \const{O\_CREAT} il comportamento è indefinito. Nella creazione di un file con \const{O\_CREAT} occorre sempre @@ -500,9 +505,9 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il viene sempre aggiunto al contenuto precedente. Con NFS questa funzionalità non è supportata e viene emulata, per questo possono verificarsi - \itindex{race~condition} \textit{race - condition} con una sovrapposizione dei dati se - più di un processo scrive allo stesso tempo.\\ + \textit{race condition} con una sovrapposizione dei + dati se più di un processo scrive allo stesso + tempo.\\ \const{O\_ASYNC} & Apre il file per l'I/O in modalità asincrona (vedi sez.~\ref{sec:signal_driven_io}). Quando è impostato viene generato il segnale \signal{SIGIO} @@ -518,11 +523,11 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il sez.~\ref{sec:proc_exec}) sul file. Il flag è previsto dallo standard POSIX.1-2008, ed è stato introdotto con il kernel 2.6.23 per evitare una - \itindex{race~condition} \textit{race condition} - che si potrebbe verificare con i \textit{thread} - fra l'apertura del file e l'impostazione della - suddetta modalità con \func{fcntl} (vedi - sez.~\ref{sec:file_fcntl_ioctl}).\\ + \textit{race condition} che si potrebbe verificare + con i \textit{thread} fra l'apertura del file e + l'impostazione della suddetta modalità con + \func{fcntl} (vedi + sez.~\ref{sec:file_fcntl_ioctl}).\\ \const{O\_DIRECT} & Esegue l'I/O direttamente dalla memoria in \textit{user space} in maniera sincrona, in modo da scavalcare i meccanismi di bufferizzazione del @@ -1236,13 +1241,12 @@ meccanismi di sincronizzazione espliciti come il \itindex{file~locking} Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui vari processi devono scrivere alla fine di un file (ad esempio un file di log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla -fine del file e poi scrivere può condurre ad una \itindex{race~condition} -\textit{race condition}l infatti può succedere che un secondo processo scriva -alla fine del file fra la \func{lseek} e la \func{write}. In questo caso, come -abbiamo appena visto, il file sarà esteso, ma il primo processo, che avrà la -posizione corrente che aveva impostato con la \func{lseek} che non corrisponde -più alla fine del file, e la sua successiva \func{write} sovrascriverà i dati -del secondo processo. +fine del file e poi scrivere può condurre ad una \textit{race condition}; +infatti può succedere che un secondo processo scriva alla fine del file fra la +\func{lseek} e la \func{write}. In questo caso, come abbiamo appena visto, il +file sarà esteso, ma il primo processo, avrà una posizione corrente che aveva +impostato con la \func{lseek} che non corrisponde più alla fine del file, e la +sua successiva \func{write} sovrascriverà i dati del secondo processo. Il problema deriva dal fatto che usare due \textit{system call} in successione non è mai un'operazione atomica dato che il kernel può interrompere @@ -1350,8 +1354,8 @@ file descriptor che si vuole ottenere come duplicato; il suo prototipo è: \begin{errlist} \item[\errcode{EBADF}] \param{oldfd} non è un file aperto o \param{newfd} ha un valore fuori dall'intervallo consentito per i file descriptor. - \item[\errcode{EBUSY}] si è rilevata la possibilità di una - \itindex{race~condition} \textit{race condition}. + \item[\errcode{EBUSY}] si è rilevata la possibilità di una \textit{race + condition}. \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. \item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file descriptor aperti. @@ -1369,24 +1373,23 @@ e si limita a restituire \param{newfd}. L'uso di \func{dup2} ha vari vantaggi rispetto alla combinazione di \func{close} e \func{dup}; anzitutto se \param{oldfd} è uguale \param{newfd} questo verrebbe chiuso e \func{dup} fallirebbe, ma soprattutto l'operazione è -atomica e consente di evitare una \itindex{race~condition} \textit{race - condition} in cui dopo la chiusura del file si potrebbe avere la ricezione -di un segnale il cui gestore (vedi sez.~\ref{sec:sig_signal_handler}) potrebbe -a sua volta aprire un file, per cui alla fine \func{dup} restituirebbe un file -descriptor diverso da quello voluto. +atomica e consente di evitare una \textit{race condition} in cui dopo la +chiusura del file si potrebbe avere la ricezione di un segnale il cui gestore +(vedi sez.~\ref{sec:sig_signal_handler}) potrebbe a sua volta aprire un file, +per cui alla fine \func{dup} restituirebbe un file descriptor diverso da +quello voluto. Con Linux inoltre la funzione prevede la possibilità di restituire l'errore \errcode{EBUSY}, che non è previsto dallo standard, quando viene rilevata la -possibilità di una \itindex{race~condition} \textit{race condition} interna in -cui si cerca di duplicare un file descriptor che è stato allocato ma per il -quale non sono state completate le operazioni di apertura.\footnote{la - condizione è abbastanza peculiare e non attinente al tipo di utilizzo - indicato, quanto piuttosto ad un eventuale tentativo di duplicare file - descriptor non ancora aperti, la condizione di errore non è prevista dallo - standard, ma in condizioni simili FreeBSD risponde con un errore di - \errval{EBADF}, mentre OpenBSD elimina la possibilità di una \textit{race - condition} al costo di una perdita di prestazioni.} In tal caso occorre -ritentare l'operazione. +possibilità di una \textit{race condition} interna in cui si cerca di +duplicare un file descriptor che è stato allocato ma per il quale non sono +state completate le operazioni di apertura.\footnote{la condizione è + abbastanza peculiare e non attinente al tipo di utilizzo indicato, quanto + piuttosto ad un eventuale tentativo di duplicare file descriptor non ancora + aperti, la condizione di errore non è prevista dallo standard, ma in + condizioni simili FreeBSD risponde con un errore di \errval{EBADF}, mentre + OpenBSD elimina la possibilità di una \textit{race condition} al costo di + una perdita di prestazioni.} In tal caso occorre ritentare l'operazione. La duplicazione dei file descriptor può essere effettuata anche usando la funzione di controllo dei file \func{fcntl} (che esamineremo in @@ -1562,10 +1565,9 @@ come per le altre funzioni che prendono come argomenti dei quando un \textit{pathname} relativo non fa riferimento ad un file posto direttamente nella directory di lavoro corrente, che alcuni dei componenti del \textit{pathname} vengano modificati in parallelo alla chiamata a \func{open}, -cosa che lascia aperta la possibilità di una \itindex{race~condition} -\textit{race condition} in cui c'è spazio per un \itindex{symlink~attack} -\textit{symlink attack} (si ricordi quanto visto per \func{access} in -sez.~\ref{sec:file_perm_management}). +cosa che lascia aperta la possibilità di una \textit{race condition} in cui +c'è spazio per un \itindex{symlink~attack} \textit{symlink attack} (si ricordi +quanto visto per \func{access} in sez.~\ref{sec:file_perm_management}). Inoltre come già accennato, la directory di lavoro corrente è una proprietà del singolo processo; questo significa che quando si lavora con i @@ -1600,14 +1602,13 @@ directory come punto di partenza per la risoluzione. In questo modo, anche quando si lavora con i \itindex{thread} \textit{thread}, si può mantenere una directory di lavoro diversa per ciascuno di essi. -Questo metodo, oltre a risolvere i problemi di \itindex{race~condition} -\textit{race condition}, consente anche di ottenere aumenti di prestazioni -significativi quando si devono eseguire molte operazioni su sezioni -dell'albero dei file che prevedono delle gerarchie di sottodirectory molto -profonde. Infatti in questo caso basta eseguire la risoluzione del -\textit{pathname} della directory di partenza una sola volta (nell'apertura -iniziale) e non tutte le volte che si deve accedere a ciascun file che essa -contiene. +Questo metodo, oltre a risolvere i problemi di \textit{race condition}, +consente anche di ottenere aumenti di prestazioni significativi quando si +devono eseguire molte operazioni su sezioni dell'albero dei file che prevedono +delle gerarchie di sottodirectory molto profonde. Infatti in questo caso basta +eseguire la risoluzione del \textit{pathname} della directory di partenza una +sola volta (nell'apertura iniziale) e non tutte le volte che si deve accedere +a ciascun file che essa contiene. La sintassi generale di queste nuove funzioni è che esse prevedono come primo argomento il file descriptor della directory da usare come base per la @@ -3093,9 +3094,8 @@ rispettivi prototipi sono: La funzione \func{getc} legge un byte da \param{stream} e lo restituisce come intero, ed in genere è implementata come una macro per cui può avere -\itindex{side~effects} \textit{side effects}, mentre \func{fgetc} è assicurato -essere sempre una funzione. Infine \func{getchar} è equivalente a -\code{getc(stdin)}. +\textit{side effects}, mentre \func{fgetc} è assicurato essere sempre una +funzione. Infine \func{getchar} è equivalente a \code{getc(stdin)}. A parte \func{getchar}, che si usa in genere per leggere un carattere da tastiera, le altre due funzioni sono sostanzialmente equivalenti. La