From 1ee77ce91c941b6be83ee7ae20f2a3e3bf032e1a Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 26 Jun 2005 01:14:15 +0000 Subject: [PATCH] Inserita mprotect, che mancava dalle funzioni per la gestione del memory mapping, e iniziato a ddescrivere remap_file_pages. --- fileadv.tex | 206 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 126 insertions(+), 80 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index e520509..f7fba16 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1383,22 +1383,60 @@ 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 -un precedente \textit{memory mapping}, ad esempio per espanderlo o -restringerlo. 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} @@ -1413,81 +1451,78 @@ 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 può restituire un -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 e così via). 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 la funzione -\func{mmap} per ciascuna delle diverse aree,\footnote{ed in effetti è quello - che veniva fatto prima che fossero introdotte queste estensioni.} ma questo -approccio ha delle conseguenze molto pesanti in termini di prestazioni. Si -ricordi infatti che il \textit{memory mapping} funziona facendo ricorso al -meccanismo della \index{memoria~virtuale} memoria virtuale per trascrivere su -un file le operazioni effettuate sugli indirizzi di memoria sui cui esso è -mappato. - -Questo vuol dire che per ciascuna mappatura in memoria deve essere definita -nella \itindex{page~table} \textit{page table} del processo una nuova area -della memoria virtuale\footnote{quella che nel gergo del kernel viene chiamata - una \textit{virtual memory area} o VMA.} che corrisponda alla mappatura, in -modo che questa diventi visibile nello spazio degli indirizzi come illustrato -in fig.~\ref{fig:file_mmap_layout}. +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 vale per ciascun processo che utilizza questa -tecnica. In situazioni come questa si possono ottenere peggioramenti notevoli -delle prestazioni, 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 queste mappature. - -Per questo motivo con il kernel 2.5.46 è stato introdotto ad opera di Ingo -Molnar un meccanismo che consente la mappatura non lineare, che è una seconda -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. Questo viene realizzato tramite una nuova system call, -\funcd{remap\_file\_pages}, il cui prototipo è: +\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} @@ -1499,13 +1534,24 @@ questa i dati del file. Questo viene realizzato tramite una nuova system call, \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}] Uno dei puntatori non è validi, in genere si è - usato un valore di \param{old\_address} non allineato ad una pagina di - memoria. + \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 -- 2.30.2