View Single Post
Old 07-01-2005, 15:56   #11
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Citt: Roma
Messaggi: 15625
Le tecniche di allocazione della memoria

Negli esempi precedenti ho utilizzato le funzioni kmalloc (o kzalloc)/kfree e vmalloc/vfree senza dare particolari spiegazioni. E' ora di ritornare sull'argomento.

Consiglio di leggere questo articolo per avere una idea pi precisa di come funzionano le cose:
http://www.csn.ul.ie/~mel/projects/v...ml/understand/
Va ben oltre quello che pu interessarvi, ma vale la pena leggerlo. nb Non tratta le tabelle di pagina di quarto livello (page upper directory, PUD), introdotte recentemente.

- Struttura della memory map del kernel:
Il kernel risiede nell'ultimo GB di memoria, da 0xc0000000 (PAGE_OFFSET) in poi. I 3 GB precedenti sono riservati per lo user space. E' possibile effettuare mappature diverse (io ad es. ho usato 2.5/1.5), oppure la totale separazione 4/4, ma il concetto lo stesso.
Questo il layout di indirizzi, visto dal kernel linux:

http://spazioinwind.libero.it/ilsens...ages/img18.png

La RAM fisica divisa in tre zone: zona DMA "legacy", corrispondente ai primi 16MB di indirizzi fisici (utilizzata dai vecchi dispositivi ISA che potevano fare DMA solo in questi indirizzi); la zona NORMAL (utilizzabile anche per DMA a 32 bit), e la zona HIGHMEM. Le prime due zone sono permanentemente mappate in memoria: ovvero il kernel ha gi indirizzi virtuali che corrispondono agli indirizzi fisici di queste regioni. La zona HIGHMEM invece mappata, dinamicamente, solo quando necessario.
Per ogni pagina di memoria il kernel tiene una piccola struttura (struct page; v. linux/mm.h) ordinate nell'array mem_map. La funzione page_address(page) restituisce l'indirizzo di una pagina, se mappata (come accade per le zone NORMAL o DMA).
Le pagine sono gestite, al livello pi basso, dal buddy allocator. Questo signore gestisce la memoria in pagine (la dimensione di una pagina 4kb su x86), raggruppandole in blocchi contigui composti da un numero potenza di due di pagine.

Per richiedere delle pagine al buddy allocator si possono usare le funzioni alloc_pages/free_pages (linux/gfp.h):
Codice:
struct page *alloc_pages(unsigned int gfp_mask, unsigned int order)
dove "order" l'ordine di pagine da allocare (significato: "voglio allocare 2^order di pagine" -- il buddy allocator lavora in potenze di 2), e gfp_mask contiene indicazioni da dove (preferibilmente) prendere le pagine, se l'allocazione deve essere atomica o se possiamo "aspettare un p". Il valore restituito la prima pagina del gruppo allocato. Se le pagine NON appartengono alla zona HIGHMEM, l'indirizzo virtuale corrispondente pu essere ottenuto chiamando la funzione page_address(page). Per le pagine HIGHMEM questo non possibile, in quanto non possiedono mappatura fissa (questo piccolo dettaglio tra i motivi per cui molto complicato per un sistema a 32 bit gestire decine di GB di memoria). Per gli interessati che cercano di accedere a pagine highmem, cercate le funzioni k(un)map[_atomic]. Non abusarne.
Nota importante: la memoria allocata da alloc_pages memoria fisicamente continua. L'ordine massimo MAX_ORDER (da 10 a 11 su x86, a seconda del kernel), che ci consente di allocare fino a PAGE_SIZE*2^MAX_ORDER byte di memoria fisicamente contigua. Per dimensioni superiori, occorrono altre tecniche (ovvero: un casino). La memoria fisicamente contigua importante per operazioni DMA.

Sotto il buddy allocator siede lo slab allocator (v. linux/slab.h e /proc/slabinfo), il cui scopo consentire e gestire l'allocazione di oggetti pi piccoli di una pagina. E' difficile che dobbiate usarlo direttamente.
Allo slab allocator accede la funzione kmalloc, la tecnica preferita di allocazione dentro al kernel: questa funzione consente di allocare velocemente piccole quantit di memoria (tipicamente fino a 128 KB) dalle zone NORMAL o DMA. Si tratta di memoria contigua fisicamente, volendo la si pu usare per operazioni DMA. La sintassi
kmalloc(size, GFP_KERNEL) per le allocazioni normali e
kmalloc(size, GFP_ATOMIC) per le operazioni atomiche (ad es. dentro un irq). Aggiungete GFP_DMA se vi serve memoria dalla zona DMA riservata alle schede legacy.
La variante kzalloc equivalente a kmalloc, ma ritorna memoria gi inizializzata a 0.
*Importante*: E' perfettamente normale (non necessariamente un errore!) che una allocazione atomica possa fallire. Se usare GFP_ATOMIC, siate preparati. O meglio, cercate di evitarle se non indispensabile.

Altra tecnica di allocazione la funzione vmalloc/vfree. Caratteristiche:
- L'allocazione avviene solo per multipli di pagina (chiedete 1 byte, ne sprecate 4095)
- L'allocazione proviene da tutte le zone: non importante se la memoria gi mappata o meno, viene comunque creata una nuova mappatura virtuale.
- La memoria restituita virtualmente contigua, ma non fisicamente
- Pu bloccare: non usare in contesti atomici!
- Pu allocare regioni enormi, da VMALLOC_START a VMALLOC_END. Non esagerare con l'uso: appesantisce le tabelle di pagine.
- E' la funzione pi simile a malloc: ci nonostante, va usata solo quando necessario (nell'esempio sulla mmap ne ho in effetti "abusato").

Direi che non il caso di addentrarsi oltre. Gli interessati possono leggere il link che ho consigliato, dove viene spiegato anche il significato delle regioni kmap e fixed map e tante altre cose.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12

Ultima modifica di ilsensine : 23-02-2006 alle 15:55.
ilsensine  offline