X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=38bd320f168b551fed88b316b62baf50e2f81272;hp=97249198be36d745d604947117032ff1c642b114;hb=50b469ec4e7bba4d52eaaa51edd77b18967079c2;hpb=840a5e76c710247e4ce8f0fff74acf30dca2425b diff --git a/fileadv.tex b/fileadv.tex index 9724919..38bd320 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1,6 +1,6 @@ %% fileadv.tex %% -%% Copyright (C) 2000-2009 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2010 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", @@ -2076,7 +2076,7 @@ kernel \textit{lease breaker} rimaste bloccate proseguono automaticamente. -\index{file!dnotify|(} +\itindbeg{dnotify} 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 @@ -2154,7 +2154,7 @@ specificate in chiamate successive vengono aggiunte a quelle gi nelle precedenti. Se si vuole rimuovere la notifica si deve invece specificare un valore nullo. -\index{file!inotify|(} +\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 @@ -2174,7 +2174,7 @@ 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. -\index{file!dnotify|)} +\itindend{dnotify} Per risolvere i problemi appena illustrati è stata introdotta una nuova interfaccia per l'osservazione delle modifiche a file o directory, chiamata @@ -2656,7 +2656,7 @@ verificano pi dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono raggruppati in un solo evento. -\index{file!inotify|)} +\itindend{inotify} % TODO trattare fanotify, vedi http://lwn.net/Articles/339399/ e % http://lwn.net/Articles/343346/ @@ -2736,17 +2736,6 @@ come vedremo, permette di eseguire con una sola chiamata una serie di operazioni, usando un vettore di \textit{control block}. Tramite questo campo si specifica quale è la natura di ciascuna di esse. -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \includestruct{listati/sigevent.h} - \end{minipage} - \normalsize - \caption{La struttura \structd{sigevent}, usata per specificare le modalità - di notifica degli eventi relativi alle operazioni di I/O asincrono.} - \label{fig:file_sigevent} -\end{figure} - Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent} che serve a specificare il modo in cui si vuole che venga effettuata la notifica del completamento delle operazioni richieste. La struttura è @@ -3927,7 +3916,7 @@ dell'ulteriore argomento il comportamento delle funzioni precedenti \func{readv} e \func{writev}. Con l'uso di queste funzioni si possono evitare eventuali -\itindex{race~condition} \textit{race conditions} quando si deve eseguire la +\itindex{race~condition} \textit{race condition} quando si deve eseguire la una operazione di lettura e scrittura vettorizzata a partire da una certa posizione su un file, mentre al contempo si possono avere in concorrenza processi che utilizzano lo stesso file descriptor (si ricordi quanto visto in @@ -4315,17 +4304,17 @@ anche se un valore nullo avrebbe dato gli stessi risultati, l'uso di questi flag, che si ricordi servono solo a dare suggerimenti al kernel, permette in genere di migliorare le prestazioni. -Come accennato con l'introduzione di \func{splice} sono state realizzate altre -due system call, \func{vmsplice} e \func{tee}, che utilizzano la stessa -infrastruttura e si basano sullo stesso concetto di manipolazione e +Come accennato con l'introduzione di \func{splice} sono state realizzate anche +altre due \textit{system call}, \func{vmsplice} e \func{tee}, che utilizzano +la stessa infrastruttura e si basano sullo stesso concetto di manipolazione e trasferimento di dati attraverso un buffer in kernel space; benché queste non attengono strettamente ad operazioni di trasferimento dati fra file -descriptor, le tratteremo qui. +descriptor, le tratteremo qui, essendo strettamente correlate fra loro. La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come -indica il suo nome consente di trasferire i dati dalla memoria di un processo -(ad esempio per un file mappato in memoria) verso una \textit{pipe}, il suo -prototipo è: +indica il suo nome consente di trasferire i dati dalla memoria virtuale di un +processo (ad esempio per un file mappato in memoria) verso una \textit{pipe}; +il suo prototipo è: \begin{functions} \headdecl{fcntl.h} \headdecl{sys/uio.h} @@ -4351,24 +4340,25 @@ prototipo La \textit{pipe} indicata da \param{fd} dovrà essere specificata tramite il file descriptor corrispondente al suo capo aperto in scrittura (di nuovo si -faccia riferimento a sez.~\ref{sec:ipc_unix}), mentre per indicare quali zone -di memoria devono essere trasferita si dovrà utilizzare un vettore di -strutture \struct{iovec} (vedi fig.~\ref{fig:file_iovec}), esattamente con gli -stessi criteri con cui le si usano per l'I/O vettorizzato, indicando gli -indirizzi e le dimensioni di ciascun segmento di memoria su cui si vuole -operare; le dimensioni del suddetto vettore devono essere passate -nell'argomento \param{nr\_segs} che indica il numero di segmenti di memoria da -trasferire. Sia per il vettore che per il valore massimo di \param{nr\_segs} -valgono le stesse limitazioni illustrate in sez.~\ref{sec:file_multiple_io}. +faccia riferimento a sez.~\ref{sec:ipc_unix}), mentre per indicare quali +segmenti della memoria del processo devono essere trasferiti verso di essa si +dovrà utilizzare un vettore di strutture \struct{iovec} (vedi +fig.~\ref{fig:file_iovec}), esattamente con gli stessi criteri con cui le si +usano per l'I/O vettorizzato, indicando gli indirizzi e le dimensioni di +ciascun segmento di memoria su cui si vuole operare; le dimensioni del +suddetto vettore devono essere passate nell'argomento \param{nr\_segs} che +indica il numero di segmenti di memoria da trasferire. Sia per il vettore che +per il valore massimo di \param{nr\_segs} valgono le stesse limitazioni +illustrate in sez.~\ref{sec:file_multiple_io}. In caso di successo la funzione ritorna il numero di byte trasferiti sulla \textit{pipe}. In generale, se i dati una volta creati non devono essere riutilizzati (se cioè l'applicazione che chiama \func{vmsplice} non modificherà più la memoria trasferita), è opportuno utilizzare per \param{flag} il valore \const{SPLICE\_F\_GIFT}; questo fa sì che il kernel -possa rimuovere le relative pagine dallo spazio degli indirizzi del processo, -e scaricarle nella cache, così che queste possono essere utilizzate -immediatamente senza necessità di eseguire una copia dei dati che contengono. +possa rimuovere le relative pagine dalla cache della memoria virtuale, così +che queste possono essere utilizzate immediatamente senza necessità di +eseguire una copia dei dati che contengono. La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il suo nome all'omonimo comando in user space, perché in analogia con questo @@ -4403,7 +4393,12 @@ sorgente e \param{fd\_out} il capo in scrittura della \textit{pipe} destinazione; a differenza di quanto avviene con \func{read} i dati letti con \func{tee} da \func{fd\_in} non vengono \textsl{consumati} e restano disponibili sulla \textit{pipe} per una successiva lettura (di nuovo per il -comportamento delle \textit{pipe} si veda sez.~\ref{sec:ipc_unix}). +comportamento delle \textit{pipe} si veda sez.~\ref{sec:ipc_unix}). Al +momento\footnote{quello della stesura di questo paragrafo, avvenuta il Gennaio + 2010, in futuro potrebbe essere implementato anche \const{SPLICE\_F\_MORE}.} +il solo valore utilizzabile per \param{flag}, fra quelli elencati in +tab.~\ref{tab:splice_flag}, è \const{SPLICE\_F\_NONBLOCK} che rende la +funzione non bloccante. La funzione restituisce il numero di byte copiati da una \textit{pipe} all'altra (o $-1$ in caso di errore), un valore nullo indica che non ci sono @@ -4521,35 +4516,37 @@ La funzione richiede che venga letto in anticipo il contenuto del file \index{memoria~virtuale} memoria virtuale ed il meccanismo della \index{paginazione} paginazione per cui la lettura viene eseguita in blocchi corrispondenti alle dimensioni delle pagine di memoria, ed i valori di -\param{offset} e \param{count} arrotondati di conseguenza. +\param{offset} e \param{count} vengono arrotondati di conseguenza. La funzione estende quello che è un comportamento normale del kernel che quando si legge un file, aspettandosi che l'accesso prosegua, esegue sempre una lettura preventiva di una certa quantità di dati; questo meccanismo di lettura anticipata viene chiamato \textit{read-ahead}, da cui deriva il nome -della funzione. La funzione, per ottimizzare gli accessi a disco, effettua la -lettura in cache della sezione richiesta e si blocca fintanto che questa non -viene completata. La posizione corrente sul file non viene modificata ed -indipendentemente da quanto indicato con \param{count} la lettura dei dati si -interrompe una volta raggiunta la fine del file. +della funzione. La funzione \func{readahead}, per ottimizzare gli accessi a +disco, effettua la lettura in cache della sezione richiesta e si blocca +fintanto che questa non viene completata. La posizione corrente sul file non +viene modificata ed indipendentemente da quanto indicato con \param{count} la +lettura dei dati si interrompe una volta raggiunta la fine del file. Si può utilizzare questa funzione per velocizzare le operazioni di lettura -all'interno del programma tutte le volte che si conosce in anticipo quanti -dati saranno necessari in seguito. Si potrà così concentrare in un unico -momento (ad esempio in fase di inizializzazione) la lettura, così da ottenere -una migliore risposta nelle operazioni successive. +all'interno di un programma tutte le volte che si conosce in anticipo quanti +dati saranno necessari nelle elaborazioni successive. Si potrà così +concentrare in un unico momento (ad esempio in fase di inizializzazione) la +lettura dei dati da disco, così da ottenere una migliore velocità di risposta +nelle operazioni successive. \itindend{read-ahead} Il concetto di \func{readahead} viene generalizzato nello standard -POSIX.1-2001 dalla funzione \funcd{posix\_fadvise},\footnote{anche se +POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se l'argomento \param{len} è stato modificato da \ctyp{size\_t} a \ctyp{off\_t} nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il kernel sulle modalità con cui si intende accedere nel futuro ad una certa porzione di un file,\footnote{la funzione però è stata introdotta su Linux solo a partire dal kernel 2.5.60.} così che esso possa provvedere le -opportune ottimizzazioni; il suo prototipo, che può è disponibile solo se si -definisce la macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è: +opportune ottimizzazioni; il prototipo di \funcd{posix\_fadvise}, che è +disponibile soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad +valore di almeno 600, è: \begin{functions} \headdecl{fcntl.h} @@ -4617,18 +4614,18 @@ che utilizza semplicemente l'informazione. Come \func{madvise} anche \func{posix\_fadvise} si appoggia al sistema della memoria virtuale ed al meccanismo standard del \textit{read-ahead} utilizzato -dal kernel; in particolare con \const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la -dimensione dell'ammontare di dati letti preventivamente rispetto al default, -aspettandosi appunto una lettura sequenziale che li utilizzerà, mentre con -\const{POSIX\_FADV\_RANDOM} si disabilita del tutto il suddetto meccanismo, -dato che con un accesso del tutto casuale è inutile mettersi a leggere i dati -immediatamente successivi gli attuali; infine l'uso di -\const{POSIX\_FADV\_NORMAL} consente di riportarsi al comportamento di -default. +dal kernel; in particolare utilizzando il valore +\const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione dell'ammontare di +dati letti preventivamente rispetto al default, aspettandosi appunto una +lettura sequenziale che li utilizzerà, mentre con \const{POSIX\_FADV\_RANDOM} +si disabilita del tutto il suddetto meccanismo, dato che con un accesso del +tutto casuale è inutile mettersi a leggere i dati immediatamente successivi +gli attuali; infine l'uso di \const{POSIX\_FADV\_NORMAL} consente di +riportarsi al comportamento di default. Le due modalità \const{POSIX\_FADV\_NOREUSE} e \const{POSIX\_FADV\_WILLNEED} fino al kernel 2.6.18 erano equivalenti, a partire da questo kernel la prima -viene non ha più alcune effetto, mentre la seconda dà inizio ad una lettura in +viene non ha più alcun effetto, mentre la seconda dà inizio ad una lettura in cache della regione del file indicata. La quantità di dati che verranno letti è ovviamente limitata in base al carico che si viene a creare sul sistema della memoria virtuale, ma in genere una lettura di qualche megabyte viene @@ -4647,11 +4644,12 @@ nuovi dati utili.\footnote{la pagina di manuale riporta l'esempio dello Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione -specifica per le operazioni di scrittura, \func{posix\_fallocate},\footnote{la - funzione è stata introdotta a partire dalle glibc 2.1.94.} che consente di -preallocare dello spazio disco per assicurarsi che una seguente scrittura non -fallisca, il suo prototipo, anch'esso disponibile solo se si definisce la -macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è: +specifica per le operazioni di scrittura, +\funcd{posix\_fallocate},\footnote{la funzione è stata introdotta a partire + dalle glibc 2.1.94.} che consente di preallocare dello spazio disco per +assicurarsi che una seguente scrittura non fallisca, il suo prototipo, +anch'esso disponibile solo se si definisce la macro \macro{\_XOPEN\_SOURCE} ad +almeno 600, è: \begin{functions} \headdecl{fcntl.h} @@ -4678,35 +4676,58 @@ macro \macro{\_XOPEN\_SOURCE} ad almeno 600, } \end{functions} -La funzione si assicura che venga allocato sufficiente spazio disco perché sia +La funzione assicura che venga allocato sufficiente spazio disco perché sia possibile scrivere sul file indicato dall'argomento \param{fd} nella regione che inizia dalla posizione \param{offset} e si estende per \param{len} byte; -se questa si estende oltre la fine del file le dimensioni di quest'ultimo -saranno incrementate di conseguenza. Dopo aver eseguito con successo la -funzione è garantito che una scrittura nella regione indicata non fallirà per -mancanza di spazio disco. - -% TODO controllare la trattazione della nuova funzionalità di preallocazione - -% TODO documentare \func{posix\_fadvise} -% vedi http://insights.oetiker.ch/linux/fadvise.html -% questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html - -% TODO documentare \func{fallocate}, introdotta con il 2.6.23 -% vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/ -% http://kernelnewbies.org/Linux_2_6_23 -% \func{fallocate} con il 2.6.25 supporta pure XFS - -Infine a partire dal kernel 2.6.23 è stata introdotta la nuova system call -\funcd{fallocate}, che consente di realizzare direttamente all'interno del -kernel le funzionalità di \func{posix\_fallocate}. Trattandosi di una funzione -di servizio questa non è stata definita come funzione di libreria e pertanto -può essere invocata indirettamente con l'ausilio di \func{syscall} (vedi -sez.~\ref{sec:intro_syscall}; il suo prototipo è: - +se questa regione si estende oltre la fine del file le dimensioni di +quest'ultimo saranno incrementate di conseguenza. Dopo aver eseguito con +successo la funzione è garantito che una successiva scrittura nella regione +indicata non fallirà per mancanza di spazio disco. La funzione non ha nessun +effetto né sul contenuto, né sulla posizione corrente del file. + +Ci si può chiedere a cosa possa servire una funzione come +\func{posix\_fallocate} dato che è sempre possibile ottenere l'effetto voluto +eseguendo esplicitamente sul file la scrittura\footnote{usando \funcd{pwrite} + per evitare spostamenti della posizione corrente sul file.} di una serie di +zeri per l'estensione di spazio necessaria qualora il \itindex{sparse~file} +file debba essere esteso o abbia dei \index{file!\textit{hole}} +buchi.\footnote{si ricordi che occorre scrivere per avere l'allocazione e che + l'uso di \func{truncate} per estendere un file creerebbe soltanto uno + \itindex{sparse~file} \textit{sparse file} (vedi sez.~\ref{sec:file_lseek}) + senza una effettiva allocazione dello spazio disco.} In realtà questa è la +modalità con cui la funzione veniva realizzata nella prima versione fornita +dalle \acr{glibc}, per cui la funzione costituiva in sostanza soltanto una +standardizzazione delle modalità di esecuzione di questo tipo di allocazioni. + +Questo metodo, anche se funzionante, comporta però l'effettiva esecuzione una +scrittura su tutto lo spazio disco necessario, da fare al momento della +richiesta di allocazione, pagandone il conseguente prezzo in termini di +prestazioni; il tutto quando in realtà servirebbe solo poter riservare lo +spazio per poi andarci a scrivere, una sola volta, quando il contenuto finale +diventa effettivamente disponibile. + +Per poter fare tutto questo è però necessario il supporto da parte del kernel, +e questo è divenuto disponibile solo a partire dal kernel 2.6.23 in cui è +stata introdotta la nuova \textit{system call} \func{fallocate},\footnote{non + è detto che la funzione sia disponibile per tutti i filesystem, ad esempio + per XFS il supporto è stato introdotto solo a partire dal kernel 2.6.25.} +che consente di realizzare direttamente all'interno del kernel l'allocazione +dello spazio disco così da poter realizzare una versione di +\func{posix\_fallocate} con prestazioni molto più elevate.\footnote{nelle + \acr{glibc} la nuova \textit{system call} viene sfruttata per la + realizzazione di \func{posix\_fallocate} a partire dalla versione 2.10.} + +Trattandosi di una funzione di servizio, ed ovviamente disponibile +esclusivamente su Linux, inizialmente \funcd{fallocate} non era stata definita +come funzione di libreria,\footnote{pertanto poteva essere invocata soltanto + in maniera indiretta con l'ausilio di \func{syscall}, vedi + sez.~\ref{sec:intro_syscall}, come \code{long fallocate(int fd, int mode, + loff\_t offset, loff\_t len)}.} ma a partire dalle \acr{glibc} 2.10 è + stato fornito un supporto esplicito; il suo prototipo è: \begin{functions} - \headdecl{linux/falloc.h} - \funcdecl{long fallocate(int fd, int mode, loff\_t offset, loff\_t len)} + \headdecl{linux/fcntl.h} + + \funcdecl{int fallocate(int fd, int mode, off\_t offset, off\_t len)} Prealloca dello spazio disco per un file. @@ -4731,6 +4752,25 @@ sez.~\ref{sec:intro_syscall}; il suo prototipo } \end{functions} +La funzione prende gli stessi argomenti di \func{posix\_fallocate} con lo +stesso significato, a cui si aggiunge l'argomento \param{mode} che indica le +modalità di allocazione; al momento quest'ultimo può soltanto essere nullo o +assumere il valore \const{FALLOC\_FL\_KEEP\_SIZE} che richiede che la +dimensione del file\footnote{quella ottenuta nel campo \var{st\_size} di una + struttura \struct{stat} dopo una chiamata a \texttt{fstat}.} non venga +modificata anche quando la somma di \param{offset} e \param{len} eccede la +dimensione corrente. + +Se \param{mode} è nullo invece la dimensione totale del file in caso di +estensione dello stesso viene aggiornata, come richiesto per +\func{posix\_fallocate}, ed invocata in questo modo si può considerare +\func{fallocate} come l'implementazione ottimale di \func{posix\_fallocate} a +livello di kernel. + +% vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/ +% http://kernelnewbies.org/Linux_2_6_23 + + %\subsection{L'utilizzo delle porte di I/O} @@ -4770,7 +4810,7 @@ sez.~\ref{sec:intro_syscall}; il suo prototipo % LocalWords: only ETXTBSY DENYWRITE ENODEV filesystem EPERM EXEC noexec table % LocalWords: ENFILE lenght segment violation SIGSEGV FIXED msync munmap copy % LocalWords: DoS Denial Service EXECUTABLE NORESERVE LOCKED swapping stack fs -% LocalWords: GROWSDOWN ANON GiB POPULATE prefaulting SIGBUS fifo VME fork old +% LocalWords: GROWSDOWN ANON POPULATE prefaulting SIGBUS fifo VME fork old % LocalWords: exec atime ctime mtime mprotect addr EACCESS mremap address new % LocalWords: long MAYMOVE realloc VMA virtual Ingo Molnar remap pages pgoff % LocalWords: dall' fault cache linker prelink advisory discrectionary lock fl @@ -4792,7 +4832,8 @@ sez.~\ref{sec:intro_syscall}; il suo prototipo % LocalWords: nwrite segs patch readahead posix fadvise TC advice FADV NORMAL % LocalWords: SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG % LocalWords: POLLRDHUP half close pwait Gb madvise MADV ahead REMOVE tmpfs -% LocalWords: DONTFORK DOFORK shmfs preadv pwritev syscall linux loff +% LocalWords: DONTFORK DOFORK shmfs preadv pwritev syscall linux loff head XFS +% LocalWords: MERGEABLE EOVERFLOW prealloca hole FALLOC KEEP stat fstat %%% Local Variables: