From: Simone Piccardi Date: Fri, 24 Jun 2005 23:41:55 +0000 (+0000) Subject: Altre correzioni di indicizzazioni. Introdotta mremap. Aggiornati i flag di X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=34c8ae732b8ffe5f4a87cdd0eba3a02df4c76d55;p=gapil.git Altre correzioni di indicizzazioni. Introdotta mremap. Aggiornati i flag di rmap per il prefaulting. Iniziata la documentazione del memory mapping non lineare. Qualche correzione alla sezione iniziale sul funzionamento della memoria virtuale. --- diff --git a/errors.tex b/errors.tex index adecb8e..7b92a3f 100644 --- a/errors.tex +++ b/errors.tex @@ -340,11 +340,16 @@ specificati nelle sezioni precedenti. \item \errcode{EMULTIHOP} \textit{Multihop attempted}. \item \errcode{ENODATA} \textit{No data available}. \item \errcode{ENOLINK} \textit{Link has been severed}. -\item \errcode{ENOMSG} \textit{No message of desired type}. +\item \errcode{ENOMSG} \textit{No message of desired type}. Indica che una + coda di messaggi del \textit{SysV IPC} non è presente nessun messaggio del + tipo desiderato. \item \errcode{ENOSR} \textit{Out of streams resources}. \item \errcode{ENOSTR} \textit{Device not a stream}. -\item \errcode{EOVERFLOW} \textit{Value too large for defined data type}. -\item \errcode{EPROTO} \textit{Protocol error}. +\item \errcode{EOVERFLOW} \textit{Value too large for defined data type}. Si è + chiesta la lettura di un dato dal \textit{SysV IPC} con \const{IPC\_STAT} ma + il valore eccede la dimensione usata nel buffer di lettura. +\item \errcode{EPROTO} \textit{Protocol error}. C'è stato un errore nel + protocollo di rete usato dal socket. \item \errcode{ETIME} \textit{Timer expired}. \end{description} @@ -352,54 +357,54 @@ specificati nelle sezioni precedenti. -\section{Errori del kernel} -\label{sec:err_kernel_err} +% \section{Errori del kernel} +% \label{sec:err_kernel_err} -In questa sezione sono raccolti i codici di errore interni del kernel. Non -sono usati dalle funzioni di libreria, ma vengono riportati da alcune system -call (TODO verificare i dettagli, eventualmente cassare). +% In questa sezione sono raccolti i codici di errore interni del kernel. Non +% sono usati dalle funzioni di libreria, ma vengono riportati da alcune system +% call (TODO verificare i dettagli, eventualmente cassare). -\begin{description} -\item \errcode{ERESTART} \textit{Interrupted system call should be restarted}. -\item \errcode{ECHRNG} \textit{Channel number out of range}. -\item \errcode{EL2NSYNC} \textit{Level 2 not synchronized}. -\item \errcode{EL3HLT} \textit{Level 3 halted}. -\item \errcode{EL3RST} \textit{Level 3 reset}. -\item \errcode{ELNRNG} \textit{Link number out of range}. -\item \errcode{EUNATCH} \textit{Protocol driver not attached}. -\item \errcode{ENOCSI} \textit{No CSI structure available}. -\item \errcode{EL2HLT} \textit{Level 2 halted}. -\item \errcode{EBADE} \textit{Invalid exchange}. -\item \errcode{EBADR} \textit{Invalid request descriptor}. -\item \errcode{EXFULL} \textit{Exchange full}. -\item \errcode{ENOANO} \textit{No anode}. -\item \errcode{EBADRQC} \textit{Invalid request code}. -\item \errcode{EBADSLT} \textit{Invalid slot}. -\item \errcode{EDEADLOCK} Identico a \errcode{EDEADLK}. -\item \errcode{EBFONT} \textit{Bad font file format}. -\item \errcode{ENONET} \textit{Machine is not on the network}. -\item \errcode{ENOPKG} \textit{Package not installed}. -\item \errcode{EADV} \textit{Advertise error}. -\item \errcode{ESRMNT} \textit{Srmount error}. -\item \errcode{ECOMM} \textit{Communication error on send}. -\item \errcode{EDOTDOT} \textit{RFS specific error}. -\item \errcode{ENOTUNIQ} \textit{Name not unique on network}. -\item \errcode{EBADFD} \textit{File descriptor in bad state}. -\item \errcode{EREMCHG} \textit{Remote address changed}. -\item \errcode{ELIBACC} \textit{Can not access a needed shared library}. -\item \errcode{ELIBBAD} \textit{Accessing a corrupted shared library}. -\item \errcode{ELIBSCN} \textit{.lib section in a.out corrupted}. -\item \errcode{ELIBMAX} \textit{Attempting to link in too many shared - libraries}. -\item \errcode{ELIBEXEC} \textit{Cannot exec a shared library directly}. -\item \errcode{ESTRPIPE} \textit{Streams pipe error}. -\item \errcode{EUCLEAN} \textit{Structure needs cleaning}. -\item \errcode{ENAVAIL} \textit{No XENIX semaphores available}. -\item \errcode{EISNAM} \textit{Is a named type file}. -\item \errcode{EREMOTEIO} \textit{Remote I/O error}. -\item \errcode{ENOMEDIUM} \textit{No medium found}. -\item \errcode{EMEDIUMTYPE} \textit{Wrong medium type}. -\end{description} +% \begin{description} +% \item \errcode{ERESTART} \textit{Interrupted system call should be restarted}. +% \item \errcode{ECHRNG} \textit{Channel number out of range}. +% \item \errcode{EL2NSYNC} \textit{Level 2 not synchronized}. +% \item \errcode{EL3HLT} \textit{Level 3 halted}. +% \item \errcode{EL3RST} \textit{Level 3 reset}. +% \item \errcode{ELNRNG} \textit{Link number out of range}. +% \item \errcode{EUNATCH} \textit{Protocol driver not attached}. +% \item \errcode{ENOCSI} \textit{No CSI structure available}. +% \item \errcode{EL2HLT} \textit{Level 2 halted}. +% \item \errcode{EBADE} \textit{Invalid exchange}. +% \item \errcode{EBADR} \textit{Invalid request descriptor}. +% \item \errcode{EXFULL} \textit{Exchange full}. +% \item \errcode{ENOANO} \textit{No anode}. +% \item \errcode{EBADRQC} \textit{Invalid request code}. +% \item \errcode{EBADSLT} \textit{Invalid slot}. +% \item \errcode{EDEADLOCK} Identico a \errcode{EDEADLK}. +% \item \errcode{EBFONT} \textit{Bad font file format}. +% \item \errcode{ENONET} \textit{Machine is not on the network}. +% \item \errcode{ENOPKG} \textit{Package not installed}. +% \item \errcode{EADV} \textit{Advertise error}. +% \item \errcode{ESRMNT} \textit{Srmount error}. +% \item \errcode{ECOMM} \textit{Communication error on send}. +% \item \errcode{EDOTDOT} \textit{RFS specific error}. +% \item \errcode{ENOTUNIQ} \textit{Name not unique on network}. +% \item \errcode{EBADFD} \textit{File descriptor in bad state}. +% \item \errcode{EREMCHG} \textit{Remote address changed}. +% \item \errcode{ELIBACC} \textit{Can not access a needed shared library}. +% \item \errcode{ELIBBAD} \textit{Accessing a corrupted shared library}. +% \item \errcode{ELIBSCN} \textit{.lib section in a.out corrupted}. +% \item \errcode{ELIBMAX} \textit{Attempting to link in too many shared +% libraries}. +% \item \errcode{ELIBEXEC} \textit{Cannot exec a shared library directly}. +% \item \errcode{ESTRPIPE} \textit{Streams pipe error}. +% \item \errcode{EUCLEAN} \textit{Structure needs cleaning}. +% \item \errcode{ENAVAIL} \textit{No XENIX semaphores available}. +% \item \errcode{EISNAM} \textit{Is a named type file}. +% \item \errcode{EREMOTEIO} \textit{Remote I/O error}. +% \item \errcode{ENOMEDIUM} \textit{No medium found}. +% \item \errcode{EMEDIUMTYPE} \textit{Wrong medium type}. +% \end{description} diff --git a/fileadv.tex b/fileadv.tex index 25e62d3..6a94f22 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -998,7 +998,7 @@ si pu \begin{figure}[htb] \centering - \includegraphics[width=14cm]{img/mmap_layout} + \includegraphics[width=13cm]{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} @@ -1094,11 +1094,11 @@ 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 - \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere + questi segmenti il kernel mantiene nella \itindex{page~table}\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 \const{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 tab.~\ref{tab:file_mmap_flag}; il valore specificato deve essere compatibile con la modalità di accesso con cui si è aperto il file. @@ -1155,7 +1155,7 @@ tab.~\ref{tab:file_mmap_flag}. memoria disponibile, si ha l'emissione di un \const{SIGSEGV}. \\ \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine - mappate. \\ + mappate.\\ \const{MAP\_GROWSDOWN} & Usato per gli stack. Indica che la mappatura deve essere effettuata con gli indirizzi crescenti verso il basso.\\ @@ -1163,17 +1163,26 @@ tab.~\ref{tab:file_mmap_flag}. argomenti \param{fd} e \param{offset} sono ignorati.\footnotemark\\ \const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\ - \const{MAP\_FILE} & Valore di compatibilità, deprecato.\\ + \const{MAP\_FILE} & Valore di compatibilità, ignorato.\\ + \const{MAP\_32BIT} & Esegue la mappatura sui primi 2GiB dello spazio + degli indirizzi, viene supportato solo sulle + piattaforme \texttt{x86-64} per compatibilità con + le applicazioni a 32 bit. Viene ignorato se si è + richiesto \const{MAP\_FIXED}.\\ + \const{MAP\_POPULATE} & Esegue il \itindex{prefaulting} + \textit{prefaulting} delle pagine di memoria + necessarie alla mappatura. \\ + \const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che + non causa I/O.\footnotemark \\ +% \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area +% mappata con \func{mremap}, proposto ma pare non +% implementato.\\ \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 \const{MAP\_SHARED} è - stato implementato in Linux a partire dai kernel della serie 2.4.x.} Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere piuttosto complessi, essi si possono comprendere solo tenendo presente che @@ -1184,14 +1193,6 @@ sola lettura si avr (\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non consentono questo tipo di accesso. -\begin{figure}[!htb] - \centering - \includegraphics[width=10cm]{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} -\end{figure} - È invece assai diversa la questione relativa agli accessi al di fuori della regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe ritenere che anch'essi debbano generare un segnale di violazione di accesso; @@ -1199,11 +1200,30 @@ questo per paginazione\index{paginazione}, la mappatura in memoria non può che essere eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una pagina, ed in generale queste potranno non corrispondere alle dimensioni -effettive del file o della sezione che si vuole mappare. Il caso più comune è -quello illustrato in fig.~\ref{fig:file_mmap_boundary}, in cui la sezione di -file non rientra nei confini di una pagina: in tal caso verrà il file sarà -mappato su un segmento di memoria che si estende fino al bordo della pagina -successiva. +effettive del file o della sezione che si vuole mappare. + +\footnotetext[20]{Dato che tutti faranno riferimento alle stesse pagine di + memoria.} +\footnotetext[21]{L'uso di questo flag con \const{MAP\_SHARED} è + stato implementato in Linux a partire dai kernel della serie 2.4.x.} + +\footnotetext{questo flag ed il precedente \const{MAP\_POPULATE} sono stati + introdotti nel kernel 2.5.46 insieme alla mappatura non lineare di cui + parleremo più avanti.} + +\begin{figure}[!htb] + \centering + \includegraphics[width=10cm]{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} +\end{figure} + + +Il caso più comune è quello illustrato in fig.~\ref{fig:file_mmap_boundary}, +in cui la sezione di file non rientra nei confini di una pagina: in tal caso +verrà il file sarà mappato su un segmento di memoria che si estende fino al +bordo della pagina successiva. In questo caso è possibile accedere a quella zona di memoria che eccede le dimensioni specificate da \param{lenght}, senza ottenere un \const{SIGSEGV} @@ -1217,14 +1237,6 @@ file mappato sono pi file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a quella della mappatura in memoria. -\begin{figure}[htb] - \centering - \includegraphics[width=10cm]{img/mmap_exceed} - \caption{Schema della mappatura in memoria di file di dimensioni inferiori - alla lunghezza richiesta.} - \label{fig:file_mmap_exceed} -\end{figure} - In questa situazione, per la sezione di pagina parzialmente coperta dal contenuto del file, vale esattamente quanto visto in precedenza; invece per la parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non @@ -1242,6 +1254,14 @@ sez.~\ref{sec:file_vfs_work}). Si tenga presente per di dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe) che sono utilizzabili solo con questa interfaccia. +\begin{figure}[htb] + \centering + \includegraphics[width=10cm]{img/mmap_exceed} + \caption{Schema della mappatura in memoria di file di dimensioni inferiori + alla lunghezza richiesta.} + \label{fig:file_mmap_exceed} +\end{figure} + Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene copiato integralmente, i file mappati in memoria verranno ereditati in maniera trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel @@ -1293,8 +1313,9 @@ memoria mappata con il file su disco; il suo prototipo \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}] O \param{start} non è multiplo di \const{PAGESIZE}, - o si è specificato un valore non valido per \param{flags}. + \item[\errcode{EINVAL}] O \param{start} non è multiplo di + \const{PAGE\_SIZE}, o si è specificato un valore non valido per + \param{flags}. \item[\errcode{EFAULT}] L'intervallo specificato non ricade in una zona precedentemente mappata. \end{errlist} @@ -1365,9 +1386,82 @@ Indicare un intervallo che non contiene pagine mappate non 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 è: +\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);} + + Restringe o allarga una mappatura in memoria di un file. + + \bodydesc{La funzione restituisce l'indirizzo alla nuova area di memoria in + caso di successo od il valore \const{MAP\_FAILED} (pari a \texttt{(void *) + -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 + 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ò + 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}. + + \itindend{memory~mapping} + \section{Il file locking} \label{sec:file_locking} diff --git a/img/mmap_boundary.dia b/img/mmap_boundary.dia index 29956d3..8160a80 100644 Binary files a/img/mmap_boundary.dia and b/img/mmap_boundary.dia differ diff --git a/img/mmap_exceed.dia b/img/mmap_exceed.dia index 8630e39..3b53196 100644 Binary files a/img/mmap_exceed.dia and b/img/mmap_exceed.dia differ diff --git a/ipc.tex b/ipc.tex index dc314c7..839f9da 100644 --- a/ipc.tex +++ b/ipc.tex @@ -2480,7 +2480,7 @@ un segmento di memoria condivisa \const{IPC\_RMID} senza i permessi necessari. \item[\errcode{EOVERFLOW}] Si è tentato il comando \const{IPC\_STAT} ma il valore del group-ID o dell'user-ID è troppo grande per essere - memorizzato nella struttura puntata dal \param{buf}. + memorizzato nella struttura puntata da \param{buf}. \item[\errcode{EFAULT}] L'indirizzo specificato con \param{buf} non è valido. \end{errlist} @@ -3364,7 +3364,7 @@ di messaggi POSIX di successo e -1 in caso di errore; nel quel caso \var{errno} assumerà i valori: \begin{errlist} - \item[\errcode{EACCESS}] Il processo non ha i privilegi per accedere al + \item[\errcode{EACCES}] Il processo non ha i privilegi per accedere al alla memoria secondo quanto specificato da \param{oflag}. \item[\errcode{EEXIST}] Si è specificato \const{O\_CREAT} e \const{O\_EXCL} ma la coda già esiste. diff --git a/process.tex b/process.tex index 37ef2d0..1166f51 100644 --- a/process.tex +++ b/process.tex @@ -294,21 +294,21 @@ virtuale di tutti i processi che hanno detta funzione nel loro codice. La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale e quelle della memoria fisica della macchina viene gestita in maniera -trasparente dall'hardware di gestione della memoria (la \textit{Memory - Management Unit} del processore). Poiché in genere la memoria fisica è solo -una piccola frazione della memoria virtuale, è necessario un meccanismo che -permetta di trasferire le pagine che servono dal supporto su cui si trovano in -memoria, eliminando quelle che non servono. Questo meccanismo è detto -\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei -compiti principali del kernel. +trasparente dal kernel con l'ausilio dell'hardware di gestione della memoria +(la \textit{Memory Management Unit} del processore). Poiché in genere la +memoria fisica è solo una piccola frazione della memoria virtuale, è +necessario un meccanismo che permetta di trasferire le pagine che servono dal +supporto su cui si trovano in memoria, eliminando quelle che non servono. +Questo meccanismo è detto \textsl{paginazione}\index{paginazione} (o +\textit{paging}), ed è uno dei compiti principali del kernel. Quando un processo cerca di accedere ad una pagina che non è nella memoria reale, avviene quello che viene chiamato un \textit{page - fault}\itindex{page~fault}; l'hardware di gestione della memoria genera -un'interruzione e passa il controllo al kernel il quale sospende il processo e -si incarica di mettere in RAM la pagina richiesta (effettuando tutte le -operazioni necessarie per reperire lo spazio necessario), per poi restituire -il controllo al processo. + fault}\itindex{page~fault}; la gestione della memoria genera un'interruzione +e passa il controllo al kernel il quale sospende il processo e si incarica di +mettere in RAM la pagina richiesta (effettuando tutte le operazioni necessarie +per reperire lo spazio necessario), per poi restituire il controllo al +processo. Dal punto di vista di un processo questo meccanismo è completamente trasparente, e tutto avviene come se tutte le pagine fossero sempre