Mandatory locking
[gapil.git] / fileadv.tex
index c269d6ae05216426c8931ebf123a6fab7e37195a..454d91b237a8899888231001900ff6620f3c2a6e 100644 (file)
@@ -33,7 +33,8 @@ affrontare nelle operazioni di I/O, che 
 devono eseguire operazioni che possono bloccarsi su più file descriptor:
 mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti
 dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata
 devono eseguire operazioni che possono bloccarsi su più file descriptor:
 mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti
 dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata
-inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un deadlock.
+inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
+\textit{deadlock}.
 
 Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
 questo tipo di comportamento aprendo un file in modalità
 
 Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
 questo tipo di comportamento aprendo un file in modalità
@@ -976,7 +977,8 @@ come maschera binaria ottenuta dall'OR di uno o pi
                              riportati sul file. Ne viene fatta una copia
                              privata cui solo il processo chiamante ha
                              accesso.  Le modifiche sono mantenute attraverso
                              riportati sul file. Ne viene fatta una copia
                              privata cui solo il processo chiamante ha
                              accesso.  Le modifiche sono mantenute attraverso
-                             il meccanismo del \textit{copy on write} e
+                             il meccanismo del 
+                             \textit{copy on write}\index{copy on write} e
                              salvate su swap in caso di necessità. Non è
                              specificato se i cambiamenti sul file originale
                              vengano riportati sulla regione
                              salvate su swap in caso di necessità. Non è
                              specificato se i cambiamenti sul file originale
                              vengano riportati sulla regione
@@ -988,7 +990,8 @@ come maschera binaria ottenuta dall'OR di uno o pi
     \macro{MAP\_EXECUTABLE}& Ignorato. \\
     \macro{MAP\_NORESERVE} & Si usa con \macro{MAP\_PRIVATE}. Non riserva
                              delle pagine di swap ad uso del meccanismo di
     \macro{MAP\_EXECUTABLE}& Ignorato. \\
     \macro{MAP\_NORESERVE} & Si usa con \macro{MAP\_PRIVATE}. Non riserva
                              delle pagine di swap ad uso del meccanismo di
-                             \textit{copy on write} per mantenere le
+                             \textit{copy on write}\index{copy on write}
+                             per mantenere le
                              modifiche fatte alla regione mappata, in
                              questo caso dopo una scrittura, se non c'è più
                              memoria disponibile, si ha l'emissione di
                              modifiche fatte alla regione mappata, in
                              questo caso dopo una scrittura, se non c'è più
                              memoria disponibile, si ha l'emissione di
@@ -997,7 +1000,7 @@ come maschera binaria ottenuta dall'OR di uno o pi
                              mappate. \\
     \macro{MAP\_GROWSDOWN} & Usato per gli stack. Indica 
                              che la mappatura deve essere effettuata con gli
                              mappate. \\
     \macro{MAP\_GROWSDOWN} & Usato per gli stack. Indica 
                              che la mappatura deve essere effettuata con gli
-                             indirizzi crecenti verso il basso.\\
+                             indirizzi crescenti verso il basso.\\
     \macro{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
                              argomenti \param{fd} e \param{offset} sono
                              ignorati.\footnotemark\\
     \macro{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
                              argomenti \param{fd} e \param{offset} sono
                              ignorati.\footnotemark\\
@@ -1234,8 +1237,8 @@ sovrapposizioni, e garantire la atomicit
 
 La prima modalità di file locking che è stata implementata nei sistemi
 unix-like è quella che viene usualmente chiamata \textit{advisory
 
 La prima modalità di file locking che è stata implementata nei sistemi
 unix-like è quella che viene usualmente chiamata \textit{advisory
-  locking},\footnote{Stevens in APUE fa riferimento a questo argomento come al
-  \textit{record locking}, dizione utilizzata anche dal manuale delle
+  locking},\footnote{Stevens in \cite{APUE} fa riferimento a questo argomento
+  come al \textit{record locking}, dizione utilizzata anche dal manuale delle
   \acr{glibc}; nelle pagine di manuale si parla di \textit{discretionary file
     lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock},
   mentre questo nome viene usato anche da Stevens per riferirsi al
   \acr{glibc}; nelle pagine di manuale si parla di \textit{discretionary file
     lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock},
   mentre questo nome viene usato anche da Stevens per riferirsi al
@@ -1272,7 +1275,7 @@ sono implementati in maniera completamente indipendente nelle due interfacce,
 che pertanto possono coesistere senza interferenze.
 
 Entrambe le interfacce prevedono la stessa procedura di funzionamento: si
 che pertanto possono coesistere senza interferenze.
 
 Entrambe le interfacce prevedono la stessa procedura di funzionamento: si
-inizia sempre con il richiere l'opportuno \textit{file lock} (un
+inizia sempre con il richiedere 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
 \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
@@ -1286,7 +1289,6 @@ gi
 \subsection{La funzione \func{flock}}
 \label{sec:file_flock}
 
 \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 è:
 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 è:
@@ -1329,28 +1331,32 @@ costanti riportate in \tabref{tab:file_flock_operation}.
 
 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
 
 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
-esclusiva. 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}. 
+alternativa. Se si specifica anche \macro{LOCK\_NB} la funzione non si
+bloccherà qualora il lock non possa essere acquisito, 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
 
 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 cosa
-succede in questi casi, occorre tenere presente che il file locking (qualunque
-sia l'interfaccia che si usa), anche se richiesto attraverso un file
-descriptor, agisce sempre su un file, secondo lo schema di
-\figref{fig:file_lock_struct}. Questo significa che le informazioni relative
-agli eventuali lock sono mantenute a livello di inode,\footnote{come mostrato
-  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}, il
-  cui indirizzo iniziale è mantenuto dal campo \var{i\_flock} della struttura
-  \var{inode} (il tutto è definito nei sorgenti del kernel in \file{fs.h}). 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}).} come è
-naturale dato che l'inode è l'unica cosa in comune cui possono accedere due
-processi diversi che aprono lo stesso file.
-
+confronti delle due funzioni \func{dup} e \func{fork}.  Per capire queste
+differenze occorre 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.
 
 \begin{figure}[htb]
   \centering
 
 \begin{figure}[htb]
   \centering
@@ -1360,37 +1366,54 @@ processi diversi che aprono lo stesso file.
   \label{fig:file_flock_struct}
 \end{figure}
 
   \label{fig:file_flock_struct}
 \end{figure}
 
-
-
-Nel caso dei lock creati con \func{flock} la semantica prevede che sia
-\func{dup} che \func{fork} non creano ulteriori istanze di un \textit{file
+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
   lock} quanto piuttosto degli ulteriori riferimenti allo stesso. Questo viene
-realizzato dal kernel mantenendo per ciascun \textit{file lock} un
-puntatore\footnote{nel campo \var{fl\_file} di \var{file\_lock}.} al file
-nella \textit{file table} cui esso fa riferimento.
-
-
-che il kernel mantiene per ciascuno di
-essi\footnote{nel campo \var{fl\_file}.} anche un riferimento
-
-essi fanno riferimento al
-
-
-
-
-Si tenga presente che la funzione blocca direttamente un file (cioè, rispetto
-allo schema di \secref{fig:file_stat_struct}, il blocco è mantenuto in
-riferimento alla struttura \var{file}, e 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. Questo
-comporta che un \textit{file lock} può essere rimosso su uno qualunque dei
-file descriptor che fanno riferimento allo stesso file: quindi se si toglie il
-blocco in un processo figlio o su un file descriptor duplicato, questo sarà
-cancellato rispettivamente anche nel processo padre e sul file descriptor
-originario.
-
-
+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, 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.
 
 
+Si tenga presente che \func{flock} non è in grado di funzionare per i file
+mantenuti 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à.
 
 \subsection{Il file locking POSIX}
 \label{sec:file_posix_lock}
 
 \subsection{Il file locking POSIX}
 \label{sec:file_posix_lock}
@@ -1398,8 +1421,8 @@ originario.
 La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
 quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
 già trattato questa funzione nelle sue molteplici funzionalità in
 La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
 quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
 già trattato questa funzione nelle sue molteplici funzionalità in
-\secref{sec:file_fcntl}, quando la si impiega per il \textit{file locking}
-però essa viene usata secondo il prototipo:
+\secref{sec:file_fcntl}; quando la si impiega per il \textit{file locking}
+però essa viene usata solo secondo il prototipo:
 \begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
   
   Applica o rimuove un \textit{file lock} sul file \param{fd}.
 \begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
   
   Applica o rimuove un \textit{file lock} sul file \param{fd}.
@@ -1424,21 +1447,13 @@ per
   }
 \end{prototype}
 
   }
 \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 una struttura
-\var{flock} la cui definizione è riportata in \figref{fig:struct_flock}.
-
+Al contrario di quanto avviene con l'interfaccia basata su \func{flock} con
+\func{fcntl} è possibile bloccare anche delle singole sezioni di un file;
+inoltre la funzione permette di leggere le informazioni relative ai blocchi
+esistenti.  Per poter fare tutto questo la funzione utilizza come terzo
+argomento una apposita struttura \var{flock} (la cui definizione è riportata
+in \figref{fig:struct_flock}) che contiene tutte le specifiche di un dato file
+lock.
 
 \begin{figure}[!htb]
   \footnotesize \centering
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1459,28 +1474,253 @@ struct flock {
   \label{fig:struct_flock}
 \end{figure}
 
   \label{fig:struct_flock}
 \end{figure}
 
+L'operazione effettivamente svolta dalla funzione è stabilita dal valore
+dall'argomento \param{cmd} che, come già riportato in \secref{sec:file_fcntl},
+specifica l'azione da compiere; i valori relativi al file locking sono tre:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\macro{F\_GETLK}] verifica se il file lock specificato dalla struttura
+  puntata da \param{lock} non è bloccato da qualche altro lock: in caso
+  affermativo sovrascrive la struttura con i valori relativi a quest'ultimo,
+  altrimenti si limita a impostarne il campo \var{l\_type} con
+  \macro{F\_UNLCK}.
+\item[\macro{F\_SETLK}] se il campo \var{l\_type} della struttura puntata da
+  \param{lock} è \macro{F\_RDLCK} o \macro{F\_WRLCK} richiede il
+  corrispondente file lock, se è \macro{F\_UNLCK} lo rilascia. Nel caso la
+  richiesta non possa essere soddisfatta a causa di un lock preesistente la
+  funzione ritorna immediatamente con un errore di \macro{EACCES} o di
+  \macro{EAGAIN}.
+\item[\macro{F\_SETLKW}] è identica a \macro{F\_SETLK}, ma se la richiesta di
+  un lock non può essere soddisfatta per la presenza di un altro blocco, mette
+  il processo in stato di attesa fintanto che il lock precedente non viene
+  rilasciato. Se l'attesa viene interrotta da un segnale la funzione ritorna
+  con un errore di \macro{EINTR}.
+\end{basedescript}
+
+Come accennato nell'interfaccia POSIX ogni file lock viene associato ad una
+struttura \func{flock}; i tre campi \var{l\_whence}, \var{l\_start} e
+\var{l\_len}, servono a specificare la sezione del file a cui fa riferimento
+il lock, \var{l\_start} specifica il byte di partenza, e \var{l\_len} la
+lunghezza della sezione; \var{l\_whence} infine imposta il riferimento da cui
+contare \var{l\_start} e segue la stessa semantica dell'omonimo argomento di
+\func{lseek}, coi tre possibili valori \macro{SEEK\_SET}, \macro{SEEK\_CUR} e
+\macro{SEEK\_END} (si vedano le relative descrizioni in
+\secref{sec:file_lseek}).
+
+Si tenga presente che un lock può essere richiesto anche per una regione al di
+là della corrente fine del file, così che una eventuale estensione dello
+stesso resti coperta dal blocco. Se si specifica un valore nullo per
+\var{l\_len} il blocco si considera esteso fino alla dimensione massima del
+file; in questo modo è possibile bloccare una qualunque regione a partire da
+un certo punto fino alla fine del file, coprendo automaticamente quanto
+eventualmente aggiunto in coda allo stesso.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{F\_RDLCK} & Richiede un blocco condiviso (\textit{read lock}).\\
+    \macro{F\_WRLCK} & Richiede un blocco esclusivo (\textit{write lock}).\\
+    \macro{F\_UNLCK} & Richiede l'eliminazione di un lock.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori possibili per il campo \var{l\_type} di \func{flock}.}
+  \label{tab:file_flock_type}
+\end{table}
+
+Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
+può assumere i tre valori riportati in \tabref{tab:file_flock_type}, che
+permettono di richiedere rispettivamente uno \textit{shared lock}, un
+\textit{esclusive lock}, e la rimozione di un lock precedentemente acquisito.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=13cm]{img/file_posix_lock}
+  \caption{Schema dell'architettura del file locking, nel caso particolare  
+    del suo utilizzo secondo l'interfaccia standard POSIX.}
+  \label{fig:file_posix_lock}
+\end{figure}
+
+Infine il campo \var{l\_pid} riporta (viene usato solo in lettura, quando si
+chiama \func{fcntl} con \macro{F\_GETLK}) qual'è il processo cui appartiene il
+file lock. Nella semantica POSIX infatti il comportamento dei lock è diverso
+rispetto a quanto visto in precedenza per \func{flock}. Lo schema della
+struttura usata in questo caso è riportato in \figref{fig:file_posix_lock};
+come si vede essa è molto simile a quanto visto in
+\figref{fig:file_flock_struct} per \func{flock}:\footnote{in questo caso si
+  sono evidenziati nella figura i campi di \var{file\_lock} significativi per
+  la semantica POSIX, in particolare adesso ciascun lock contiene, oltre al
+  \acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
+  bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}.  La struttura è
+  comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
+  impostato il bit \macro{FL\_POSIX} ed il campo \var{fl\_file} non viene
+  usato.} il lock è sempre associato all'inode, solo che in questo caso la
+titolarità non viene identificata con il riferimento ad una voce nella file
+table, ma con il valore del \acr{pid} del processo.
+
+Tutto ciò significa che la rimozione di un blocco viene effettuata
+controllando che il \acr{pid} del processo richiedente corrisponda a quello
+contenuto nel lock. Questa diversa modalità ha delle conseguenze precise
+riguardo il comportamento dei lock POSIX. La prima conseguenza è che un lock
+POSIX non viene mai ereditato attraverso una \func{fork}, dato che il processo
+figlio avrà un \acr{pid} diverso, mentre passa indenne attraverso una
+\func{exec} in quanto il \acr{pid} resta lo stesso.  Questo comporta che, al
+contrario di quanto avveniva con la semantica BSD, quando processo termina
+tutti i file lock da esso detenuti vengono immediatamente rilasciati.
+
+La seconda conseguenza è che qualunque file descriptor che faccia riferimento
+allo stesso file (che sia stato ottenuto con una \func{dup} o con una
+\func{open} non fa differenza) può essere usato per rimuovere un lock, dato
+che quello che conta è solo il \acr{pid} del processo. Da questo deriva una
+ulteriore sottile differenza di comportamento: dato che alla chiusura di un
+file i lock ad esso associati vengono rimossi, nella semantica POSIX basterà
+chiudere un file descriptor per cancellare tutti i lock relativi al file cui
+esso faceva riferimento, anche se questi fossero stati creati usando altri
+file descriptor che restano aperti.
+
+Abbiamo visto come l'interfaccia POSIX per il file locking sia molto più
+potente e flessibile di quella di BSD, ma è anche molto più complicata da
+usare per le varie opzioni da passare a \func{fcntl}. Per questo motivo è
+disponibile anche una interfaccia semplificata (ripresa da System V) che
+utilizza la funzione \func{lockf}, il cui prototipo è:
+\begin{prototype}{sys/file.h}{int lockf(int fd, int cmd, off\_t len)}
+  
+  Applica, controlla o rimuove un \textit{file lock} sul file \param{fd}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\macro{EWOULDBLOCK}] Non è possibile acquisire il lock, e si è
+      selezionato \macro{LOCK\_NB}, oppure l'operazione è proibita perché il
+      file è mappato in memoria.
+    \item[\macro{ENOLCK}] Il sistema non ha le risorse per il locking: ci sono
+      troppi segmenti di lock aperti, si è esaurita la tabella dei lock.
+    \end{errlist}
+    ed inoltre \macro{EBADF}, \macro{EINVAL}.
+  }
+\end{prototype}
+
+Il comportamento della funzione dipende dal valore dell'argomento \param{cmd}
+che specifica quale azione eseguire; i valori possibili sono riportati in
+\tabref{tab:file_lockf_type}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{8cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{LOCK\_SH}& Richiede uno \textit{shared lock}. Più processi possono
+                      mantenere un lock condiviso sullo stesso file.\\
+    \macro{LOCK\_EX}& Richiede un \textit{exclusive lock}. Un solo processo
+                      alla volta può mantenere un lock esclusivo su un file. \\
+    \macro{LOCK\_UN}& Sblocca il file.\\
+    \macro{LOCK\_NB}& Non blocca la funzione quando il lock non è disponibile,
+                      si specifica sempre insieme ad una delle altre operazioni
+                      con un OR aritmetico dei valori.\\ 
+    \hline    
+  \end{tabular}
+  \caption{Valori possibili per il campo \var{cmd} di \func{lockf}.}
+  \label{tab:file_lockf_type}
+\end{table}
+
+Qualora il lock non possa essere acquisito, a meno di non aver specificato
+\macro{LOCK\_NB}, la funzione si blocca fino alla disponibilità dello stesso.
+Dato che la funzione è implementata utilizzando \func{fcntl} la semantica
+delle operazioni è la stessa di quest'ultima (pertanto la funzione non è
+affatto equivalente a \func{flock}).
+
 
 
 \subsection{Il \textit{mandatory locking}}
 \label{sec:file_mand_locking}
 
 Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4,
 
 
 \subsection{Il \textit{mandatory locking}}
 \label{sec:file_mand_locking}
 
 Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4,
-per introdurre un file locking che come dice il nome, fosse effettivo
+per introdurre un file locking che, come dice il nome, fosse effettivo
 indipendentemente dai controlli eseguiti da un processo. Con il
 \textit{mandatory locking} infatti è possibile far eseguire il blocco del file
 indipendentemente dai controlli eseguiti da un processo. Con il
 \textit{mandatory locking} infatti è possibile far eseguire il blocco del file
-direttamente al sistema, così che anche qualora non si predisponessero le
+direttamente al sistema, così che, anche qualora non si predisponessero le
 opportune verifiche nei processi, questo verrebbe comunque rispettato.
 
 Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
 opportune verifiche nei processi, questo verrebbe comunque rispettato.
 
 Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
-utilizzo particolare del bit \acr{suid}. Se si ricorda quanto esposto in
-\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare
-l'userid effettivo con cui viene eseguito un programma, ed è pertanto sempre
-associato alla presenza del permesso di esecuzione. Impostando questo bit su
-un file senza permesso di esecuzione in un sistema che supporta il
-\textit{mandatory locking}, fa sì che quest'ultimo venga attivato per il file
-in questione. In questo modo una combinazione dei permessi originariamente non
-contemplata, in quanto senza significato, diventa l'indicazione della presenza
-o meno del \textit{mandatory locking}.
+utilizzo particolare del bit \acr{sgid}. Se si ricorda quanto esposto in
+\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
+groupid effettivo con cui viene eseguito un programma, ed è pertanto sempre
+associato alla presenza del permesso di esecuzione per il gruppo. Impostando
+questo bit su un file senza permesso di esecuzione in un sistema che supporta
+il \textit{mandatory locking}, fa sì che quest'ultimo venga attivato per il
+file in questione. In questo modo una combinazione dei permessi
+originariamente non contemplata, in quanto senza significato, diventa
+l'indicazione della presenza o meno del \textit{mandatory
+  locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
+  \secref{sec:file_chmod} e cioè che il bit \acr{sgid} viene cancellato (come
+  misura di sicurezza) quando di scrive su un file, questo non vale quando
+  esso viene utilizzato per attivare il \textit{mandatory locking}.}
+
+L'uso del \textit{mandatory locking} presenta vari aspetti delicati, dato che
+neanche root può passare sopra ad un lock; pertanto un processo che blocchi un
+file cruciale può renderlo completamente inaccessibile, rendendo completamente
+inutilizzabile il sistema\footnote{il problema si potrebbe risolvere
+  rimuovendo il bit \acr{sgid}, ma non è detto che sia così facile fare questa
+  operazione con un sistema bloccato.} inoltre con il \textit{mandatory
+  locking} si può bloccare completamente un server NFS richiedendo una lettura
+su un file su cui è attivo un lock. Per questo motivo l'abilitazione del
+mandatory locking è di norma disabilitata, e deve essere attivata filesystem
+per filesystem in fase di montaggio (specificando l'apposita opzione di
+\func{mount} riportata in \tabref{tab:sys_mount_flags}, o con l'opzione
+\cmd{mand} per il comando).
+
+Si tenga presente inoltre che il \textit{mandatory locking} funziona
+sull'interfaccia POSIX di \func{fcntl}, questo significa che non ha nessun
+effetto sui lock richiesti con l'interfaccia di \func{flock}, ed inoltre che
+la granularità del lock è quella del singolo byte, come per \func{fcntl}.
+
+La sintassi di acquisizione dei lock è esattamente la stessa vista in
+precedenza per \func{fcntl} e \func{lockf}, la differenza è che in caso di
+mandatory lock attivato non è più necessario controllare la disponibilità di
+accesso al file, ma si potranno usare direttamente le ordinarie funzioni di
+lettura e scrittura e sarà compito del kernel gestire direttamente il file
+locking.
+
+Questo significa che in caso di read lock la lettura dal file potrà avvenire
+normalmente con \func{read}, mentre una \func{write} si bloccherà fino al
+rilascio del lock, a meno di non aver aperto il file con \macro{O\_NONBLOCK},
+nel qual caso essa ritornerà immediatamente con un errore di \macro{EAGAIN}.
+
+Se invece si è acquisito un write lock tutti i tentativi di leggere o scrivere
+sulla regione del file bloccata fermeranno il processo fino al rilascio del
+lock, a meno che il file non sia stato aperto con \macro{O\_NONBLOCK}, nel
+qual caso di nuovo si otterrà un ritorno immediato con l'errore di
+\macro{EAGAIN}.
+
+Infine occorre ricordare che le funzioni di lettura e scrittura non sono le
+sole ad operare sui contenuti di un file, e che sia \func{creat} che
+\func{open} (quando chiamata con \macro{O\_TRUNC}) effettuano dei cambiamenti,
+così come \func{truncate}, riducendone le dimensioni (a zero nei primi due
+casi, a quanto specificato nel secondo). Queste operazioni sono assimilate a
+degli accessi in scrittura e pertanto non potranno essere eseguite (fallendo
+con un errore di \macro{EAGAIN}) su un file su cui sia presente un qualunque
+lock (le prime due sempre, la terza solo nel caso che la riduzione delle
+dimensioni del file vada a sovrapporsi ad una regione bloccata).
+
+L'ultimo aspetto della interazione del \textit{mandatory locking} con le
+funzioni di accesso ai file è quello relativo ai file mappati in memoria
+appena trattati in \secref{sec:file_memory_map}; anche in tal caso infatti,
+quando si esegue la mappatura con l'opzione \macro{MAP\_SHARED}, si ha un
+accesso al contenuto del file. Lo standard SVID prevede che sia impossibile
+eseguire il memory mapping di un file su cui sono presenti dei
+lock\footnote{alcuni sistemi, come HP-UX, sono ancora più restrittivi e lo
+  impediscono anche in caso di \textit{advisory locking}, anche se questo non
+  ha molto senso.} in Linux è stata però fatta la scelta implementativa di
+seguire questo comportamento soltanto quando si chiama \func{mmap} con
+l'opzione \macro{MAP\_SHARED} (nel qual caso la funzione fallisce con il
+solito \macro{EAGAIN}). 
+