Sophie

Sophie

distrib > Mandriva > 9.1 > i586 > by-pkgid > f1098342ec4a2b28475e34123ce17201 > files > 516

howto-html-it-9.1-0.5mdk.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE>KernelAnalysis-HOWTO: Gestione della Memoria su Linux</TITLE>
 <LINK HREF="KernelAnalysis-HOWTO-8.html" REL=next>
 <LINK HREF="KernelAnalysis-HOWTO-6.html" REL=previous>
 <LINK HREF="KernelAnalysis-HOWTO.html#toc7" REL=contents>
</HEAD>
<BODY>
<A HREF="KernelAnalysis-HOWTO-8.html">Next</A>
<A HREF="KernelAnalysis-HOWTO-6.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc7">Contents</A>
<HR>
<H2><A NAME="s7">7. Gestione della Memoria su Linux</A></H2>

<H2><A NAME="ss7.1">7.1 Introduzione</A>
</H2>

<P>Linux usa la segmentazione paginata che semplifica molto la notazione.
<H3>Segmenti</H3>

<P>Vengono utilizzati soltanto 4 segmenti:
<P>
<UL>
<LI>2 segmenti (codice e dati/stack) per il KERNEL MODE da [0xC000
0000] (3 GB) a [0xFFFF FFFF] (4 GB)</LI>
<LI>2 segmenti (codice e dati/stack) per lo USER MODE da [0]
(0 GB) a [0xBFFF FFFF] (3 GB)</LI>
</UL>
<P>
<PRE>
                               __
   4 GB---&gt;|                |    |
           |     Kernel     |    |  Kernel Mode (Codice + Dati/Stack)
           |                |  __|
   3 GB---&gt;|----------------|  __
           |                |    |
           |                |    |
   2 GB---&gt;|                |    |
           |     Tasks      |    |  User Mode (Codice + Dati/Stack)
           |                |    |
   1 GB---&gt;|                |    |
           |                |    |
           |________________|  __| 
 0x00000000
          Indirizzi Lineari Kernel/User
 
</PRE>
<H2><A NAME="ss7.2">7.2 Implementazione 386+</A>
</H2>

<P>Linux implementa la Paginazione usando 3 Levelli di Pagine, ma
su architettura 386+ solo 2 sono effettivamente utilizzati:
<P>
<PRE>
 
   -----------------------------------------------------------------
   I   N   D   I   R   I   Z   Z   I       L   I   N   E   A   R   I
   -----------------------------------------------------------------
        \___/                 \___/                     \_____/ 
 
     PD offset              PF offset                 Frame offset 
     [10 bits]              [10 bits]                 [12 bits]       
          |                     |                          |
          |                     |     -----------          |        
          |                     |     | Valore  |----------|---------
          |     |         |     |     |---------|   /|\    |        |
          |     |         |     |     |         |    |     |        |
          |     |         |     |     |         |    | Frame offset |
          |     |         |     |     |         |   \|/             |
          |     |         |     |     |---------|&lt;------            |
          |     |         |     |     |         |      |            |
          |     |         |     |     |         |      | x 4096     |
          |     |         |  PF offset|_________|-------            |
          |     |         |       /|\ |         |                   |
      PD offset |_________|-----   |  |         |          _________|
            /|\ |         |    |   |  |         |          | 
             |  |         |    |  \|/ |         |         \|/
 _____       |  |         |    ------&gt;|_________|   INDIRIZZO FISICO 
|     |     \|/ |         |    x 4096 |         |
| CR3 |--------&gt;|         |           |         |
|_____|         | ....... |           | ....... |
                |         |           |         |    
 
               Page Directory          Page File

                       Paginazione su 386+
 

</PRE>
<H2><A NAME="ss7.3">7.3 Mappatura Memory</A>
</H2>

<P>Linux gestisce il Controllo di Accesso soltanto sulla Paginazione,
quindi Tasks differenti possono condividere lo stesso indirizzo di
Segmento ma, avendo differenti valori nel registro CR3 (usato per
puntare alla Page Directory), puntano effettivamente a differenti
Pagine.
<P>In User mode un Task non puo' superare il limite di 3 GB (0 x
C0 00 00 00), quindi soltanto le prime 768 page directories hanno
senso (768*4MB = 3GB, perche' ogni page directory e' grande 4MB).
<P>Quando un Task entra in Kernel Mode (tramite System call o IRQ)
le altre 256 pages directories sono effettivamente utilizzate e sono
in comune rispetto a tutti gli altri Tasks (quindi sempre le stesse
aree di memoria).
<P>Si noti che lo Spazio Lineare del Kernel (e soltanto del Kernel)
e' uguale allo Spazio Fisico, cosicche':
<P>
<PRE>
 
            ________________ _____                    
           |Altri Dati Kernel|___  |  |                   |
           |-----------------|   | |__|                   |
           |     Kernel      |\  |____|   Spazio Reale    |
  3 GB ---&gt;|-----------------| \      | Altri Dati Kernel |
           |                 |\ \     |                   |
           |              ___|_\_\____|__   Spazio        |
           |      Tasks      |  \ \   |     Reale         |
           |              ___|___\_\__|__   Tasks         |
           |                 |    \ \ |                   |
           |                 |     \ \|-------------------|
           |                 |      \ |Spazio Reale Kernel|
           |_________________|       \|___________________|
      
           Indirizzi Logici          Indirizzi Fisici
 
</PRE>
<P>Lo Spazio Lineare del Kernel corrisponde allo Spazio Fisico traslato
di 3 GB in basso (infatti le page tables sono del tipo { "00000000",
"00000001" }, di modo che possano lavorare senza virtualizzazione,
riportando semplicemente il valore lineare su quello fisico).
<P>Si noti come non esista neanche conflitto tra gli indirizzi fisici
Kernel e quelli User perche' il Kernel ha un'allocazione di tipo
statica (quindi conosciamo subito dove piazzare i dati): per quanto
riguarda i moduli o i dati aggiuntivi, basta scegliere i valori in
modo tale che non vadano in conflitto con le Page Tables gia' presenti
dello User Mode.
<H2><A NAME="ss7.4">7.4 Allocazione della memoria a basso livello</A>
</H2>

<H3>Inizializzazione di Avvio</H3>

<P>Si parte dalla funzione ''kmem_cache_init'' (lanciata da start_kernel
[init/main.c] all'avvio):
<P>
<PRE>
|kmem_cache_init
   |kmem_cache_estimate
</PRE>
<P>
<UL>
<LI>kmem_cache_init [mm/slab.c]</LI>
<LI>kmem_cache_estimate</LI>
</UL>
<P>Continuiamo con ''mem_init'' (anch'essa lanciata da start_kernel[init/main.c])
<P>
<PRE>
|mem_init
   |free_all_bootmem
      |free_all_bootmem_core
</PRE>
<P>
<UL>
<LI>mem_init [arch/i386/mm/init.c]</LI>
<LI>free_all_bootmem [mm/bootmem.c]</LI>
<LI>free_all_bootmem_core</LI>
</UL>
<H3>Allocazione Run-time</H3>

<P>Su Linux, quando vogliamo allocate memoria, ad esempio durante
la "copy_on_write" (si veda il Cap.10), chiamiamo:
<P>
<PRE>
|copy_mm 
   |allocate_mm = kmem_cache_alloc
      |__kmem_cache_alloc
         |kmem_cache_alloc_one
            |alloc_new_slab
               |kmem_cache_grow
                  |kmem_getpages
                     |__get_free_pages
                        |alloc_pages
                           |alloc_pages_pgdat
                              |__alloc_pages
                                 |rmqueue   
                                 |reclaim_pages
</PRE>
<P>
<UL>
<LI>copy_mm [kernel/fork.c]</LI>
<LI>allocate_mm [kernel/fork.c]</LI>
<LI>kmem_cache_alloc [mm/slab.c]</LI>
<LI>__kmem_cache_alloc </LI>
<LI>kmem_cache_alloc_one</LI>
<LI>alloc_new_slab</LI>
<LI>kmem_cache_grow</LI>
<LI>kmem_getpages</LI>
<LI>__get_free_pages [mm/page_alloc.c]</LI>
<LI>alloc_pages [mm/numa.c]</LI>
<LI>alloc_pages_pgdat</LI>
<LI>__alloc_pages [mm/page_alloc.c]</LI>
<LI>rm_queue</LI>
<LI>reclaim_pages [mm/vmscan.c]</LI>
</UL>
<P>DAFARE: Capire le Zone
<H2><A NAME="ss7.5">7.5 Swapping</A>
</H2>

<H3>Introduzione</H3>

<P>Lo Swapping viene gestito dal demone ''kswapd'' (Kernel Thread).
<H3>kswapd</H3>

<P>Come tutti i Kernel Threads, ''kswapd'' ha un ciclo principale
in attesa di essere svegliato.
<P>
<PRE>
|kswapd
   |// routines di inizializzazione
   |for (;;) { // Ciclo principale
      |do_try_to_free_pages
      |recalculate_vm_stats
      |refill_inactive_scan
      |run_task_queue
      |interruptible_sleep_on_timeout // In attesa di essere svegliati
   |}
</PRE>
<P>
<UL>
<LI>kswapd [mm/vmscan.c]</LI>
<LI>do_try_to_free_pages</LI>
<LI>recalculate_vm_stats [mm/swap.c]</LI>
<LI>refill_inactive_scan [mm/vmswap.c]</LI>
<LI>run_task_queue [kernel/softirq.c]</LI>
<LI>interruptible_sleep_on_timeout [kernel/sched.c]</LI>
</UL>
<H3>Quando abbiamo bisogno dello swapping?</H3>

<P>Lo Swapping e' necessario quando dobbiamo accedere ad una pagina
che non e' presente in memoria fisica: il tutto viene scatenato da
un'eccezione (generata dall'accesso non autorizzato):
<P>
<PRE>
 | Page Fault Exception
 | cause by all these conditions: 
 |   a-) User page 
 |   b-) Read or write access 
 |   c-) Page not present
 |
 |
 -----------&gt; |do_page_fault
                 |handle_mm_fault
                    |pte_alloc 
                       |pte_alloc_one
                          |__get_free_page = __get_free_pages
                             |alloc_pages
                                |alloc_pages_pgdat
                                   |__alloc_pages
                                      |wakeup_kswapd // Svegliamo kswapd
   
                   Page Fault ICA
 
</PRE>
<P>
<UL>
<LI>do_page_fault [arch/i386/mm/fault.c] </LI>
<LI>handle_mm_fault [mm/memory.c]</LI>
<LI>pte_alloc</LI>
<LI>pte_alloc_one [include/asm/pgalloc.h]</LI>
<LI>__get_free_page [include/linux/mm.h]</LI>
<LI>__get_free_pages [mm/page_alloc.c]</LI>
<LI>alloc_pages [mm/numa.c]</LI>
<LI>alloc_pages_pgdat</LI>
<LI>__alloc_pages</LI>
<LI>wakeup_kswapd [mm/vmscan.c]</LI>
</UL>
<HR>
<A HREF="KernelAnalysis-HOWTO-8.html">Next</A>
<A HREF="KernelAnalysis-HOWTO-6.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc7">Contents</A>
</BODY>
</HTML>