From 3cf93b3dfc49fbf8b16f908bee85fa2ecaea4e3f Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 5 Feb 2012 17:47:35 +0000 Subject: [PATCH] Altro accorpamento di sezioni e risistemazione dei riferimenti, Completato tutto fino a dupN. --- fileadv.tex | 16 +- fileio.tex | 538 +++++++++++++++++++++++++------------------- img/filedup.dia | Bin 3028 -> 3133 bytes img/filemultacc.dia | Bin 3964 -> 4095 bytes img/fileshar.dia | Bin 3858 -> 3986 bytes ipc.tex | 2 +- prochand.tex | 23 +- tcpsock.tex | 6 +- 8 files changed, 330 insertions(+), 255 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index 1de6aeb..a4ca6e2 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -26,12 +26,12 @@ controllo più dettagliato delle modalità di I/O. \itindbeg{file~locking} -In sez.~\ref{sec:file_sharing} abbiamo preso in esame le modalità in cui un -sistema unix-like gestisce la condivisione dei file da parte di processi -diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti -in \itindex{append~mode} \textit{append mode}, quando più processi scrivono -contemporaneamente sullo stesso file non è possibile determinare la sequenza -in cui essi opereranno. +In sez.~\ref{sec:file_shared_access} abbiamo preso in esame le modalità in cui +un sistema unix-like gestisce l'accesso concorrente ai file da parte di +processi diversi. In quell'occasione si è visto come, con l'eccezione dei file +aperti in \itindex{append~mode} \textit{append mode}, quando più processi +scrivono contemporaneamente sullo stesso file non è possibile determinare la +sequenza in cui essi opereranno. Questo causa la possibilità di una \itindex{race~condition} \textit{race condition}; in generale le situazioni più comuni sono due: l'interazione fra @@ -260,8 +260,8 @@ Questa struttura prevede che, quando si richiede la rimozione di un file descriptor che fa riferimento ad una voce nella \itindex{file~table} \textit{file table} corrispondente a quella registrata nel blocco. Allora se ricordiamo quanto visto in sez.~\ref{sec:file_dup} e -sez.~\ref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli -ereditati in un processo figlio puntano sempre alla stessa voce nella +sez.~\ref{sec:file_shared_access}, e cioè che i file descriptor duplicati e +quelli ereditati in un processo figlio puntano sempre alla stessa voce nella \itindex{file~table} \textit{file table}, si può capire immediatamente quali sono le conseguenze nei confronti delle funzioni \func{dup} e \func{fork}. diff --git a/fileio.tex b/fileio.tex index 481d210..d631d40 100644 --- a/fileio.tex +++ b/fileio.tex @@ -294,7 +294,7 @@ nuovo file questo diventerà il nuovo \itindex{standard~input} \textit{standard Al momento dell'apertura il nuovo file descriptor non è condiviso con nessun altro processo (torneremo sul significato della condivisione dei file descriptor, che in genere si ottiene dopo una \func{fork}, in -sez.~\ref{sec:file_sharing}) ed è impostato, come accennato in +sez.~\ref{sec:file_shared_access}) ed è impostato, come accennato in sez.~\ref{sec:proc_exec}, per restare aperto attraverso una \func{exec}. Inoltre la posizione sul file, il cosiddetto \textit{offset}, è impostata all'inizio del file. Una volta aperto un file si potrà operare su di @@ -699,8 +699,8 @@ La funzione chiude il file descriptor \param{fd}. La chiusura rilascia ogni eventuale blocco (il \textit{file locking} \itindex{file~locking} è trattato in sez.~\ref{sec:file_locking}) che il processo poteva avere acquisito su di esso. Se \param{fd} è l'ultimo riferimento (di eventuali copie, vedi -sez.~\ref{sec:file_sharing} e \ref{sec:file_dup}) ad un file aperto, tutte le -risorse nella \itindex{file~table} \textit{file table} vengono +sez.~\ref{sec:file_shared_access} e \ref{sec:file_dup}) ad un file aperto, +tutte le risorse nella \itindex{file~table} \textit{file table} vengono rilasciate. Infine se il file descriptor era l'ultimo riferimento ad un file su disco quest'ultimo viene cancellato. @@ -818,7 +818,7 @@ la successiva scrittura avvenga alla fine del file, infatti se questo è stato aperto anche da un altro processo che vi ha scritto, la fine del file può essersi spostata, ma noi scriveremo alla posizione impostata in precedenza (questa è una potenziale sorgente di \itindex{race~condition} \textit{race - condition}, vedi sez.~\ref{sec:file_atomic}). + condition}, vedi sez.~\ref{sec:file_shared_access}). Non tutti i file supportano la capacità di eseguire una \func{lseek}, in questo caso la funzione ritorna l'errore \errcode{ESPIPE}. Questo, oltre che @@ -1024,7 +1024,7 @@ L'uso di \func{pread} è equivalente all'esecuzione di una \func{read} seguita da una \func{lseek} che riporti al valore precedente la posizione corrente sul file, ma permette di eseguire l'operazione atomicamente. Questo può essere importante quando la posizione sul file viene condivisa da processi diversi -(vedi sez.~\ref{sec:file_sharing}). Il valore di +(vedi sez.~\ref{sec:file_shared_access}). Il valore di \param{offset} fa sempre riferimento all'inizio del file. La funzione \func{pread} è disponibile anche in Linux, però diventa @@ -1115,14 +1115,15 @@ permettono di eseguire alcune operazioni avanzate con i file (il grosso dell'argomento sarà comunque affrontato in cap.~\ref{cha:file_advanced}). -\subsection{La condivisione dei files} -\label{sec:file_sharing} +\subsection{La gestione dell'accesso concorrente ai files} +\label{sec:file_shared_access} In sez.~\ref{sec:file_fd} abbiamo descritto brevemente l'architettura dell'interfaccia con i file da parte di un processo, mostrando in fig.~\ref{fig:file_proc_file} le principali strutture usate dal kernel; esamineremo ora in dettaglio le conseguenze che questa architettura ha nei -confronti dell'accesso allo stesso file da parte di processi diversi. +confronti dell'accesso concorrente allo stesso file da parte di processi +diversi. \begin{figure}[!htb] \centering @@ -1147,20 +1148,20 @@ vengono mantenute nella sua voce della \itindex{file~table} \textit{file azione simultanea sullo stesso file, in particolare occorre tenere presente che: \begin{itemize} -\item ciascun processo può scrivere indipendentemente; dopo ciascuna - \func{write} la posizione corrente sarà cambiata solo nel processo. Se la - scrittura eccede la dimensione corrente del file questo verrà esteso - automaticamente con l'aggiornamento del campo \var{i\_size} \itindex{inode} - nell'\textit{inode}. +\item ciascun processo può scrivere indipendentemente, dopo ciascuna + \func{write} la posizione corrente sarà cambiata solo nel processo + scrivente. Se la scrittura eccede la dimensione corrente del file questo + verrà esteso automaticamente con l'aggiornamento del campo \var{i\_size} + della struttura \kstruct{inode}. \item se un file è in modalità \itindex{append~mode} \const{O\_APPEND} tutte le volte che viene effettuata una scrittura la posizione corrente viene - prima impostata alla dimensione corrente del file letta \itindex{inode} - dall'\textit{inode}. Dopo la scrittura il file viene automaticamente esteso. + prima impostata alla dimensione corrente del file letta dalla struttura + \kstruct{inode}. Dopo la scrittura il file viene automaticamente esteso. \item l'effetto di \func{lseek} è solo quello di cambiare il campo \var{f\_pos} nella struttura \kstruct{file} della \itindex{file~table} \textit{file table}, non c'è nessuna operazione sul file su disco. Quando la si usa per porsi alla fine del file la posizione viene impostata leggendo la - dimensione corrente \itindex{inode} dall'\textit{inode}. + dimensione corrente dalla struttura \kstruct{inode}. \end{itemize} \begin{figure}[!htb] @@ -1171,175 +1172,89 @@ che: \end{figure} Il secondo caso è quello in cui due file descriptor di due processi diversi -puntino alla stessa voce nella \itindex{file~table} \textit{file table}; -questo è ad esempio il caso dei file aperti che vengono ereditati dal processo +puntino alla stessa voce nella \itindex{file~table} \textit{file table}. +Questo è ad esempio il caso dei file aperti che vengono ereditati dal processo figlio all'esecuzione di una \func{fork} (si ricordi quanto detto in sez.~\ref{sec:proc_fork}). La situazione è illustrata in fig.~\ref{fig:file_acc_child}; dato che il processo figlio riceve una copia dello spazio di indirizzi del padre, riceverà anche una copia di -\kstruct{file\_struct} e relativa tabella dei file aperti. - -In questo modo padre e figlio avranno gli stessi file descriptor che faranno -riferimento alla stessa voce nella \textit{file table}, condividendo così la -posizione corrente sul file. Questo ha le conseguenze descritte a suo tempo in -sez.~\ref{sec:proc_fork}: in caso di scrittura contemporanea la posizione -corrente nel file varierà per entrambi i processi (in quanto verrà modificato -\var{f\_pos} che è lo stesso per entrambi). - -Si noti inoltre che anche i \itindex{file~status~flag} flag di stato del file -(quelli impostati dall'argomento \param{flag} di \func{open}) essendo tenuti -nella voce della \textit{file table}, vengono in questo caso condivisi. Ai -file però sono associati anche altri flag, dei quali l'unico usato al momento -è \const{FD\_CLOEXEC}, detti \itindex{file~descriptor~flags} \textit{file - descriptor flags}. Questi ultimi sono tenuti invece in -\kstruct{file\_struct}, e perciò sono specifici di ciascun processo e non +\kstruct{file\_struct} e della relativa tabella dei file aperti. + +Questo significa che il figlio avrà gli stessi file aperti del padre, in +quanto la sua \kstruct{file\_struct}, pur essendo allocata in maniera +indipendente, contiene gli stessi valori di quella del padre e quindi i suoi +file descriptor faranno riferimento alla stessa voce nella +\itindex{file~table} \textit{file table}, condividendo così la posizione +corrente sul file. Questo ha le conseguenze descritte a suo tempo in +sez.~\ref{sec:proc_fork}: in caso di scrittura o lettura da parte di uno dei +due processi, la posizione corrente nel file varierà per entrambi, in quanto +verrà modificato il campo \var{f\_pos} della struttura \kstruct{file}, che è +la stessa per entrambi. Questo consente una sorta di +``\textsl{sincronizzazione}'' automatica della posizione sul file fra padre e +figlio che occorre tenere presente. + +Si noti inoltre che in questo caso anche i \itindex{file~status~flag} flag di +stato del file, essendo mantenuti nella struttura \kstruct{file} della +\textit{file table}, vengono condivisi, per cui una modifica degli stessi con +\func{fcntl} (vedi sez.~\ref{sec:file_fcntl}) si applicherebbe a tutti +processi che condividono la voce nella \itindex{file~table} \textit{file + table}. Ai file però sono associati anche altri flag, dei quali l'unico +usato al momento è \const{FD\_CLOEXEC}, detti \itindex{file~descriptor~flags} +\textit{file descriptor flags}; questi invece sono mantenuti in +\kstruct{file\_struct}, e perciò sono locali per ciascun processo e non vengono modificati dalle azioni degli altri anche in caso di condivisione -della stessa voce della \textit{file table}. - - - -\subsection{Operazioni atomiche con i file} -\label{sec:file_atomic} - -Come si è visto in un sistema unix-like è sempre possibile per più processi -accedere in contemporanea allo stesso file, e che le operazioni di lettura e -scrittura possono essere fatte da ogni processo in maniera autonoma in base -ad una posizione corrente nel file che è locale a ciascuno di essi. - -Se dal punto di vista della lettura dei dati questo non comporta nessun -problema, quando si andrà a scrivere le operazioni potranno mescolarsi in -maniera imprevedibile. Il sistema però fornisce in alcuni casi la possibilità -di eseguire alcune operazioni di scrittura in maniera coordinata anche senza -utilizzare meccanismi di sincronizzazione più complessi (come il -\itindex{file~locking} \textit{file locking}, che esamineremo in -sez.~\ref{sec:file_locking}). +della stessa voce della \itindex{file~table} \textit{file table}. + +Si tenga presente dunque che in un sistema unix-like è sempre possibile per +più processi accedere in contemporanea allo stesso file e che non esistono, a +differenza di altri sistemi operativi, dei meccanismi di blocco o di +restrizione dell'accesso impliciti se più processi vogliono accedere allo +stesso file. Questo significa che le operazioni di lettura e scrittura vengono +sempre fatte da ogni processo in maniera autonoma, utilizzando una posizione +corrente nel file che normalmente (a meno di non trovarsi nella situazione di +fig.~\ref{fig:file_acc_child}) è locale a ciascuno di essi. + +Dal punto di vista della lettura dei dati questo comporta la possibilità di +poter leggere dati non coerenti in caso di scrittura contemporanea da parte di +un altro processo. Dal punto di vista della scrittura invece si potranno avere +sovrapposizioni imprevedibili quando due processi scrivono nella stessa +sezione di file, dato che ciascuno lo farà in maniera indipendente. Il +sistema però fornisce in alcuni casi la possibilità di eseguire alcune +operazioni di scrittura in maniera coordinata anche senza utilizzare dei +meccanismi di sincronizzazione espliciti come il \itindex{file~locking} +\textit{file locking}, che esamineremo in sez.~\ref{sec: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}: 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 nostro primo processo avrà -ancora la posizione corrente impostata con la \func{lseek} che non corrisponde -più alla fine del file, e la successiva \func{write} sovrascriverà i dati del -secondo processo. - -Il problema è che usare due \textit{system call} in successione non è -un'operazione atomica; il problema è stato risolto introducendo la modalità -\itindex{append~mode} \const{O\_APPEND}. In questo caso infatti, come abbiamo -descritto in precedenza, è il kernel che aggiorna automaticamente la posizione -alla fine del file prima di effettuare la scrittura, e poi estende il file. -Tutto questo avviene all'interno di una singola \textit{system call} (la -\func{write}) che non essendo interrompibile da un altro processo costituisce -un'operazione atomica. - -Un altro caso tipico in cui è necessaria l'atomicità è quello in cui si vuole -creare un \textsl{file di lock} \index{file!di lock}, bloccandosi se il file -esiste. In questo caso la sequenza logica porterebbe a verificare prima -l'esistenza del file con una \func{stat} per poi crearlo con una \func{creat}; -di nuovo avremmo la possibilità di una \itindex{race~condition} \textit{race - condition} da parte di un altro processo che crea lo stesso file fra il -controllo e la creazione. - -Per questo motivo sono stati introdotti per \func{open} i due flag -\const{O\_CREAT} e \const{O\_EXCL}. In questo modo l'operazione di controllo -dell'esistenza del file (con relativa uscita dalla funzione con un errore) e -creazione in caso di assenza, diventa atomica essendo svolta tutta all'interno -di una singola \textit{system call} (per i dettagli sull'uso di questa -caratteristica si veda sez.~\ref{sec:ipc_file_lock}). - - -\subsection{Le funzioni \func{sync} e \func{fsync}} -\label{sec:file_sync} - -% TODO, aggiungere syncfs, introdotta con il 2.6.39 - -Come accennato in sez.~\ref{sec:file_open_close} tutte le operazioni di -scrittura sono in genere bufferizzate dal kernel, che provvede ad effettuarle -in maniera asincrona (ad esempio accorpando gli accessi alla stessa zona del -disco) in un secondo tempo rispetto al momento della esecuzione della -\func{write}. - -Per questo motivo, quando è necessaria una sincronizzazione dei dati, il -sistema mette a disposizione delle funzioni che provvedono a forzare lo -scarico dei dati dai buffer del kernel.\footnote{come già accennato neanche - questo dà la garanzia assoluta che i dati siano integri dopo la chiamata, - l'hardware dei dischi è in genere dotato di un suo meccanismo interno di - ottimizzazione per l'accesso al disco che può ritardare ulteriormente la - scrittura effettiva.} La prima di queste funzioni è \funcd{sync} il cui -prototipo è: - -\begin{funcproto}{ -\fhead{unistd.h} -\fdecl{int sync(void)} -\fdesc{Sincronizza il buffer della cache dei file col disco.} -} - -{La funzione ritorna sempre $0$ ed ha sempre successo.} -\end{funcproto} - -\noindent i vari standard prevedono che la funzione si limiti a far partire -le operazioni, ritornando immediatamente; in Linux (dal kernel 1.3.20) invece -la funzione aspetta la conclusione delle operazioni di sincronizzazione del -kernel. - -La funzione viene usata dal comando \cmd{sync} quando si vuole forzare -esplicitamente lo scarico dei dati su disco, o dal demone di sistema -\cmd{update} che esegue lo scarico dei dati ad intervalli di tempo fissi: il -valore tradizionale, usato da BSD, per l'update dei dati è ogni 30 secondi, ma -in Linux il valore utilizzato è di 5 secondi; con le nuove versioni\footnote{a - partire dal kernel 2.2.8} poi, è il kernel che si occupa direttamente di -tutto quanto attraverso il demone interno \cmd{bdflush}, il cui comportamento -può essere controllato attraverso il file \sysctlfile{vm/bdflush} (per -il significato dei valori si può leggere la documentazione allegata al kernel -in \file{Documentation/sysctl/vm.txt}). - -Quando si vogliono scaricare soltanto i dati di un file (ad esempio essere -sicuri che i dati di un database sono stati registrati su disco) si possono -usare le due funzioni \funcd{fsync} e \funcd{fdatasync}, i cui prototipi sono: - -\begin{funcproto}{ -\fhead{unistd.h} -\fdecl{int fsync(int fd)} -\fdesc{Sincronizza dati e metadati di un file.} -\fdecl{int fdatasync(int fd)} -\fdesc{Sincronizza i dati di un file.} -} - -{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual - caso \var{errno} assumerà uno dei valori: - \begin{errlist} - \item[\errcode{EINVAL}] \param{fd} è un \index{file!speciali} file speciale - che non supporta la sincronizzazione. - \end{errlist} - ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO} nel loro - significato generico.} -\end{funcproto} - -Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del -file specificato, ed attendono fino alla conclusione delle operazioni; -\func{fsync} forza anche la sincronizzazione dei meta-dati del file (che -riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli -altri dati contenuti \itindex{inode} nell'\textit{inode} che si leggono con -\func{fstat}, come i tempi del file). - -Si tenga presente che questo non comporta la sincronizzazione della -directory che contiene il file (e scrittura della relativa voce su -disco) che deve essere effettuata esplicitamente.\footnote{in realtà per - il filesystem \acr{ext2}, quando lo si monta con l'opzione \cmd{sync}, - il kernel provvede anche alla sincronizzazione automatica delle voci - delle directory.} - - -\subsection{Le funzioni \func{dup} e \func{dup2}} +\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. + +Il problema deriva dal fatto che usare due \textit{system call} in successione +non è mai un'operazione atomica dato che il kernel può interrompere +l'esecuzione del processo fra le due. Nel caso specifico il problema è stato +risolto introducendo la modalità di scrittura \itindex{append~mode} in +\textit{append}, attivabile con il flag \const{O\_APPEND}. In questo caso +infatti, come abbiamo illustrato in sez.~\ref{sec:file_open_close}, è il +kernel che aggiorna automaticamente la posizione alla fine del file prima di +effettuare la scrittura, e poi estende il file. Tutto questo avviene +all'interno di una singola \textit{system call}, la \func{write}, che non +essendo interrompibile da un altro processo realizza un'operazione atomica. + + +\subsection{La duplicazione dei file descriptor} \label{sec:file_dup} -Abbiamo già visto in sez.~\ref{sec:file_sharing} come un processo figlio +Abbiamo già visto in sez.~\ref{sec:file_shared_access} come un processo figlio condivida gli stessi file descriptor del padre; è possibile però ottenere un comportamento analogo all'interno di uno stesso processo \textit{duplicando} -un file descriptor. Per far questo si usa la funzione \funcd{dup} il cui -prototipo è: +un file descriptor. Per far questo si usa la funzione di sistema \funcd{dup}, +il cui prototipo è: \begin{funcproto}{ \fhead{unistd.h} @@ -1360,11 +1275,12 @@ prototipo è: La funzione ritorna, come \func{open}, il primo file descriptor libero. Il file descriptor è una copia esatta del precedente ed entrambi possono essere interscambiati nell'uso. Per capire meglio il funzionamento della funzione si -può fare riferimento a fig.~\ref{fig:file_dup}: l'effetto della funzione è -semplicemente quello di copiare il valore nella struttura -\kstruct{file\_struct}, cosicché anche il nuovo file descriptor fa riferimento -alla stessa voce nella \textit{file table}; per questo si dice che il nuovo -file descriptor è \textsl{duplicato}, da cui il nome della funzione. +può fare riferimento a fig.~\ref{fig:file_dup}. L'effetto della funzione è +semplicemente quello di copiare il valore di un certo file descriptor in +un altro all'interno della struttura \kstruct{file\_struct}, cosicché anche +questo faccia riferimento alla stessa voce nella \textit{file table}. Per +questo motivo si dice che il nuovo file descriptor è ``\textsl{duplicato}'', +da cui il nome della funzione. \begin{figure}[!htb] \centering \includegraphics[width=12cm]{img/filedup} @@ -1373,30 +1289,47 @@ file descriptor è \textsl{duplicato}, da cui il nome della funzione. \end{figure} Si noti che per quanto illustrato in fig.~\ref{fig:file_dup} i file descriptor -duplicati condivideranno eventuali lock, \textit{file status flag}, e -posizione corrente. Se ad esempio si esegue una \func{lseek} per modificare la -posizione su uno dei due file descriptor, essa risulterà modificata anche -sull'altro (dato che quello che viene modificato è lo stesso campo nella voce -della \textit{file table} a cui entrambi fanno riferimento). L'unica -differenza fra due file descriptor duplicati è che ciascuno avrà il suo -\textit{file descriptor flag}; a questo proposito va specificato che nel caso -di \func{dup} il flag di \textit{close-on-exec} \itindex{close-on-exec} (vedi -sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato -nella copia. - -L'uso principale di questa funzione è per la redirezione dell'input e -dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec}; -diventa così possibile associare un file (o una pipe) allo standard input o -allo standard output (torneremo sull'argomento in sez.~\ref{sec:ipc_pipe_use}, -quando tratteremo le pipe). Per fare questo in genere occorre prima chiudere -il file che si vuole sostituire, cosicché il suo file descriptor possa esser -restituito alla chiamata di \func{dup}, come primo file descriptor -disponibile. - -Dato che questa è l'operazione più comune, è prevista una diversa versione -della funzione, \funcd{dup2}, che permette di specificare esplicitamente -qual è il valore di file descriptor che si vuole avere come duplicato; il suo -prototipo è: +duplicati condivideranno eventuali lock (vedi sez.~\ref{sec:file_locking}), +\itindex{file~status~flag} i flag di stato, e la posizione corrente sul +file. Se ad esempio si esegue una \func{lseek} per modificare la posizione su +uno dei due file descriptor, essa risulterà modificata anche sull'altro, dato +che quello che viene modificato è lo stesso campo nella voce della +\textit{file table} a cui entrambi fanno riferimento. + +L'unica differenza fra due file descriptor duplicati è che ciascuno avrà un +suo \textit{file descriptor flag} indipendente. A questo proposito deve essere +tenuto presente che nel caso in cui si usi \func{dup} per duplicare un file +descriptor, se questo ha il flag di \textit{close-on-exec} +\itindex{close-on-exec} attivo (vedi sez.~\ref{sec:proc_exec} e +sez.~\ref{sec:file_fcntl}), questo verrà cancellato nel file descriptor +restituito come copia. + +L'uso principale di questa funzione è nella shell per la redirezione dei file +standard di tab.~\ref{tab:file_std_files} fra l'esecuzione di una \func{fork} +e la successiva \func{exec}. Diventa così possibile associare un file (o una +pipe) allo \itindex{standard~input} \textit{standard input} o allo +\itindex{standard~output} \textit{standard output} (vedremo un esempio in +sez.~\ref{sec:ipc_pipe_use}, quando tratteremo le pipe). + +Ci si può chiedere perché non sia in questo caso sufficiente chiudere il file +standard che si vuole redirigere e poi aprire direttamente con \func{open} il +file vi si vuole far corrispondere, invece di duplicare un file descriptor che +si è già aperto. La risposta sta nel fatto che il file che si vuole redirigere +non è detto sia un file regolare, ma potrebbe essere, come accennato, anche +una fifo o un socket, oppure potrebbe essere un file associato ad un file +descriptor che si è ereditato già aperto (ad esempio attraverso un'altra +\func{exec}) da un processo antenato del padre, del quale non si conosce il +nome. Operando direttamente con i file descriptor \func{dup} consente di +ignorare le origini del file descriptor che si duplica e funziona in maniera +generica indipendentemente dall'oggetto a cui questo fa riferimento. + +Per ottenere la redirezione occorre pertanto disporre del file descriptor +associato al file che si vuole usare e chiudere il file descriptor che si +vuole sostituire, cosicché esso possa esser restituito alla successiva +chiamata di \func{dup} come primo file descriptor disponibile. Dato che +questa è l'operazione più comune, è prevista un'altra funzione di sistema, +\funcd{dup2}, che permette di specificare esplicitamente qual è il numero di +file descriptor che si vuole ottenere come duplicato; il suo prototipo è: \begin{funcproto}{ \fhead{unistd.h} @@ -1409,31 +1342,173 @@ 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{EINTR}] la funzione è stata interrotta da un segnale. \item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file descriptor aperti. \end{errlist} } \end{funcproto} - -\noindent e qualora il file descriptor \param{newfd} sia già aperto (come -avviene ad esempio nel caso della duplicazione di uno dei file standard) esso -sarà prima chiuso e poi duplicato (così che il file duplicato sarà connesso -allo stesso valore per il file descriptor). +La funzione duplica il file descriptor \param{oldfd} su un altro file +descriptor di valore \param{newfd}. Qualora il file descriptor \param{newfd} +sia già aperto, come avviene ad esempio nel caso della duplicazione di uno dei +file standard di tab.~\ref{tab:file_std_files}, esso sarà prima chiuso e poi +duplicato. Se \param{newfd} è uguale a \param{oldfd} la funzione non fa nulla +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. + +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. La duplicazione dei file descriptor può essere effettuata anche usando la funzione di controllo dei file \func{fcntl} (che esamineremo in sez.~\ref{sec:file_fcntl}) con il parametro \const{F\_DUPFD}. L'operazione ha la sintassi \code{fcntl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per -\param{newfd} diventa equivalente a \func{dup}. +\param{newfd} diventa equivalente a \func{dup}. La sola differenza fra le due +funzioni (a parte la sintassi ed i diversi codici di errore) è che \func{dup2} +chiude il file descriptor \param{newfd} se questo è già aperto, garantendo che +la duplicazione sia effettuata esattamente su di esso, invece \func{fcntl} +restituisce il primo file descriptor libero di valore uguale o maggiore +di \param{newfd}, per cui se \param{newfd} è aperto la duplicazione avverrà su +un altro file descriptor. + +Su Linux inoltre è presente una terza funzione di sistema non +standard,\footnote{la funzione è stata introdotta con il kernel 2.6.27 e resa + disponibile con la \acr{glibc} 2.9.} \funcd{dup3}, che consente di duplicare +un file descriptor reimpostandone i flag, per usarla occorre definire la macro +\macro{\_GNU\_SOURCE} ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int dup3(int oldfd, int newfd, int flags)} +\fdesc{Duplica un file descriptor su un altro.} +} + +{La funzione ritorna il nuovo file descriptor in caso di successo e $-1$ per + un errore, nel qual caso \var{errno} assumerà gli stessi valori di + \func{dup2} più \errcode{EINVAL} qualora \param{flags} contenga un valore + non valido o \param{newfd} sia uguale a \param{oldfd}. +} +\end{funcproto} + +La funzione è identica a \func{dup2} ma prevede la possibilità di mantenere il +flag di \textit{close-on-exec} \itindex{close-on-exec} sul nuovo +file descriptor specificando \const{O\_CLOEXEC} in \param{flags} (che è l'unico +flag usabile in questo caso). Inoltre rileva esplicitamente la possibile +coincidenza fra \param{newfd} e \param{oldfd}, fallendo con un errore di +\errval{EINVAL}. + + +\subsection{Le funzioni di sincronizzazione dei dati} +\label{sec:file_sync} + +Come accennato in sez.~\ref{sec:file_open_close} tutte le operazioni di +scrittura sono in genere bufferizzate dal kernel, che provvede ad effettuarle +in maniera asincrona, ad esempio accorpando gli accessi alla stessa zona del +disco, in un secondo tempo rispetto al momento della esecuzione della +\func{write}. -La sola differenza fra le due funzioni\footnote{a parte la sintassi ed i - diversi codici di errore.} è che \func{dup2} chiude il file descriptor -\param{newfd} se questo è già aperto, garantendo che la duplicazione sia -effettuata esattamente su di esso, invece \func{fcntl} restituisce il primo -file descriptor libero di valore uguale o maggiore di \param{newfd} (e se -\param{newfd} è aperto la duplicazione avverrà su un altro file descriptor). +Per questo motivo quando è necessaria una sincronizzazione dei dati il sistema +mette a disposizione delle funzioni che provvedono a forzare lo scarico dei +dati dai buffer del kernel. La prima di queste funzioni di sistema è +\funcd{sync}, il cui prototipo è:\footnote{questo è il prototipo usato a + partire dalla \acr{glibc} 2.2.2 seguendo gli standard, in precedenza la + funzione era definita come \code{int sync(void)} e ritornava sempre $0$.} +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{void sync(void)} +\fdesc{Sincronizza il buffer della cache dei file col disco.} +} + +{La funzione non ritorna nulla e non prevede condizioni di errore.} +\end{funcproto} + +I vari standard prevedono che la funzione si limiti a far partire le +operazioni, ritornando immediatamente; con Linux fin dal kernel 1.3.20 invece +la funzione aspetta la conclusione delle operazioni di sincronizzazione. Si +tenga presente comunque che questo non dà la garanzia assoluta che i dati +siano integri dopo la chiamata, l'hardware dei dischi è in genere dotato di un +suo meccanismo interno di bufferizzazione che può ritardare ulteriormente la +scrittura effettiva. + +La funzione viene usata dal comando \cmd{sync} quando si vuole forzare +esplicitamente lo scarico dei dati su disco, un tempo era invocata da un +apposito demone di sistema (in genere chiamato \cmd{update}) che eseguiva lo +scarico dei dati ad intervalli di tempo fissi, ad esempio il valore +tradizionale usato da BSD era di 30 secondi, mentre su Linux il valore +utilizzato è di 5 secondi. + +Con le nuove versioni del kernel le operazioni di scarico periodico dei dati +su disco vengono gestite direttamente dal sistema della memoria virtuale, +attraverso opportuni \textit{task} interni al kernel il cui comportamento può +essere controllato attraverso il file \sysctlfile{vm/bdflush}. Per il +significato dei valori si può leggere la documentazione allegata ai sorgenti +del kernel nel file \file{Documentation/sysctl/vm.txt}. Si tenga presente che +la funzione di sistema \funcm{bdflush} che un tempo veniva usata per queste +impostazioni è deprecata e causa semplicemente la stampa di un messaggio nei +log del kernel, pertanto non la prenderemo in esame. + +Quando si vogliono scaricare soltanto i dati di un singolo file (ad esempio +essere sicuri che i dati di un database sono stati registrati su disco) si +possono usare le due funzioni di sistema \funcd{fsync} e \funcd{fdatasync}, i +cui prototipi sono: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int fsync(int fd)} +\fdesc{Sincronizza dati e metadati di un file.} +\fdecl{int fdatasync(int fd)} +\fdesc{Sincronizza i dati di un file.} +} + +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{fd} è un \index{file!speciali} file speciale + che non supporta la sincronizzazione. + \end{errlist} + ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO} nel loro + significato generico.} +\end{funcproto} + +Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del +file specificato, ed attendono fino alla conclusione delle operazioni; +\func{fsync} forza anche la sincronizzazione dei meta-dati del file (che +riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli +altri dati contenuti \itindex{inode} nell'\textit{inode} che si leggono con +\func{fstat}, come i tempi del file). + +Si tenga presente che questo non comporta la sincronizzazione della +directory che contiene il file (e scrittura della relativa voce su +disco) che deve essere effettuata esplicitamente.\footnote{in realtà per + il filesystem \acr{ext2}, quando lo si monta con l'opzione \cmd{sync}, + il kernel provvede anche alla sincronizzazione automatica delle voci + delle directory.} + + + +% TODO, aggiungere syncfs, introdotta con il 2.6.39 \subsection{Le funzioni \func{openat}, \func{mkdirat} e affini} @@ -1775,19 +1850,15 @@ per \var{cmd} è riportata di seguito: (il comportamento predefinito) restano aperti. \item[\const{F\_GETFL}] ritorna il valore del \textit{file status flag} in caso di successo o $-1$ in caso di errore; permette cioè di rileggere quei - bit impostati da \func{open} all'apertura del file che vengono memorizzati - (quelli riportati nella prima e terza sezione di - tab.~\ref{tab:file_open_flags}). -% TODO toglire riferimeto a tabella flag e mettere altro - + bit impostati da \func{open} all'apertura del file che vengono memorizzati, + quelli riportati in tab.~\ref{tab:open_access_mode_flag} e + tab.~\ref{tab:open_operation_flag}). \item[\const{F\_SETFL}] imposta il \textit{file status flag} al valore specificato da \param{arg}, ritorna un valore nullo in caso di successo o - $-1$ in caso di errore. Possono essere impostati solo i bit riportati nella - terza sezione di tab.~\ref{tab:file_open_flags}.\footnote{la pagina di - manuale riporta come impostabili solo \const{O\_APPEND}, - \const{O\_NONBLOCK} e \const{O\_ASYNC}.} -% TODO toglire riferimeto a tabella flag e mettere altro - + $-1$ in caso di errore. Possono essere impostati solo i bit riportati in + tab.~\ref{tab:open_operation_flag}.\footnote{la pagina di manuale riporta + come impostabili solo \const{O\_APPEND}, \const{O\_NONBLOCK} e + \const{O\_ASYNC}.} \item[\const{F\_GETLK}] richiede un controllo sul file lock specificato da \param{lock}, sovrascrivendo la struttura da esso puntata con il risultato; ritorna un valore nullo in caso di successo o $-1$ in caso di errore. Questa @@ -2119,8 +2190,9 @@ A parte i dettagli legati alla gestione delle operazioni di lettura e scrittura (sia per quel che riguarda la bufferizzazione, che le formattazioni), i \textit{file stream} restano del tutto equivalenti ai file descriptor (sui quali sono basati), ed in particolare continua a valere quanto -visto in sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in -sez.~\ref{sec:file_access_control} per il controllo di accesso. +visto in sez.~\ref{sec:file_shared_access} a proposito dell'accesso +concorrente ed in sez.~\ref{sec:file_access_control} per il controllo di +accesso. \itindend{file~stream} @@ -3867,12 +3939,6 @@ con uno dei valori \const{FSETLOCKING\_INTERNAL} o % LocalWords: locking fsetlocking type Virtual operation dentry unistd sys AT % LocalWords: modification hole functions FSETSIG pathname EEXIST CREAT EINTR % LocalWords: EISDIR EFBIG EOVERFLOW ELOOP NOFOLLOW ENODEV ENOENT ENOTDIR fork - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "gapil" -%%% End: -% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK EACCES% LocalWords: EFAULT % LocalWords: EMFILE ENAMETOOLONG ENFILE ENOMEM ENOSPC EROFS exec access RDWR % LocalWords: RDONLY ioctl AND ACCMODE creation Denial Service DoS opendir NFS % LocalWords: SOURCE LARGEFILE BITS NOCTTY TRUNC SHLOCK shared EXLOCK race SGI @@ -3890,4 +3956,12 @@ con uno dei valori \const{FSETLOCKING\_INTERNAL} o % LocalWords: sigaction SIGINFO siginfo SETLEASE lease GETLEASE NOTIFY request % LocalWords: everything framebuffer ENOTTY argp CDROM lsattr chattr magic % LocalWords: number FIOCLEX FIONCLEX FIOASYNC FIONBIO FIOSETOWN FIOGETOWN -% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY +% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY EACCES +% LocalWords: EBUSY OpenBSD +% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK +% LocalWords: EFAULT + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: diff --git a/img/filedup.dia b/img/filedup.dia index 14771736bb47757c734a092e6a9c69b15f3ca072..7230f1a05040d61542534bde191e2cd7bd84beda 100644 GIT binary patch literal 3133 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 Xm*NHgw@SSA-IqTB=O;rqZtnm9dYBUV literal 3028 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 WD1Q+DSE;{#`0#(m62oi7-~a%Pu-1tH diff --git a/img/filemultacc.dia b/img/filemultacc.dia index 5393ff1af27681f77df448c0038b3a613d777679..25911095b6ec3b8194bfa91f19a8b0499420c106 100644 GIT binary patch literal 4095 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 literal 3964 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 diff --git a/img/fileshar.dia b/img/fileshar.dia index 077ceb01c4b0919a5a403b8ed2f364e1ed4704a9..01d2f4ad6ba661b0a4fe8ba4622e214448fbaf92 100644 GIT binary patch literal 3986 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 literal 3858 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