Risistemata flock, aggiunta figura sulla struttura del sistema
[gapil.git] / fileadv.tex
index 454396284aeb4eda50e21e3bc3db924ad9e84ccc..349d1573bc11750f46e04bef05be284bfbc8c180 100644 (file)
@@ -1228,6 +1228,7 @@ bloccare l'accesso al file da parte di altri processi, cos
 sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
 
 
+
 \subsection{L'\textit{advisory locking}}
 \label{sec:file_record_locking}
 
@@ -1246,39 +1247,49 @@ sistema, che si incaricano di asserire e verificare se esistono delle
 condizioni di blocco per l'accesso ai file.  Questo significa che le funzioni
 \func{read} o \func{write} non risentono affatto della presenza di un
 eventuale blocco, e che sta ai vari processi controllare esplicitamente lo
-stato dei file condivisi prima di accedervi ed implementare opportunamente un
-protocollo di accesso.
+stato dei file condivisi prima di accedervi, implementando un opportuno
+protocollo.
+
+In generale si distinguono due tipologie di blocco per un file: la prima è il
+cosiddetto \textit{shared lock}, detto anche \textit{read lock} in quanto
+serve a bloccare l'accesso in scrittura su un file affinché non venga
+modificato mentre lo si legge. Si parla di \textsl{blocco condiviso} in quanto
+più processi possono richiedere contemporaneamente uno \textit{shared lock}
+su un file per proteggere il loro accesso in lettura.
+
+La seconda tipologia è il cosiddetto \textit{exclusive lock}, detto anche
+\textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in
+lettura che in scrittura) da parte di altri processi mentre lo si sta
+scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo
+processo alla volta può richiedere un \textit{exclusive lock} su un file per
+proteggere il suo accesso in scrittura.
 
 In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory
   locking}, la prima è quella derivata da BSD, che è basata sulla funzione
-\func{flock}, la seconda è quella standardizzata da POSIX.1 (originaria di
+\func{flock}, la seconda è quella standardizzata da POSIX.1 (derivata da
 System V), che è basata sulla funzione \func{fcntl}.  I \textit{file lock}
 sono implementati in maniera completamente indipendente nelle due interfacce,
 che pertanto possono coesistere senza interferenze.
 
-In generale si distinguono due tipologie di blocco per un file: la prima è il
-cosiddetto \textit{shared lock}, detto anche \textit{read lock} in quanto
-serve a bloccare l'accesso in scrittura su un file affinché non venga
-modificato mentre lo si legge. Si parla di \textsl{blocco condiviso} in quanto
-più processi possono richiedere contemporaneamente uno \textit{shared lock}
-per proteggere un accesso in lettura.
-
-La seconda è il cosiddetto \textit{exclusive lock}, detto anche \textit{write
-  lock} in quanto serve a bloccare l'accesso su un file da parte di altri (sia
-in lettura che in scrittura) mentre lo si sta scrivendo. Si parla di
-\textsl{blocco esclusivo} appunto perché un solo processo alla volta può
-richiedere un \textit{exclusive lock} per proteggere un accesso in scrittura.
-
-Entrambe le interfacce garantiscono che quando si richiede un \textit{file
-  lock} su un file su cui ne sia già presente un altro che non ne consente
-l'acquisizione (uno \textit{shared lock} su un file con un \textit{exclusive
-  lock}, o un \textit{exclusive lock} su un file con altro \textit{file lock})
-la funzione blocca il processo fintanto che \textit{file lock} preesistente
-non viene rimosso.
-
-L'interfaccia classica usata da BSD permette di eseguire il blocco solo su un
-intero file, funzione usata per richiedere e rimuovere un \textit{file lock} è
-\func{flock}, il cui prototipo è:
+Entrambe le interfacce prevedono la stessa procedura di funzionamento: si
+inizia sempre con il richiere l'opportuno \textit{file lock} (un
+\textit{exclusive lock} per una scrittura, uno \textit{shared lock} per una
+lettura) prima di eseguire l'accesso ad un file.  Se il lock viene acquisito
+il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un
+comportamento non bloccante) viene posto in stato di sleep. Una volta finite
+le operazioni sul file si deve provvedere a rimuovere il lock.  Si ricordi che
+la condizione per acquisire uno \textit{shared lock} è che il file non abbia
+già un \textit{exclusive lock} attivo, mentre per acquisire un
+\textit{exclusive lock} non deve essere presente nessun tipo di blocco.
+
+
+\subsection{La funzione \func{flock}}
+\label{sec:file_flock}
+
+
+La prima interfaccia per il file locking, quella derivata da BSD, permette di
+eseguire un blocco solo su un intero file; la funzione usata per richiedere e
+rimuovere un \textit{file lock} è \func{flock}, ed il suo prototipo è:
 \begin{prototype}{sys/file.h}{int flock(int fd, int operation)}
   
   Applica o rimuove un \textit{file lock} sul file \param{fd}.
@@ -1292,9 +1303,10 @@ intero file, funzione usata per richiedere e rimuovere un \textit{file lock} 
   }
 \end{prototype}
 
-Il comportamento della funzione è specificato dal valore dell'argomento
-\param{operation}, da passare come maschera binaria dei valori riportati in 
-\tabref{tab:file_flock_operation}.
+La funzione può essere usata per acquisire o rilasciare un blocco a seconda di
+quanto specificato tramite il valore dell'argomento \param{operation}, questo
+viene interpretato come maschera binaria, e deve essere passato utilizzando le
+costanti riportate in \tabref{tab:file_flock_operation}.
 
 \begin{table}[htb]
   \centering
@@ -1315,21 +1327,89 @@ Il comportamento della funzione 
   \label{tab:file_flock_operation}
 \end{table}
 
+I primi due valori, \macro{LOCK\_SH} e \macro{LOCK\_EX} permettono di
+richiedere un \textit{file lock}, ed ovviamente devono essere usati in maniera
+alternativa. Se si specifica anche \macro{LOCK\_NB} la funzione non si
+bloccherà qualora il lock non possa essere aqcuisito, ma ritornerà subito con
+un errore di \macro{EWOULDBLOCK}. Per rilasciare un lock si dovrà invece usare
+\macro{LOCK\_NB}.
+
+La semantica del file locking di BSD è diversa da quella del file locking
+POSIX, in particolare per quanto riguarda il comportamento dei lock nei
+confronti delle due funzioni \func{dup} e \func{fork}.  Per capire queste
+differenze occore prima descrivere con maggiore dettaglio come viene
+realizzato il file locking nel kernel.
+
+In \figref{fig:file_flock_struct} si è riportato uno schema essenziale
+dell'implementazione del file locking in Linux; il punto fondamentale da
+capire è che un lock, qualunque sia l'interfaccia che si usa, anche se
+richiesto attraverso un file descriptor, agisce sempre su un file; perciò le
+informazioni relative agli eventuali \textit{file lock} sono mantenute a
+livello di inode,\footnote{in particolare, come accennato in
+  \figref{fig:file_flock_struct}, i \textit{file lock} sono mantenuti un una
+  \textit{linked list}\index{linked list} di strutture \var{file\_lock}. La
+  lista è referenziata dall'indirizzo di partenza mantenuto dal campo
+  \var{i\_flock} della struttura \var{inode} (per le definizioni esatte si
+  faccia riferimento al file \file{fs.h} nei sorgenti del kernel).  Un bit del
+  campo \var{fl\_flags} di specifica se si tratta di un lock in semantica BSD
+  (\macro{FL\_FLOCK}) o POSIX (\macro{FL\_POSIX}).} dato che questo è l'unico
+riferimento in comune che possono avere due processi diversi che aprono lo
+stesso file.
 
-Con \func{flock} il blocco è associato direttamente al file (cioè rispetto
-allo schema di \secref{sec:file_fd} fa riferimento all'inode e non al file
-descriptor); pertanto sia \func{dup} che \func{fork} non creano altre istanze
-del blocco ma piuttosto degli ulteriori riferimenti allo stesso \textit{file
-  lock}. 
-
-La funzione blocca direttamente il file (cioè rispetto allo schema di
-\secref{fig:file_stat_struct} fa riferimento alla struttura \var{file}, non al
-file descriptor). Pertanto sia \func{dup} che \func{fork} non creano ulteriori
-istanze di un \textit{file lock} quanto piuttosto degli ulteriori riferimenti
-allo stesso \textit{file lock}. Questo comporta che un lock può essere rimosso
-su uno qualunque dei file descriptor che fanno riferimento allo stesso file,
-ed esso .
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=13cm]{img/file_flock}
+  \caption{Schema dell'architettura del file locking, nel caso particolare  
+    del suo utilizzo da parte dalla funzione \func{flock}.}
+  \label{fig:file_flock_struct}
+\end{figure}
 
+La richiesta di un file lock prevede una scansione della lista per determinare
+se l'acquisizione è possibile, ed in caso positivo l'aggiunta di un nuovo
+elemento.\footnote{cioè una nuova struttura \var{file\_lock}.}  Nel caso dei
+lock creati con \func{flock} la semantica della funzione prevede che sia
+\func{dup} che \func{fork} non creino ulteriori istanze di un \textit{file
+  lock} quanto piuttosto degli ulteriori riferimenti allo stesso. Questo viene
+realizzato dal kernel associando ad ogni nuovo \textit{file lock} un
+puntatore\footnote{il puntatore è mantenuto nel campo \var{fl\_file} di
+  \var{file\_lock}, e viene utilizzato solo per i lock creati con la semantica
+  BSD.} alla voce nella \textit{file table} da cui si è richiesto il blocco,
+che così ne identifica il titolare.
+
+Questa struttura comporta che, quando si richiede la rimozione di un file
+lock, il kernel acconsenta solo se la richiesta proviene da un file descriptor
+che fa riferimento ad una voce nella file table corrispondente a quella
+registrata nel blocco.  Allora se ricordiamo quanto visto in
+\secref{sec:file_dup} e \secref{sec:file_sharing}, e cioè che i file
+descriptor duplicati e quelli ereditati in un processo figlio puntano sempre
+alla stessa voce nella file table, si può capire immediatamente quali sono le
+conseguenze nei confronti delle funzioni \func{dup} e \func{fork}.
+
+Sarà cioè possibile rimuovere un file lock attraverso uno qualunque dei file
+descriptor che fanno riferimento alla stessa voce nella file table, quindi
+anche se questo è diverso da quello con cui lo si è
+creato,\footnote{attenzione, questo non vale se il file descriptor fa
+  riferimento allo stesso file, ma attraverso una voce diversa della file
+  table, come accade tutte le volte che si apre più volte lo stesso file.} o
+se si esegue la rimozione in un processo figlio; inoltre una volta tolto un
+file lock, la rimozione avrà effetto su tutti i file descriptor che
+condividono la stessa voce nella file table, e quindi, nel caso di file
+descriptor ereditati attraverso una \func{fork}, anche su processi diversi.
+
+Infine, per evitare che la terminazione imprevista di un processo lasci attivi
+dei file lock, è previsto che quando un file viene chiuso il kernel provveda
+anche a rimuovere tutti i lock ad esso associati. Anche in questo caso occorre
+tenere presente cosa succede quando si hanno file descriptor duplicati; in tal
+caso infatti il file non verrà effettivamente chiuso (ed il lock rimosso)
+fintanto che non viene rilasciata la relativa voce nella file table; la
+rimozione cioè avverrà solo quando tutti i file descriptor che fanno
+riferimento alla stessa voce sono stati chiusi, quindi, nel caso ci siano
+processi figli che mantengono ancora aperto un file descriptor, il lock non
+sarà rilasciato.
+
+
+\subsection{Il file locking POSIX}
+\label{sec:file_posix_lock}
 
 La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
 quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
@@ -1360,15 +1440,27 @@ per
   }
 \end{prototype}
 
+Si tenga presente che \func{flock} non è in grado di funzionare per i file
+manetenuti su NFS, in questo caso, se si ha la necessità di eseguire il
+\textit{file locking}, occorre usare l'interfaccia basata su \func{fcntl} che
+può funzionare anche attraverso NFS, a condizione che sia il client che il
+server supportino questa funzionalità.
+La standardizzatione operata con POSIX.1 ha adottato le API per il
+\textit{file locking} originarie di System V, basate sulla funzione 
+
+
+
 Al contrario di \func{flock} con \func{fcntl} è possibile bloccare anche solo
-delle sezioni di un file. La funzione prende come argomento 
+delle sezioni di un file. La funzione prende come argomento una struttura
+\var{flock} la cui definizione è riportata in \figref{fig:struct_flock}.
 
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
     \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct struct {
+struct flock {
     short int l_type;   /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK.  */
     short int l_whence; /* Where `l_start' is relative to (like `lseek').  */
     off_t l_start;      /* Offset where the lock begins.  */
@@ -1385,12 +1477,6 @@ struct struct {
 
 
 
-
-Si tenga conto che \func{flock} non è in grado di eseguire il \textit{file
-  locking} su NFS, se si ha questa necessità occorre usare \func{fcntl} che
-funziona anche attraverso NFS, posto che il server supporti il \textit{file
-  locking}.
-
 \subsection{Il \textit{mandatory locking}}
 \label{sec:file_mand_locking}