Sophie

Sophie

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

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">Avanti</A>
<A HREF="KernelAnalysis-HOWTO-6.html">Indietro</A>
<A HREF="KernelAnalysis-HOWTO.html#toc7">Indice</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">Avanti</A>
<A HREF="KernelAnalysis-HOWTO-6.html">Indietro</A>
<A HREF="KernelAnalysis-HOWTO.html#toc7">Indice</A>
</BODY>
</HTML>