X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=0d6e2f08d1f3160ce34f94cd4b847d0ebc9526dd;hp=7ff5ff72f9ac965bb3682fa455e3d4d8e73b30aa;hb=933c31be4afaf6d54c982bd493195f9fb1b5c9b6;hpb=821f26c01a474d3e79c15855d855683c7b37085e diff --git a/fileadv.tex b/fileadv.tex index 7ff5ff7..0d6e2f0 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1232,13 +1232,22 @@ sovrapposizioni, e garantire la atomicit \label{sec:file_record_locking} La prima modalità di file locking che è stata implementata nei sistemi -unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in -quanto sono i singoli processi, e non il 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. +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 + \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 + \textit{file locking} di POSIX. Dato che la dizione \textit{record locking} + è quantomeno ambigua in quanto non esiste niente che possa fare riferimento + al concetto di \textit{record}, alla fine si è scelto di mantenere il nome + \textit{advisory locking}.} in quanto sono i singoli processi, e non il +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. In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory locking}, la prima è quella derivata da BSD, che è basata sulla funzione @@ -1247,9 +1256,29 @@ System V), che 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, come accennato essa è basata sulla funzione \func{flock}, il cui -prototipo è: +intero file, funzione usata per richiedere e rimuovere un \textit{file lock} è +\func{flock}, il cui prototipo è: \begin{prototype}{sys/file.h}{int flock(int fd, int operation)} Applica o rimuove un \textit{file lock} sul file \param{fd}. @@ -1275,12 +1304,8 @@ Il comportamento della funzione \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \macro{LOCK\_SH} & Asserisce uno \textit{shared lock} (blocco - condiviso) sul file. Un blocco condiviso può essere - mantenuto da più processi contemporaneamente.\\ - \macro{LOCK\_EX} & Asserisce un \textit{esclusive lock} (blocco - esclusivo) sul file. Un blocco esclusivo può essere - mantenuto da un solo processo alla volta.\\ + \macro{LOCK\_SH} & Asserisce uno \textit{shared lock} sul file.\\ + \macro{LOCK\_EX} & Asserisce un \textit{esclusive lock} sul file.\\ \macro{LOCK\_UN} & Sblocca il file.\\ \macro{LOCK\_NB} & Impedisce che la funzione si blocchi nella richiesta di un \textit{file lock}.\\ @@ -1290,12 +1315,70 @@ Il comportamento della funzione \label{tab:file_flock_operation} \end{table} +La funzione blocca direttamente il file (cioè rispetto allo schema di +\secref{fig:file_stat_struct} fa riferimento all'inode, non al file +descriptor). Pertanto sia \func{dup} che \func{fork} non creano altre istanze +di un \textit{file lock}. + +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: +\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)} + + Applica 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{EACCES}] L'operazione è proibita per la presenza di + \textit{file lock} da parte di altri processi. + \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, o il + protocollo per il locking remoto è fallito. + \item[\macro{EDEADLK}] Si è richiesto un lock su una regione bloccata da + un altro processo che è a sua volta in attesa dello sblocco di un lock + mantenuto dal processo corrente; si avrebbe pertanto un + \textit{deadlock}. Non è garantito che il sistema riconosca sempre + questa situazione. + \item[\macro{EINTR}] La funzione è stata interrotta da un segnale prima di + poter acquisire un lock. + \end{errlist} + ed inoltre \macro{EBADF}, \macro{EFAULT}. + } +\end{prototype} -Si tenga conto che la funzione non è in grado di eseguire un blocco su NFS, in -tal caso occorre usare \func{fcntl} che funziona anche attraverso NFS, posto -che il server supporti il \textit{file locking}. +Al contrario di \func{flock} con \func{fcntl} è possibile bloccare anche solo +delle sezioni di un file. La funzione prende come argomento +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct struct { + 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. */ + off_t l_len; /* Size of the locked area; zero means until EOF. */ + pid_t l_pid; /* Process holding the lock. */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \type{flock}, usata da \func{fcntl} per il file + locking.} + \label{fig:struct_flock} +\end{figure} + + + + +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}