-%% fileadv.tex
-%%
-%% Copyright (C) 2000-2005 Simone Piccardi. Permission is granted to
-%% copy, distribute and/or modify this document under the terms of the GNU Free
-%% Documentation License, Version 1.1 or any later version published by the
-%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
-%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
-%% license is included in the section entitled "GNU Free Documentation
-%% License".
-%%
-\chapter{La gestione avanzata dei file}
-\label{cha:file_advanced}
-
-In questo capitolo affronteremo le tematiche relative alla gestione avanzata
-dei file. In particolare tratteremo delle funzioni di input/output avanzato,
-che permettono una gestione più sofisticata dell'I/O su file, a partire da
-quelle che permettono di gestire l'accesso contemporaneo a più file, per
-concludere con la gestione dell'I/O mappato in memoria. Dedicheremo poi la
-fine del capitolo alle problematiche del \textit{file locking}.
-
-
-\section{L'\textit{I/O multiplexing}}
-\label{sec:file_multiplexing}
-
-Uno dei problemi che si presentano quando si deve operare contemporaneamente
-su molti file usando le funzioni illustrate in
-cap.~\ref{cha:file_unix_interface} e cap.~\ref{cha:files_std_interface} è che
-si può essere bloccati nelle operazioni su un file mentre un altro potrebbe
-essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
-problema. In questa sezione forniremo una introduzione a questa problematica
-ed analizzeremo le varie funzioni usate per implementare questa modalità di
-I/O.
-
-
-\subsection{La problematica dell'\textit{I/O multiplexing}}
-\label{sec:file_noblocking}
-
-Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call,\index{system~call~lente} che in
-certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
- ricordi però che questo può accadere solo per le pipe, i
- socket\index{socket} ed alcuni file di
- dispositivo\index{file!di~dispositivo}; sui file normali le funzioni di
- lettura e scrittura ritornano sempre subito.} Ad esempio le operazioni di
-lettura possono bloccarsi quando non ci sono dati disponibili sul descrittore
-su cui si sta operando.
-
-Questo comportamento causa uno dei problemi più comuni che ci si trova ad
-affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
-più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
-possibile prevedere quando questo può avvenire (il caso più classico è quello
-di un server in attesa di dati in ingresso da vari client). Quello che può
-accadere è di restare bloccati nell'eseguire una operazione su un file
-descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere
-un'altro disponibile. Questo comporta nel migliore dei casi una operazione
-ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
-nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
-da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
-potrebbe addirittura arrivare ad un \textit{deadlock}\itindex{deadlock}.
-
-Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento delle funzioni di I/O aprendo un file in
-\textsl{modalità non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK}
-nella chiamata di \func{open}. In questo caso le funzioni di input/output
-eseguite sul file che si sarebbero bloccate, ritornano immediatamente,
-restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O
-permette di risolvere il problema controllando a turno i vari file descriptor,
-in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
-Ovviamente questa tecnica, detta \textit{polling}\itindex{polling}, è
-estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
-eseguire in continuazione delle system call che nella gran parte dei casi
-falliranno.
-
-Per superare questo problema è stato introdotto il concetto di \textit{I/O
- multiplexing}, una nuova modalità di operazioni che consenta di tenere sotto
-controllo più file descriptor in contemporanea, permettendo di bloccare un
-processo quando le operazioni volute non sono possibili, e di riprenderne
-l'esecuzione una volta che almeno una di quelle richieste sia disponibile, in
-modo da poterla eseguire con la sicurezza di non restare bloccati.
-
-Dato che, come abbiamo già accennato, per i normali file su disco non si ha
-mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
-prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
-tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
-ulteriori dettagli e qualche esempio in sez.~\ref{sec:TCP_sock_multiplexing}.
-
-
-\subsection{Le funzioni \func{select} e \func{pselect}}
-\label{sec:file_select}
-
-Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O
- multiplexing} è stato BSD,\footnote{la funzione \func{select} è apparsa in
- BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che
- supportano i \textit{socket}\index{socket}, compreso le varianti di System
- V.} con la funzione \funcd{select}, il cui prototipo è:
-\begin{functions}
- \headdecl{sys/time.h}
- \headdecl{sys/types.h}
- \headdecl{unistd.h}
- \funcdecl{int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set
- *exceptfds, struct timeval *timeout)}
-
- Attende che uno dei file descriptor degli insiemi specificati diventi
- attivo.
-
- \bodydesc{La funzione in caso di successo restituisce il numero di file
- descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
- caso \var{errno} assumerà uno dei valori:
+capacità \const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può
+acquisire \textit{lease} su qualunque file.
+
+Se su un file è presente un \textit{lease} quando il \textit{lease breaker}
+esegue una \func{truncate} o una \func{open} che confligge con
+esso,\footnote{in realtà \func{truncate} confligge sempre, mentre \func{open},
+ se eseguita in sola lettura, non confligge se si tratta di un \textit{read
+ lease}.} la funzione si blocca (a meno di non avere aperto il file con
+\const{O\_NONBLOCK}, nel qual caso \func{open} fallirebbe con un errore di
+\errcode{EWOULDBLOCK}) e viene eseguita la notifica al \textit{lease holder},
+così che questo possa completare le sue operazioni sul file e rilasciare il
+\textit{lease}. In sostanza con un \textit{read lease} si rilevano i
+tentativi di accedere al file per modificarne i dati da parte di un altro
+processo, mentre con un \textit{write lease} si rilevano anche i tentativi di
+accesso in lettura. Si noti comunque che le operazioni di notifica avvengono
+solo in fase di apertura del file e non sulle singole operazioni di lettura e
+scrittura.
+
+L'utilizzo dei \textit{file lease} consente al \textit{lease holder} di
+assicurare la consistenza di un file, a seconda dei due casi, prima che un
+altro processo inizi con le sue operazioni di scrittura o di lettura su di
+esso. In genere un \textit{lease holder} che riceve una notifica deve
+provvedere a completare le necessarie operazioni (ad esempio scaricare
+eventuali buffer), per poi rilasciare il \textit{lease} così che il
+\textit{lease breaker} possa eseguire le sue operazioni. Questo si fa con il
+comando \const{F\_SETLEASE}, o rimuovendo il \textit{lease} con
+\const{F\_UNLCK}, o, nel caso di \textit{write lease} che confligge con una
+operazione di lettura, declassando il \textit{lease} a lettura con
+\const{F\_RDLCK}.
+
+Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
+il numero di secondi specificato dal parametro di sistema mantenuto in
+\sysctlfile{fs/lease-break-time} sarà il kernel stesso a rimuoverlo o
+declassarlo automaticamente (questa è una misura di sicurezza per evitare che
+un processo blocchi indefinitamente l'accesso ad un file acquisendo un
+\textit{lease}). Una volta che un \textit{lease} è stato rilasciato o
+declassato (che questo sia fatto dal \textit{lease holder} o dal kernel è lo
+stesso) le chiamate a \func{open} o \func{truncate} eseguite dal \textit{lease
+ breaker} rimaste bloccate proseguono automaticamente.
+
+Benché possa risultare utile per sincronizzare l'accesso ad uno stesso file da
+parte di più processi, l'uso dei \textit{file lease} non consente comunque di
+risolvere il problema di rilevare automaticamente quando un file o una
+directory vengono modificati,\footnote{questa funzionalità venne aggiunta
+ principalmente ad uso di Samba per poter facilitare l'emulazione del
+ comportamento di Windows sui file, ma ad oggi viene considerata una
+ interfaccia mal progettata ed il suo uso è fortemente sconsigliato a favore
+ di \textit{inotify}.} che è quanto necessario ad esempio ai programma di
+gestione dei file dei vari desktop grafici.
+
+\itindbeg{dnotify}
+
+Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
+un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia
+ specifica di Linux che deve essere evitata se si vogliono scrivere programmi
+ portabili, e che le funzionalità illustrate sono disponibili soltanto se è
+ stata definita la macro \macro{\_GNU\_SOURCE}.} chiamata \textit{dnotify},
+che consente di richiedere una notifica quando una directory, o uno qualunque
+dei file in essa contenuti, viene modificato. Come per i \textit{file lease}
+la notifica avviene di default attraverso il segnale \signal{SIGIO}, ma se ne
+può utilizzare un altro, e di nuovo, per le ragioni già esposte in precedenza,
+è opportuno che si utilizzino dei segnali \textit{real-time}. Inoltre, come
+in precedenza, si potrà ottenere nel gestore del segnale il file descriptor
+che è stato modificato tramite il contenuto della struttura
+\struct{siginfo\_t}.
+
+\itindend{file~lease}
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{DN\_ACCESS} & Un file è stato acceduto, con l'esecuzione di una fra
+ \func{read}, \func{pread}, \func{readv}.\\
+ \const{DN\_MODIFY} & Un file è stato modificato, con l'esecuzione di una
+ fra \func{write}, \func{pwrite}, \func{writev},
+ \func{truncate}, \func{ftruncate}.\\
+ \const{DN\_CREATE} & È stato creato un file nella directory, con
+ l'esecuzione di una fra \func{open}, \func{creat},
+ \func{mknod}, \func{mkdir}, \func{link},
+ \func{symlink}, \func{rename} (da un'altra
+ directory).\\
+ \const{DN\_DELETE} & È stato cancellato un file dalla directory con
+ l'esecuzione di una fra \func{unlink}, \func{rename}
+ (su un'altra directory), \func{rmdir}.\\
+ \const{DN\_RENAME} & È stato rinominato un file all'interno della
+ directory (con \func{rename}).\\
+ \const{DN\_ATTRIB} & È stato modificato un attributo di un file con
+ l'esecuzione di una fra \func{chown}, \func{chmod},
+ \func{utime}.\\
+ \const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
+ eventi.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti che identificano le varie classi di eventi per i quali
+ si richiede la notifica con il comando \const{F\_NOTIFY} di \func{fcntl}.}
+ \label{tab:file_notify}
+\end{table}
+
+Ci si può registrare per le notifiche dei cambiamenti al contenuto di una
+certa directory eseguendo la funzione \func{fcntl} su un file descriptor
+associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
+l'argomento \param{arg} di \func{fcntl} serve ad indicare per quali classi
+eventi si vuole ricevere la notifica, e prende come valore una maschera
+binaria composta dall'OR aritmetico di una o più delle costanti riportate in
+tab.~\ref{tab:file_notify}.
+
+A meno di non impostare in maniera esplicita una notifica permanente usando il
+valore \const{DN\_MULTISHOT}, la notifica è singola: viene cioè inviata una
+sola volta quando si verifica uno qualunque fra gli eventi per i quali la si è
+richiesta. Questo significa che un programma deve registrarsi un'altra volta
+se desidera essere notificato di ulteriori cambiamenti. Se si eseguono diverse
+chiamate con \const{F\_NOTIFY} e con valori diversi per \param{arg} questi
+ultimi si \textsl{accumulano}; cioè eventuali nuovi classi di eventi
+specificate in chiamate successive vengono aggiunte a quelle già impostate
+nelle precedenti. Se si vuole rimuovere la notifica si deve invece
+specificare un valore nullo.
+
+\itindbeg{inotify}
+
+Il maggiore problema di \textit{dnotify} è quello della scalabilità: si deve
+usare un file descriptor per ciascuna directory che si vuole tenere sotto
+controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
+quando la directory che si controlla è all'interno di un dispositivo
+rimovibile, mantenere il relativo file descriptor aperto comporta
+l'impossibilità di smontare il dispositivo e di rimuoverlo, il che in genere
+complica notevolmente la gestione dell'uso di questi dispositivi.
+
+Un altro problema è che l'interfaccia di \textit{dnotify} consente solo di
+tenere sotto controllo il contenuto di una directory; la modifica di un file
+viene segnalata, ma poi è necessario verificare di quale file si tratta
+(operazione che può essere molto onerosa quando una directory contiene un gran
+numero di file). Infine l'uso dei segnali come interfaccia di notifica
+comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
+sez.~\ref{sec:sig_adv_control}. Per tutta questa serie di motivi in generale
+quella di \textit{dnotify} viene considerata una interfaccia di usabilità
+problematica ed il suo uso oggi è fortemente sconsigliato.
+
+\itindend{dnotify}
+
+Per risolvere i problemi appena illustrati è stata introdotta una nuova
+interfaccia per l'osservazione delle modifiche a file o directory, chiamata
+\textit{inotify}.\footnote{l'interfaccia è disponibile a partire dal kernel
+ 2.6.13, le relative funzioni sono state introdotte nelle glibc 2.4.} Anche
+questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
+si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
+notifica degli eventi associata ad un singolo file descriptor, il che permette
+di risolvere il principale problema di \itindex{dnotify} \textit{dnotify}. La
+coda viene creata attraverso la funzione di sistema \funcd{inotify\_init}, il
+cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_init(void)}
+\fdesc{Inizializza una istanza di \textit{inotify}.}
+}
+
+{La funzione ritornaun file descriptor in caso di successo, o $-1$ in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori: