Inserita mprotect, che mancava dalle funzioni per la gestione del memory
[gapil.git] / fileadv.tex
index 6a94f22492fa08ef6ca8047c9e49681ca23d269d..f7fba16f329e1116e2f3d44123f7d51635667b7b 100644 (file)
@@ -998,7 +998,7 @@ si pu
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=13cm]{img/mmap_layout}
+  \includegraphics[width=14cm]{img/mmap_layout}
   \caption{Disposizione della memoria di un processo quando si esegue la
   mappatura in memoria di un file.}
   \label{fig:file_mmap_layout}
@@ -1038,7 +1038,7 @@ eseguire la mappatura in memoria di un file, 
   \funcdecl{void * mmap(void * start, size\_t length, int prot, int flags, int
     fd, off\_t offset)}
   
-  Esegue la mappatura in memoria del file \param{fd}.
+  Esegue la mappatura in memoria della sezione specificata del file \param{fd}.
   
   \bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
     in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
@@ -1056,11 +1056,18 @@ eseguire la mappatura in memoria di un file, 
       dimensione delle pagine).
     \item[\errcode{ETXTBSY}] Si è impostato \const{MAP\_DENYWRITE} ma
       \param{fd} è aperto in scrittura.
-    \item[\errcode{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria.
+    \item[\errcode{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria
+      rispetto a quanto consentito dai limiti di sistema (vedi
+      sez.~\ref{sec:sys_resource_limit}).
     \item[\errcode{ENOMEM}] Non c'è memoria o si è superato il limite sul
       numero di mappature possibili.
     \item[\errcode{ENODEV}] Il filesystem di \param{fd} non supporta il memory
       mapping.
+    \item[\errcode{EPERM}] L'argomento \param{prot} ha richiesto
+      \const{PROT\_EXEC}, ma il filesystem di \param{fd} è montato con
+      l'opzione \texttt{noexec}.
+    \item[\errcode{ENFILE}] Si è superato il limite del sistema sul numero di
+      file aperti (vedi sez.~\ref{sec:sys_resource_limit}).
     \end{errlist}
   }
 \end{functions}
@@ -1213,7 +1220,7 @@ effettive del file o della sezione che si vuole mappare.
 
 \begin{figure}[!htb] 
   \centering
-  \includegraphics[width=10cm]{img/mmap_boundary}
+  \includegraphics[width=12cm]{img/mmap_boundary}
   \caption{Schema della mappatura in memoria di una sezione di file di
     dimensioni non corrispondenti al bordo di una pagina.}
   \label{fig:file_mmap_boundary}
@@ -1256,7 +1263,7 @@ che sono utilizzabili solo con questa interfaccia.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=10cm]{img/mmap_exceed}
+  \includegraphics[width=12cm]{img/mmap_exceed}
   \caption{Schema della mappatura in memoria di file di dimensioni inferiori
     alla lunghezza richiesta.}
   \label{fig:file_mmap_exceed}
@@ -1376,27 +1383,66 @@ mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo 
   }
 \end{functions}
 
-La funzione cancella la mappatura per l'intervallo specificato attraverso
-\param{start} e \param{length}, ed ogni successivo accesso a tale regione
-causerà un errore di accesso in memoria. L'argomento \param{start} deve essere
-allineato alle dimensioni di una pagina di memoria, e la mappatura di tutte le
-pagine contenute (anche parzialmente) nell'intervallo indicato, verrà rimossa.
-Indicare un intervallo che non contiene pagine mappate non è un errore.
+La funzione cancella la mappatura per l'intervallo specificato con
+\param{start} e \param{length}; ogni successivo accesso a tale regione causerà
+un errore di accesso in memoria. L'argomento \param{start} deve essere
+allineato alle dimensioni di una pagina, e la mappatura di tutte le pagine
+contenute anche parzialmente nell'intervallo indicato, verrà rimossa.
+Indicare un intervallo che non contiene mappature non è un errore.  Si tenga
+presente inoltre che alla conclusione di un processo ogni pagina mappata verrà
+automaticamente rilasciata, mentre la chiusura del file descriptor usato per
+il \textit{memory mapping} non ha alcun effetto su di esso.
+
+Lo standard POSIX prevede anche una funzione che permetta di cambiare le
+protezioni delle pagine di memoria; lo standard prevede che essa si applichi
+solo ai \textit{memory mapping} creati con \func{mmap}, ma nel caso di Linux
+la funzione può essere usata con qualunque pagina valida nella memoria
+virtuale. Questa funzione è \funcd{mprotect} ed il suo prototipo è:
+\begin{functions}  
+%  \headdecl{unistd.h}
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{int mprotect(const void *addr, size\_t len, int prot)}
+  
+  Modifica le protezioni delle pagine di memoria comprese nell'intervallo
+  specificato.
+
+  \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[\errcode{EINVAL}] il valore di \param{addr} non è valido o non è un
+      multiplo di \const{PAGE\_SIZE}.
+    \item[\errcode{EACCESS}] l'operazione non è consentita, ad esempio si è
+      cercato di marcare con \const{PROT\_WRITE} un segmento di memoria cui si
+      ha solo accesso in lettura.
+%     \item[\errcode{ENOMEM}] non è stato possibile allocare le risorse
+%       necessarie all'interno del kernel.
+%     \item[\errcode{EFAULT}] si è specificato un indirizzo di memoria non
+%       accessibile.
+    \end{errlist}
+    ed inoltre \errval{ENOMEM} ed \errval{EFAULT}.
+  } 
+\end{functions}
+
+
+La funzione prende come argomenti un indirizzo di partenza in \param{addr},
+allineato alle dimensioni delle pagine di memoria, ed una dimensione
+\param{size}. La nuova protezione deve essere specificata in \param{prot} con
+una combinazione dei valori di tab.~\ref{tab:file_mmap_prot}.  La nuova
+protezione verrà applicata a tutte le pagine contenute, anche parzialmente,
+dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1.
 
-Alla conclusione del processo, ogni pagina mappata verrà automaticamente
-rilasciata, mentre la chiusura del file descriptor usato per effettuare la
-mappatura in memoria non ha alcun effetto sulla stessa.
 
 Infine Linux supporta alcune operazioni specifiche non disponibili su altri
-kernel unix-like. La prima di queste operazioni è la possibilità di modificare
-una mappatura precedente, ad esempio per espanderla o restringerla. Questo è
-realizzato dalla funzione \funcd{mremap}, il cui prototipo è:
+kernel unix-like. La prima di queste è la possibilità di modificare un
+precedente \textit{memory mapping}, ad esempio per espanderlo o restringerlo.
+Questo è realizzato dalla funzione \funcd{mremap}, il cui prototipo è:
 \begin{functions}  
   \headdecl{unistd.h}
   \headdecl{sys/mman.h} 
 
   \funcdecl{void * mremap(void *old\_address, size\_t old\_size , size\_t
-    new\_size, unsigned long flags);}
+    new\_size, unsigned long flags)}
   
   Restringe o allarga una mappatura in memoria di un file.
 
@@ -1405,62 +1451,122 @@ realizzato dalla funzione \funcd{mremap}, il cui prototipo 
       -1}) in caso di errore, nel qual caso \var{errno} assumerà uno dei
     valori:
     \begin{errlist}
-    \item[\errcode{EINVAL}] Uno dei puntatori non è validi, in genere si è
-      usato un valore di \param{old\_address} non allineato ad una pagina di
-      memoria.
-    \item[\errcode{EFAULT}] Ci sono degli indirizzi non validi nell'intervallo
-      di memoria specificato dagli argomenti \param{old\_address} e
-      \param{old\_size}, o ci sono altre mappatura di un tipo non
-      corrispondente a quella richiesta.
-    \item[\errcode{ENOMEM}] Non c'è memoria sufficiente oppure l'area di
+    \item[\errcode{EINVAL}] il valore di \param{old\_address} non è un
+      puntatore valido.
+    \item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo
+      specificato da \param{old\_address} e \param{old\_size}, o ci sono altre
+      mappature di tipo non corrispondente a quella richiesta.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente oppure l'area di
       memoria non può essere espansa all'indirizzo virtuale corrente, e non si
       è specificato \const{MREMAP\_MAYMOVE} nei flag.
-    \item[\errcode{EAGAIN}] Il segmento di memoria scelto è bloccato e non può
+    \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può
       essere rimappato.
     \end{errlist}
   }
 \end{functions}
 
-La funzione richiede come argomenti \param{old\_address} che specifica il
-precedente indirizzo per la mappatura in memoria e \param{old\_size}, che ne
-indica la dimensione, con \param{new\_size} si specifica invece la nuova
-dimensione che si vuole ottenere. Questa funzione usa il meccanismo della
-\index{memoria~virtuale}memoria virtuale per modificare l'associazione fra gli
-indirizzi virtuali del processo e le pagine di memoria, modificando una
-precedente mappatura.
-
-Infine l'argomento \param{flags} è una maschera binaria per i flag che
-controllano il comportamento della funzione. Il solo valore utilizzato è
-\const{MREMAP\_MAYMOVE}\footnote{per poter utilizzare questa costante occorre
-  aver definito \macro{\_GNU\_SOURCE} prima di includere \file{sys/mman.h}.}
-che consente di eseguire l'espansione anche quando non è possibile utilizzare
-il predente indirizzo. Per questo motivo la funzione restituisce sempre
-l'indirizzo della nuova zona di memoria, che, se si è usato questo flag, non è
-detto coincida con \param{old\_address}.
-
-La mappatura in memoria di un file viene normalmente eseguita in maniera
-lineare, cioè parti successive di un file vengono mappate linearmente su
-indirizzi successivi in memoria (la prima pagina di un file viene mappata
-sulla prima pagina di memoria). Esistono però delle applicazioni\footnote{in
-  particolare la tecnica è usata dai database o dai programmi che realizzano
-  macchine virtuali.} in cui è utile poter mappare parti diverse di un file su
-diverse zone di memoria. 
-
-Questo è ovviamente sempre possibile eseguendo più volte \func{mmap} per
-ciascuna delle diverse aree, ma questo approccio ha delle conseguenze molto
-pesanti in termini di prestazioni. Si ricordi infatti che il \textit{memory
-  mapping} in memoria funziona facendo ricorso al meccaniso della
-\index{memoria~virtuale} memoria virtuale per trascrivere su un file le
-operazioni effettuate sugli indirizzi di memoria sui cui esso è mappato. 
-
-Per questo motivo con il kernel 2.5.46 è stato introdotto ad opera di Ingo
-Molnar un meccanismo che consente la mappatura non lineare, ed i due nuovi
-flag \const{MAP\_POPULATE} e \const{MAP\_NONBLOCK} per \func{mmap}.
+La funzione richiede come argomenti \param{old\_address} (che deve essere
+allineato alle dimensioni di una pagina di memoria) che specifica il
+precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne
+indica la dimensione. Con \param{new\_size} si specifica invece la nuova
+dimensione che si vuole ottenere. Infine l'argomento \param{flags} è una
+maschera binaria per i flag che controllano il comportamento della funzione.
+Il solo valore utilizzato è \const{MREMAP\_MAYMOVE}\footnote{per poter
+  utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima
+  di includere \file{sys/mman.h}.}  che consente di eseguire l'espansione
+anche quando non è possibile utilizzare il precedente indirizzo. Per questo
+motivo, se si è usato questo flag, la funzione può restituire un indirizzo
+della nuova zona di memoria che non è detto coincida con \param{old\_address}.
+
+La funzione si appoggia al sistema della \index{memoria~virtuale} memoria
+virtuale per modificare l'associazione fra gli indirizzi virtuali del processo
+e le pagine di memoria, modificando i dati direttamente nella
+\itindex{page~table} \textit{page table} del processo. Come per
+\func{mprotect} la funzione può essere usata in generale, anche per pagine di
+memoria non corrispondenti ad un \textit{memory mapping}, e consente così di
+implementare la funzione \func{realloc} in maniera molto efficiente.
+
+Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in
+memoria di un file viene eseguita in maniera lineare, cioè parti successive di
+un file vengono mappate linearmente su indirizzi successivi in memoria.
+Esistono però delle applicazioni\footnote{in particolare la tecnica è usata
+  dai database o dai programmi che realizzano macchine virtuali.} in cui è
+utile poter mappare sezioni diverse di un file su diverse zone di memoria.
+
+Questo è ovviamente sempre possibile eseguendo la funzione \func{mmap} per
+ciascuna delle diverse aree,\footnote{ed in effetti è quello che veniva fatto
+  anche con Linux prima che fossero introdotte queste estensioni.} ma questo
+approccio ha delle conseguenze molto pesanti in termini di prestazioni.
+Infatti per ciascuna mappatura in memoria deve essere definita nella
+\itindex{page~table} \textit{page table} del processo una nuova area di
+memoria virtuale\footnote{quella che nel gergo del kernel viene chiamata VMA
+  (\textit{virtual memory area}).} che corrisponda alla mappatura, in modo che
+questa diventi visibile nello spazio degli indirizzi come illustrato in
+fig.~\ref{fig:file_mmap_layout}.
+
+Quando un processo esegue un gran numero di mappature diverse\footnote{si può
+  arrivare anche a centinaia di migliaia.} per realizzare a mano una mappatura
+non-linare si avrà un accrescimento eccessivo della sua \itindex{page~table}
+\textit{page table}, e lo stesso accadrà per tutti gli altri processi che
+utilizzano questa tecnica. In situazioni in cui le applicazioni hanno queste
+esigenze si avranno delle prestazioni ridotte, dato che il kernel dovrà
+impiegare molte risorse\footnote{sia in termini di memoria interna per i dati
+  delle \itindex{page~table} \textit{page table}, che di CPU per il loro
+  aggiornamento.} solo per mantenere i dati di una gran quantità di
+\textit{memory mapping}.
+
+Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo
+Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è
+una caratteristica specifica di Linux, non presente in altri sistemi
+unix-like.  Diventa così possibile utilizzare una sola mappatura
+iniziale\footnote{e quindi una sola \textit{virtual memory area} nella
+  \itindex{page~table} \textit{page table} del processo.} e poi rimappare a
+piacere all'interno di questa i dati del file. Ciò è possibile grazie ad una
+nuova system call, \funcd{remap\_file\_pages}, il cui prototipo è:
+\begin{functions}  
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{int remap\_file\_pages(void *start, size\_t size, int prot,
+    ssize\_t pgoff, int flags)}
+  
+  Permette di rimappare non linearmente un precedente \textit{memory mapping}.
+
+  \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[\errcode{EINVAL}] Si è usato un valore non valido per uno degli
+      argomenti o \param{start} non fa riferimento ad un \textit{memory
+        mapping} valido creato con \const{MAP\_SHARED}.
+    \end{errlist}
+  }
+\end{functions}
+
+Per poter utilizzare questa funzione occorre anzitutto effettuare
+preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per
+definire l'area di memoria che poi sarà rimappata non linearmente. Poi di
+chiamerà questa funzione per modificare le corrispondenze fra pagine di
+memoria e pagine del file; si tenga presente che \func{remap\_file\_pages}
+permette anche di mappare la stessa pagina di un file in più pagine della
+regione mappata.
+
+La funzione richiede che si identifichi la pagine di file che si vuole
+rimappare con \param{pgoff} e \param{size}, che ne indicano l'inizio (in unità
+della dimensione delle pagine di memoria) \param{start}
+
+Insiema al meccanismo per la mappatura non-lineare con sono stati introdotti
+anche due nuovi flag per \func{mmap}: \const{MAP\_POPULATE} e
+\const{MAP\_NONBLOCK}.
 
 
 \itindend{memory~mapping}
 
 
+% i raw device 
+%\subsection{I \textit{raw} device}
+%\label{sec:file_raw_device}
+
+
+
 
 \section{Il file locking}
 \label{sec:file_locking}