Avanti sul memory mapping
authorSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 Aug 2002 17:38:13 +0000 (17:38 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 Aug 2002 17:38:13 +0000 (17:38 +0000)
fileadv.tex
fileintro.tex
fileunix.tex

index 7a47057..790ccdb 100644 (file)
@@ -830,34 +830,36 @@ Essi verranno letti (o scritti) nell'ordine in cui li si sono specificati.
 \label{sec:file_memory_map}
 
 Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
-rispetto a quella classica, è quella dei file \textsl{mappati in memoria} (il
-cosiddetto \textit{memory-mapped I/O}). In sostanza quello che si fa è usare
-il meccanismo della \textsl{paginazione}\index{paginazione} usato per la
-memoria virtuale (vedi \secref{sec:proc_mem_gen}) vedere il file in una
-sezione dello spazio di indirizzi del processo, in modo che l'accesso a
-quest'ultimo avvenga con le normali operazioni di lettura e scrittura delle
-variabili in memoria.
-
-Questa interfaccia è più efficiente dell'uso delle usuali funzioni di I/O, in
-quanto permette di caricare in memoria solo le parti del file che sono
-effettivamente usate ad un dato istante. Infatti, dato che l'accesso è fatto
-direttamente attraverso la memoria virtuale, non è necessario trasferire in un
-buffer tutti i dati che potrebbero servire, e poi riscrivere il tutto una
-volta completate le operazioni, la scrittura e la lettura avverranno invece
-direttamente sulla sezione di memoria mappata, che sarà a sua volta letta o
-scritta sul file, una pagina alla volta (e solo per le parti effettivamente
-usate) in maniera trasparente attraverso il meccanismo della paginazione.
-L'acceso alle pagine non ancora caricate avverrà allo stesso modo con cui
-vengono caricate in memoria le pagine che sono state salvate sullo swap.
-
-Inoltre in situazioni in cui la memoria è scarsa, le pagine che mappano un
+rispetto a quella classica vista in \capref{cha:file_unix_interface}, è il
+cosiddetto \textit{memory-mapped I/O}, che attraverso il meccanismo della
+\textsl{paginazione}\index{paginazione} usato dalla memoria virtuale (vedi
+\secref{sec:proc_mem_gen}) permette di \textsl{mappare} il contenuto di un
+file in una sezione dello spazio di indirizzi del processo.
+
+Tutto questo comporta una notevole semplificazione delle operazioni di I/O, in
+quanto non sarà più necessario utilizzare dei buffer intermedi su cui
+appoggiare i dati da traferire, ma questi potranno essere acceduti
+direttamente dalla sezione di memoria; inoltre questa interfaccia
+è più efficiente delle usuali funzioni di I/O, in quanto permette di caricare
+in memoria solo le parti del file che sono effettivamente usate ad un dato
+istante.
+
+Infatti, dato che l'accesso è fatto direttamente attraverso la memoria
+virtuale, la sezione di memoria mappata su cui si opera sarà a sua volta letta
+o scritta sul file una pagina alla volta e solo per le parti effettivamente
+usate, il tutto in maniera completamente trasparente al processo; l'acceso
+alle pagine non ancora caricate avverrà allo stesso modo con cui vengono
+caricate in memoria le pagine che sono state salvate sullo swap.
+
+Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un
 file vengono salvate automaticamente, così come le pagine dei programmi
 vengono scritte sulla swap; questo consente di accedere ai file su dimensioni
-il cui solo limite è quello dello spazio di indirizzi disponibile, 
+il cui solo limite è quello dello spazio di indirizzi disponibile, e non della
+memoria su cui possono esserne lette delle porzioni.
 
-
-La funzione che permette di attivare il memory mapping di un file è
-\func{mmap}, il suo prototipo è:
+L'interfaccia prevede varie funzioni per la gestione del \textit{memory
+  mapping}, la prima di queste è \func{mmap}, che esegue la mappatura in
+memoria un file; il suo prototipo è:
 \begin{functions}
   
   \headdecl{unistd.h}
@@ -867,18 +869,230 @@ La funzione che permette di attivare il memory mapping di un file 
     fd, off\_t offset)}
   
   Esegue la mappatura in memoria del file \param{fd}.
+  
+  \bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
+    in caso di successo, e \macro{MAP\_FAILED} (-1) in caso di errore, nel
+    qual caso \var{errno} viene settata ai valori:
+    \begin{errlist}
+    \item[\macro{EBADF}] Il file descriptor non è valido, e non si è usato
+      \macro{MAP\_ANONYMOUS}.
+    \item[\macro{EACCES}] Il file descriptor non si riferisce ad un file
+      normale, o si è richiesto \macro{MAP\_PRIVATE} ma \param{fd} non è
+      aperto in lettura, o si è richiesto \macro{MAP\_SHARED} e settato
+      \macro{PROT\_WRITE} ed \param{fd} non è aperto in lettura/scrittura, o
+      si è settato \macro{PROT\_WRITE} ed \param{fd} è in
+      \textit{append-only}.
+    \item[\macro{EINVAL}] I valori di \param{start}, \param{length} o
+      \param{offset} non sono validi (o troppo grandi o non allineati sulla
+      dimensione delle pagine).
+    \item[\macro{ETXTBSY}] Si è settato \macro{MAP\_DENYWRITE} ma \param{fd} è
+      aperto in scrittura.
+    \item[\macro{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria.
+    \item[\macro{ENOMEM}] Non c'è memoria o si è superato il limite sul numero
+      di mappature possibili.
+    \item[\macro{ENODEV}] Il filesystem di \param{fd} no supporta il memory
+      mapping.
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione richiede di mappare in memoria la sezione del file \param{fd} a
+partire da \param{offset} per \param{lenght} byte, preferibilmente
+all'indirizzo \param{start}. Il valore di \param{offset} deve essere un
+multiplo della dimensione di una pagina di memoria. Il valore dell'argomento
+\param{prot} indica la protezione\footnote{in Linux la memoria reale è divisa
+  in pagine: ogni processo vede la sua memoria attraverso uno o più segmenti
+  lineari di memoria virtuale.  Per ciascuno di questi segmenti il kernel
+  mantiene nella \textit{page table} la mappatura sulle pagine di memoria
+  reale, ed le modalità di accesso (lettura, esecuzione, scrittura); una loro
+  violazione causa quella che si chiama una \textit{segment violation}, e la
+  relativa emissione del segnale \macro{SIGSEGV}.} da applicare al segmento di
+memoria e deve essere specificato come maschera binaria ottenuta dall'OR di
+uno o più dei valori riportati in \tabref{tab:file_mmap_flag}; il valore
+specificato deve essere compatibile con la modalità con cui si è aperto il
+file.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{PROT\_EXEC}  & Le pagine possono essere eseguite.\\
+    \macro{PROT\_READ}  & Le pagine possono essere lette.\\
+    \macro{PROT\_WRITE} & Le pagine possono essere scritte.\\
+    \macro{PROT\_NONE}  & L'accesso alle pagine è vietato.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{prot} di \func{mmap}, relativi alla
+    protezione applicate alle pagine del file mappate in memoria.}
+  \label{tab:file_mmap_prot}
+\end{table}
+
+L'argomento \param{flags} specifica qual'è il tipo di oggetto mappato, le
+opzioni relative alle modalità con cui è effettuata la mappatura e alle
+modalità con cui le modifiche alla memoria mappata vengono condivise o
+mantenute private al processo che le ha effettuate. Deve essere specificato
+come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
+\tabref{tab:file_mmap_flag}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{MAP\_FIXED}     & Non permette di restituire un indirizzo diverso
+                             da \param{start}, se questo non può essere usato
+                             \func{mmap} fallisce. Se si setta questo flag il
+                             valore di \param{start} deve essere allineato
+                             alle dimensioni di una pagina. \\
+    \macro{MAP\_SHARED}    & I cambiamenti sulla memoria mappata vengono
+                             riportati sul file e saranno immediatamente
+                             visibili agli altri processi che mappano lo stesso
+                             file.\footnotemark Il file su disco però non sarà
+                             aggiornato fino alla chiamata di \func{rsync} o
+                             \func{unmap}), e solo allora le modifiche saranno
+                             visibili per l'I/O convenzionale. Incompatibile
+                             con \macro{MAP\_PRIVATE}. \\ 
+    \macro{MAP\_PRIVATE}   & I cambiamenti sulla memoria mappata non vengono
+                             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
+                             salvate su swap in caso di necessità. Non è
+                             specificato se i cambiamenti sul file originale
+                             vengano riportati sulla regione
+                             mappata. Incompatibile con \macro{MAP\_SHARED}. \\
+    \macro{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
+                             \textit{DoS}\index{DoS} (veniva usato per
+                             segnalare che tentativi di scrittura sul file
+                             dovevano fallire con \macro{ETXTBUSY}).\\
+    \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 mantere le modifiche 
+                             fatte alla regione mappata, in
+                             questo caso dopo una scrittura, se non c'è più
+                             memoria disponibile, si ha l'emissione di
+                             un \macro{SIGSEGV}. \\
+    \macro{MAP\_LOCKED}    & Se settato impedisce lo swapping delle pagine
+                             mappate. \\
+    \macro{MAP\_GROWSDOWN} & Usato per gli stack. Indica alla virtual memory
+                             che la mappatura deve essere effettuata .\\
+    \macro{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
+                             argomenti \param{fd} e \param{offset} sono
+                             ignorati.\footnotemark\\
+    \macro{MAP\_ANON}      & Sinonimo di \macro{MAP\_ANONYMOUS}, deprecato.\\
+    \macro{MAP\_FILE}      & Valore di compatibiità, deprecato.\\
+    \hline
+  \end{tabular}
+  \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.}
+  \label{tab:file_mmap_flag}
+\end{table}
+
+\footnotetext{Dato che tutti faranno riferimento alle stesse pagine di
+  memoria.}  
+\footnotetext{L'uso di questo flag con \macro{MAP\_SHARED} è
+  stato implementato in Linux a partire dai kernel della serie 2.4.x.}
+
+Un file viene sempre mappato su multipli delle dimensioni di una pagina,
+qualora esso sia più corto la parte restante è riempita con zeri; eventuali
+scritture in quella zona di memoria non vengono riportate sul file. Se le
+dimensioni del file cambiano (esso viene esteso o troncato), non è specificato
+quale effetto viene a aversi sulle pagine di memoria che corrispondono alle
+regioni aggiunte o tolte.
+
+Si tenga presente che non tutti i file possono venire mappati in memoria; ad
+esempio non è possibile mappare in memoria pipe, socket e fifo; lo stesso vale
+anche per alcuni file di dispositivo, che non dispongono dell'operazione
+relativa \var{mmap} (si ricordi quanto esposto in \secref{sec:file_vfs_work}).
+
+La memoria mappata viene mantenuta attraverso una \func{fork}; con gli stessi
+attributi. In particolare se la memoria è condivisa lo sarà anche fra padre e
+figlio, se è privata ognuno di essi manterrà una sua versione privata. Non c'è
+invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
+sostituisce tutto lo spazio degli indirizzo con quello del nuovo programma.
+
+Quando si effettua una mappatura di un file, i relativi tempi (vedi
+\secref{sec:file_file_times}) vengono pure modificati. Il valore di
+\var{st\_atime} può venir cambiato in un qualunque momento in cui la mappatura
+sia attiva: il primo riferimento ad una pagina mappata aggiorna questo tempo.
+I valori di \var{st\_ctime} e \var{st\_mtime} vengono cambiati solo quando è
+possibile una scrittura (cioè per un file mappato con \macro{PROT\_WRITE} e
+\macro{MAP\_SHARED}) e sono aggiornati dopo la scrittura e prima di una
+eventuale \func{msync}.
+
+Dato per i file mappati in memoria le operazioni di I/O sono gestite
+direttamente dalla memoria virtuale, occorre essere consapevoli delle
+interazioni che possono esserci con operazioni effettuate con l'interfaccia
+standard di \capref{sec:file_unix_interface}. Il problema è che una volta che
+si è mappato un file, le operazioni di lettura e scrittura saranno eseguite
+sulla memoria, e riportate su disco in maniera autonoma dal sistema della
+memoria virtuale.  
+
+Pertanto se si modifica un file con l'interfaccia standard queste modifiche
+potranno essere visibili o meno a seconda del momento in cui la memoria
+virtuale leggerà dal disco in memoria quella sezione del file, ed è del tutto
+indefinito quale può essere il contenuto della memoria mappata.  È però
+possibile usare la funzione \func{msync} per sincronizzare il contenuto della
+memoria con il file su disco; il suo prototipo è:
+\begin{functions}  
+  \headdecl{unistd.h}
+  \headdecl{sys/mman.h} 
 
+  \funcdecl{int msync(const void *start, size\_t length, int flags)}
+  
+  Sincronizza i contenuti di una sezione di un file mappato in memoria.
+  
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore nel qual caso \var{errno} viene settata ai valori:
     \begin{errlist}
-    \item[\macro{EBADF}] Il file descriptor non è valido, e non si è usato
-      \macro{MAP\_ANONYMOUS}.
-    \item[\macro{EACCES}] \macro{MAP\_PRIVATE}.
-    \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
+    \item[\macro{EINVAL}] O \param{start} non è multiplo di \macro{PAGESIZE},
+    o si è specificato un valore non valido per \param{flags}.
+    \item[\macro{EFAULT}] Il range specificato non ricade in una zona
+      precedentemente mappata.
     \end{errlist}
-  ed inoltre \macro{ENOMEM}.}
+  }
 \end{functions}
 
+La funzione esegue la sincronizzazione su file di quanto scritto nella sezione
+di memoria indicata da \param{start} e \param{offset}.  Provvede anche ad
+aggiornare i relativi tempi di modifica; in questo modo le funzioni
+dell'interfaccia standard potranno accedere al contenuto aggiornato.
+
+L'argomento \param{flag} è specificato come maschera binaria composta da un OR
+dei valori riportati in \tabref{tab:file_mmap_rsync}, di questi però
+\macro{MS\_ASYNC} e \macro{MS\_SYNC} sono incompatibili; con il primo valore
+infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
+meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
+attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
+flag fa invalidare le pagine di cui si richiede la sincronizzazione per tutte
+le mappature dello stesso file, così che esse possano essere immediatamente
+aggiornate ai nuovi valori.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{MS\_ASYNC}     & Richiede la sincronizzazione.\\
+    \macro{MS\_SYNC}      & Attende che la sincronizzazione si eseguita.\\
+    \macro{MS\_INVALIDATE}& Richiede che le altre mappature dello stesso file
+                            siano invalidate.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{flag} di \func{msync}.}
+  \label{tab:file_mmap_rsync}
+\end{table}
+
 Una volta completate le operazioni di I/O si può eliminare la mappatura della
 memoria usando la funzione \func{munmap}, il cui prototipo è:
 \begin{functions}  
@@ -887,19 +1101,19 @@ memoria usando la funzione \func{munmap}, il cui prototipo 
 
   \funcdecl{int munmap(void *start, size\_t length)}
   
-  Esegue la mappatura in memoria del file \param{fd}.
+  Rilascia la mappatura sulla sezione di memoria specificata.
 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore nel qual caso \var{errno} viene settata ai valori:
     \begin{errlist}
-    \item[\macro{EBADF}] Il file descriptor non è valido, e non si è usato
-      \macro{MAP\_ANONYMOUS}.
-    \item[\macro{EACCES}] \macro{MAP\_PRIVATE}.
-    \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
+    \item[\macro{EINVAL}] Il range specificato non ricade in una zona
+      precedentemente mappata.
     \end{errlist}
-  ed inoltre \macro{ENOMEM}.}
+  }
 \end{functions}
 
+La funzione 
+
 
 \section{Il file locking}
 \label{sec:file_locking}
index 14e4f27..0a7bb94 100644 (file)
@@ -448,26 +448,29 @@ operazioni previste dal kernel 
 \begin{table}[htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|l|p{7cm}|}
+  \begin{tabular}[c]{|l|p{8cm}|}
     \hline
     \textbf{Funzione} & \textbf{Operazione} \\
     \hline
     \hline
-    \textsl{\code{open}}   & apre il file \\
-    \textsl{\code{read}}   & legge dal file \\
-    \textsl{\code{write}}  & scrive sul file \\ 
-    \textsl{\code{llseek}} & sposta la posizione corrente sul file \\
+    \textsl{\code{open}}   & apre il file (vedi \secref{sec:file_open}). \\
+    \textsl{\code{read}}   & legge dal file (vedi \secref{sec:file_read}).\\
+    \textsl{\code{write}}  & scrive sul file (vedi \secref{sec:file_write}).\\ 
+    \textsl{\code{llseek}} & sposta la posizione corrente sul file (vedi
+                             \secref{sec:file_lseek}). \\
     \textsl{\code{ioctl}}  & accede alle operazioni di controllo 
-                       (tramite la \func{ioctl})\\
-    \textsl{\code{readdir}}& per leggere il contenuto di una directory \\
-    \textsl{\code{poll}}   & \\
-    \textsl{\code{mmap}}   & chiamata dalla system call \func{mmap}. 
-                       mappa il file in memoria\\
+                             (vedi \secref{sec:file_ioctl}).\\
+    \textsl{\code{readdir}}& legge il contenuto di una directory \\
+    \textsl{\code{poll}}   & usata nell'I/O multiplexing (vedi
+                             \secref{sec:file_multiplexing}). \\
+    \textsl{\code{mmap}}   & mappa il file in memoria (vedi 
+                             \secref{sec:file_memory_map}). \\
     \textsl{\code{release}}& chiamata quando l'ultima referenza a un file 
-                       aperto è chiusa\\
-    \textsl{\code{fsync}}  & chiamata dalla system call \func{fsync} \\
-    \textsl{\code{fasync}} & chiamate da \func{fcntl} quando è abilitato 
-                           il modo asincrono per l'I/O su file. \\
+                             aperto è chiusa. \\
+    \textsl{\code{fsync}}  & sincronizza il contenuto del file (vedi
+                             \secref{sec:file_sync}). \\
+    \textsl{\code{fasync}} & abilita l'I/O asincrono (vedi
+                             \secref{sec:file_asyncronous_io}) sul file. \\
     \hline
   \end{tabular}
   \caption{Operazioni sui file definite nel VFS.}
index 8f49c5e..4ea7eb9 100644 (file)
@@ -252,7 +252,8 @@ sempre il file descriptor con il valore pi
     opzione è ignorata. \\
     \macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata
     fallisce. Questo flag è specifico di Linux ed è stato introdotto con il
-    kernel 2.1.126 per evitare dei DoS\protect\footnotemark\ quando 
+    kernel 2.1.126 per evitare dei
+    \textit{DoS}\index{DoS}\protect\footnotemark\ quando  
     \func{opendir} viene chiamata su una 
     fifo o su un device di unità a nastri, non deve essere utilizzato al di 
     fuori dell'implementazione di \func{opendir}. \\