X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=fileadv.tex;h=c3936d97da12142e0f7921257dded96b8d3a2dbb;hb=4c8d31d106d4ae2b75557dfbd6ab3e96b926074c;hp=ea2eb4b78288e0f6cf21442885dcd864f8499050;hpb=e6ca5b03eaf1e9ef82eb75f722487efe97abaf88;p=gapil.git diff --git a/fileadv.tex b/fileadv.tex index ea2eb4b..c3936d9 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -305,7 +305,7 @@ contestualmente all'esecuzione della funzione,\footnote{in Linux per kernel 2.6.16, non era presente la relativa system call, e la funzione era implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man select\_tut}) per cui la possibilità di \itindex{race~condition} - \textit{race condition} permaneva; in tale situzione si può ricorrere ad una + \textit{race condition} permaneva; in tale situazione si può ricorrere ad una soluzione alternativa, chiamata \itindex{self-pipe trick} \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della stessa; si può indicare @@ -543,7 +543,7 @@ accesso ai file; per questo motivo Stevens chiama questa modalit In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select} che, quando vengono usate con un numero molto grande di file descriptor, non -hanno buone prestazioni. % aggiungere cenno a epoll quando l'avrò scritta +hanno buone prestazioni. % TODO aggiungere cenno a epoll quando l'avrò scritta In tal caso infatti la maggior parte del loro tempo di esecuzione è impegnato ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo per determinare quali di essi (in genere una piccola @@ -555,13 +555,15 @@ file descriptor sono pi segnale. Inoltre dato che i segnali normali non si accodano (si ricordi quanto illustrato in sez.~\ref{sec:sig_notification}), in presenza di più file descriptor attivi contemporaneamente, più segnali emessi nello stesso momento -verrebbero notificati una volta sola. Linux però supporta le estensioni -POSIX.1b dei segnali real-time, che vengono accodati e che permettono di -riconoscere il file descriptor che li ha emessi. In questo caso infatti si può -fare ricorso alle informazioni aggiuntive restituite attraverso la struttura -\struct{siginfo\_t}, utilizzando la forma estesa \var{sa\_sigaction} del -gestore installata con il flag \const{SA\_SIGINFO} (si riveda quanto -illustrato in sez.~\ref{sec:sig_sigaction}). +verrebbero notificati una volta sola. + +Linux però supporta le estensioni POSIX.1b dei segnali real-time, che vengono +accodati e che permettono di riconoscere il file descriptor che li ha emessi. +In questo caso infatti si può fare ricorso alle informazioni aggiuntive +restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma +estesa \var{sa\_sigaction} del gestore installata con il flag +\const{SA\_SIGINFO} (si riveda quanto illustrato in +sez.~\ref{sec:sig_sigaction}). Per far questo però occorre utilizzare le funzionalità dei segnali real-time (vedi sez.~\ref{sec:sig_real_time}) impostando esplicitamente con il comando @@ -581,11 +583,13 @@ risposta a seconda del segnale usato, dato che i segnali real-time supportano anche questa funzionalità. In questo modo si può identificare immediatamente un file su cui l'accesso è diventato possibile evitando completamente l'uso di funzioni come \func{poll} e \func{select}, almeno fintanto che non si satura -la coda. Se infatti si eccedono le dimensioni di quest'ultima, il kernel, non -potendo più assicurare il comportamento corretto per un segnale real-time, -invierà al suo posto un solo \const{SIGIO}, su cui si saranno accumulati tutti -i segnali in eccesso, e si dovrà allora determinare con un ciclo quali sono i -file diventati attivi. +la coda. + +Se infatti si eccedono le dimensioni di quest'ultima, il kernel, non potendo +più assicurare il comportamento corretto per un segnale real-time, invierà al +suo posto un solo \const{SIGIO}, su cui si saranno accumulati tutti i segnali +in eccesso, e si dovrà allora determinare con un ciclo quali sono i file +diventati attivi. % TODO fare esempio che usa O_ASYNC @@ -626,11 +630,11 @@ soluzione disponibile con l'interfaccia tradizionale, che Queste nuove funzionalità sono delle estensioni specifiche, non standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel -supportano meccanismi simili). Esse sono realizzate, e solo a partire dalla -versione 2.4 del kernel, attraverso l'uso di alcuni \textsl{comandi} -aggiuntivi per la funzione \func{fcntl} (vedi sez.~\ref{sec:file_fcntl}), che -divengono disponibili soltanto se si è definita la macro \macro{\_GNU\_SOURCE} -prima di includere \file{fcntl.h}. +supportano meccanismi simili). Alcune di esse sono realizzate, e solo a +partire dalla versione 2.4 del kernel, attraverso l'uso di alcuni +\textsl{comandi} aggiuntivi per la funzione \func{fcntl} (vedi +sez.~\ref{sec:file_fcntl}), che divengono disponibili soltanto se si è +definita la macro \macro{\_GNU\_SOURCE} prima di includere \file{fcntl.h}. \index{file!lease|(} @@ -699,7 +703,8 @@ su un file, e che un \textit{lease} pu può ottenere un \textit{lease} soltanto per un file appartenente ad un \acr{uid} corrispondente a quello del processo. Soltanto un processo con privilegi di amministratore (cioè con la \itindex{capabilities} capability -\const{CAP\_LEASE}) può acquisire \textit{lease} su qualunque file. +\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 @@ -743,28 +748,20 @@ kernel 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 viene -modificato, che è quanto necessario ad esempio ai programma di gestione dei -file dei vari desktop grafici. +risolvere il problema di rilevare automaticamente quando un file o una +directory vengono modificati, che è quanto necessario ad esempio ai programma +di gestione dei file dei vari desktop grafici. Per risolvere questo problema è stata allora creata un'altra interfaccia, chiamata \textit{dnotify}, che consente di richiedere una notifica quando una directory, o di uno qualunque dei file in essa contenuti, viene modificato. Come per i \textit{file lease} la notifica avviene di default attraverso il -segnale \const{SIGIO}, ma questo può essere modificato e si può ottenere nel -gestore il file descriptor che è stato modificato dal contenuto della -struttura \struct{siginfo\_t}. +segnale \const{SIGIO}, ma se ne può utilizzare un altro. Inoltre si potrà +ottenere nel gestore del segnale il file descriptor che è stato modificato +tramite il contenuto della struttura \struct{siginfo\_t}. \index{file!lease|)} -Ci si può registrare per le notifiche dei cambiamenti al contenuto di una -certa directory eseguendo \func{fcntl} su un file descriptor \param{fd} -associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso -l'argomento \param{arg} 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}. - \begin{table}[htb] \centering \footnotesize @@ -800,23 +797,226 @@ tab.~\ref{tab:file_notify}. \label{tab:file_notify} \end{table} -A meno di non impostare in maniera esplicita una notifica permanente usando -\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 +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. + +\index{file!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 un eccesso di file aperti. Inoltre +quando la directory è su un dispositivo rimuovibile, mantenere un file +descriptor aperto comporta l'impossibilità di smontare il dispositivo e +rimuoverlo, complicando la gestione. + +Un secondo problema è che l'interfaccia consente solo di tenere sotto +controllo il contenuto di una directory; la modifica di un file viene +segnalata, ma poi devo verificare quale è. 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_control}, e per questo in +generale quella di \textit{dnotify} viene considerata una interfaccia di +usabilità problematica. + \index{file!dnotify|)} +Per questa serie di motivi, a partire dal kernel 2.6.13, è stata introdotta +una nuova interfaccia per l'osservazione delle modifiche a file o directory, +chiamata \textit{inotify}.\footnote{le corrispondenti funzioni di interfaccia + sono state introdotte nelle glibc 2.4.} 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, risolvendo così il principale +problema di \itindex{dnotify} \textit{dnotify}. La coda viene creata +attraverso la funzione \funcd{inotify\_init}, il cui prototipo è: +\begin{prototype}{sys/inotify.h} + {int inotify\_init(void)} + + Inizializza una istanza di \textit{inotify}. + + \bodydesc{La funzione restituisce un file descriptor in caso di successo, o + $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EMFILE}] si è raggiunto il numero massimo di istanze di + \textit{inotify} consentite all'utente. + \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti + nel sistema. + \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare + l'istanza. + \end{errlist} +} +\end{prototype} + +La funzione non prende alcun argomento, e restituisce un file descriptor +associato alla coda, attraverso il quale verranno effettuate le operazioni di +notifica. Si tratta di un file descriptor speciale, che non è associato a +nessun file, ma che viene utilizzato per notificare gli eventi che si sono +posti in osservazione all'applicazione che usa l'interfaccia di +\textit{inotify}. Dato che questo file descriptor non è associato a nessun +file o directory, questo consente di evitare l'inconveniente di non poter +smontare un filesystem i cui file sono tenuti sotto osservazione.\footnote{ed + una delle caratteristiche dell'interfaccia di \textit{inotify} è proprio + quella di notificare il fatto che il filesystem su cui si trova il file o la + directory osservata è stato smontato.} + +Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà +essere utilizzato come argomento per le funzioni \func{select} e \func{poll}, +e siccome gli eventi vengono notificati come dati disponibili in lettura sul +file descriptor, dette funzioni ritorneranno tutte le volte che si avrà un +evento di notifica. Così, invece di dover utilizzare i segnali, si potrà +gestire l'osservazione delle modifiche con l'\textit{I/O multiplexing}, +utilizzando secondo le modalità illustrate in +sez.~\ref{sec:file_multiplexing}. + +Infine l'interfaccia di \textit{inotify} consente di mettere sotto +osservazione sia singoli file, che intere directory; in quest'ultimo caso +l'interfaccia restituirà informazioni sia riguardo alla directory che ai file +che essa contiene. Una volta creata la coda di notifica si devono definire +gli eventi da tenere sotto osservazione; questo viene fatto tramite una +\textsl{lista di osservazione} (o \textit{watch list}) associata alla coda. +Per gestire la lista di osservazione l'interfaccia fornisce due funzioni, la +prima di queste è \funcd{inotify\_add\_watch}, il cui prototipo è: +\begin{prototype}{sys/inotify.h} + {int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)} + + Aggiunge un evento di osservazione alla lista di osservazione di \param{fd}. + + \bodydesc{La funzione restituisce un valore positivo in caso di successo, o + $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato. + \item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd} + non è un filesystem di \textit{inotify}. + \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di + osservazione o il kernel non ha potuto allocare una risorsa necessaria. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF}.} +\end{prototype} + +La funzione consente di creare un \textsl{evento di osservazione} (un +cosiddetto ``\textit{watch}'') nella lista di una coda di notifica, indicata +specificando il file descriptor ad essa associato nell'argomento \param{fd}. +Il file o la directory da porre sotto osservazione viene invece indicato per +nome, che viene passato nell'argomento \param{pathname}. Infine il terzo +argomento, \param{mask}, indica che tipo di eventi devono essere tenuti sotto +osservazione. Questo deve essere specificato come maschera binaria combinando +i valori delle costanti riportate in tab.~\ref{tab:inotify_event_watch}. In +essa si sono marcati con un ``$\bullet$'' gli eventi che, quando specificati +per una directory, vengono osservati anche su tutti i file che essa contiene. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|p{10cm}|} + \hline + \textbf{Valore} & & \textbf{Significato} \\ + \hline + \hline + \const{IN\_ACCESS} &$\bullet$& c'è stato accesso al file in + lettura.\\ + \const{IN\_ATTRIB} &$\bullet$& ci sono stati cambiamenti sui dati + dell'inode.\\ + \const{IN\_CLOSE\_WRITE} &$\bullet$& è stato chiuso un file aperto in + scrittura.\\ + \const{IN\_CLOSE\_NOWRITE}&$\bullet$& è stato chiuso un file aperto in + sola lettura.\\ + \const{IN\_CREATE} &$\bullet$& è stato creato un file o una + directory in una directory sotto + osservazione.\\ + \const{IN\_DELETE} &$\bullet$& è stato cancellato un file o una + directory in una directory sotto + osservazione.\\ + \const{IN\_DELETE\_SELF} & & è stato cancellato il file (o la + directory) sotto osservazione.\\ + \const{IN\_MODIFY} &$\bullet$& è stato modificato il file.\\ + \const{IN\_MOVE\_SELF} & & è stato rinominato il file (o la + directory) sotto osservazione.\\ + \const{IN\_MOVED\_FROM} &$\bullet$& un file è stato spostato fuori dalla + directory sotto osservazione.\\ + \const{IN\_MOVED\_TO} &$\bullet$& un file è stato spostato nella + directory sotto osservazione.\\ + \const{IN\_OPEN} &$\bullet$& un file è stato aperto.\\ + \hline + \end{tabular} + \caption{Le costanti che identificano i valori per la maschera binaria + dell'argomento \param{mask} di \func{inotify\_add\_watch}.} + \label{tab:inotify_event_watch} +\end{table} + +Se non esiste nessun \textit{watch} per il file (o la directory) specificata +questo verrà creato per gli eventi specificati dall'argomento \param{mask}, +altrimenti la funzione sovrascriverà le impostazioni precedenti. In caso di +successo la funzione ritorna un intero positivo, detto \textit{watch + descriptor} che identifica univocamente l'evento di osservazione. Questo +valore è importante perché è soltanto con esso che si può rimuovere un evento +di osservazione, usando la seconda funzione dell'interfaccia di gestione, +\funcd{inotify\_rm\_watch}, il cui prototipo è: +\begin{prototype}{sys/inotify.h} + {int inotify\_rm\_watch(int fd, uint32\_t wd)} + + Rimuove un evento di osservazione. + + \bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di + errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EBADF}] non si è specificato in \param{fd} un file descriptor + valido. + \item[\errcode{EINVAL}] il valore di \param{wd} non è corretto, o \param{fd} + non è associato ad una coda di notifica. + \end{errlist} +} +\end{prototype} + +Oltre che per la rimozione, il \textit{watch descriptor} viene usato anche per +identificare l'evento a cui si fa riferimento nella lista dei risultati +restituiti da \textit{inotify} + + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includestruct{listati/inotify_event.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{inotify\_event}.} + \label{fig:inotify_event} +\end{figure} + + +Inoltre l'interfaccia di \textit{inotify} permette di conoscere, come avviene +per i file descriptor associati ai socket (si veda al proposito quanto +trattato in sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in +lettura sul nostro file descriptor, utilizzando su di esso l'operazione +\const{FIONREAD} con \func{ioctl}.\footnote{questa è una delle operazioni + speciali (che abbiamo visto in sez.~\ref{sec:file_ioctl}) che nel caso è + disponibile solo per i socket e per i file descriptor creati con + \func{inotify\_init}.} Questo consente anche di ottenere rapidamente il +numero di file che sono cambiati. + -\index{file!inotify|)} % TODO inserire anche inotify, vedi http://www.linuxjournal.com/article/8478 -\index{file!inotify|(} +% TODO e man inotify + +\index{file!inotify|)} + + + @@ -2796,7 +2996,10 @@ possibilit % LocalWords: flock shared exclusive operation dup inode linked NFS cmd ENOLCK % LocalWords: EDEADLK whence SEEK CUR type pid GETLK SETLK SETLKW all'inode HP % LocalWords: switch bsd lockf mandatory SVr sgid group root mount mand TRUNC -% LocalWords: SVID UX Documentation sendfile dnotify inotify NdA +% LocalWords: SVID UX Documentation sendfile dnotify inotify NdA ppoll fds add +% LocalWords: init EMFILE FIONREAD ioctl watch char pathname uint mask ENOSPC +% LocalWords: dell'inode CLOSE NOWRITE MOVE MOVED FROM TO rm wd event page +% LocalWords: attribute Universe %%% Local Variables: