520 likes | 659 Views
Diseño de Sistemas Operativos. Ingeniería en Informática Facultad de Las Palmas de Gran Canaria Curso 2003 - 2004. Sistema de Paginado. Nayarit Santana Pacheco Iván Martín Mesa. I N D I C E T E M A T I C O. Introducción Diagrama General Estructuras de Datos Tabla de Páginas
E N D
Diseño de Sistemas Operativos Ingeniería en Informática Facultad de Las Palmas de Gran Canaria Curso 2003 - 2004 Sistema de Paginado Nayarit Santana Pacheco Iván Martín Mesa
I N D I C E T E M A T I C O • Introducción • Diagrama General • Estructuras de Datos • Tabla de Páginas • Directorio de Páginas • Cachés • Gestión • Asignación y Liberación de páginas • Asignación y Liberación de zonas de memoria (núcleo) • Bloqueo de páginas en memoria • Dispositivos de swap • Tratamiento de Excepciones
I N T R O D U C C I Ó N • Todo proceso tiene asociado un espacio de direccionamiento donde se encuentran las zonas de memoria que le han sido asignadas. • Este espacio se compone de varias regiones de memoria: • código • datos • inicializados • no inicializados • código y datos de las bibliotecas compartidas • pila 0xC0000000 _end _data _etext 0 Espacio de direccionamiento de un proceso
I N T R O D U C C I Ó N Al arrancar un proceso no siempre es necesaria toda la información del mismo PAGINACIÓN BAJO DEMANDA El espacio de cada región de memoria se organiza en páginas para un mejor manejo de la información. Cada región posee una serie de atributos que a su vez heredan las páginas que componen la misma Memoria
DATA CODE I N T R O D U C C I Ó N Los derechos de acceso a la memoria son gestionados directamente por el procesador. Si el proceso modifica los derechos de acceso asociados a una región, el núcleo se encarga de modificar la protección asociada a las páginas que componen la región de memoria afectada. Existen diversas constantes que representan las diferentes protecciones posibles (<sys/mman.h>), y en caso de fallo la variable errno puede tomar distintos valores: Proceso Memoria Mostrar Tablas Núcleo
task_struct mm_struct vm_area_struct mm count DATA pgd mmap mmap_avl mmap_sem vm_next vm_area_struct CODE vm_end vm_start vm_flags vm_inode vm_ops vm_end vm_start vm_flags vm_inode vm_ops vm_next D I A G R A M A G E N E R A L Pagina logica Memoria física MAPPER 0x8059BB8 MEMORIA SECUNDARIA 0x8048000 0x0000000
ESTRUCTURAS DE DATOS - TABLAS DE PAGINAS • Los procesos necesitan direcciones contiguas • DIRECCIONES VIRTUALES • (no tienen porqué ser contiguas en memoria física) • Estas direcciones son utilizadas tanto por los procesos como por el núcleo. • Para acceder a memoria es necesario convertir la dirección virtual en una dirección física. • La dirección virtual se divide en dos partes: • número de página • desplazamiento Dirección virtual Tabla de páginas Dirección física
ESTRUCTURAS DE DATOS - TABLAS DE PAGINAS Dirección virtual El número de página se utiliza como índice de una tabla de páginas y el desplazamiento hace referencia a la posición que ocupa el dato dentro de la página en cuestión. Todos los accesos a memoria se realizan a través de la tabla de páginas y cada proceso tiene una propia. Para que 2 procesos compartan una página, debe aparecer el nº de marco de la página física en sus respectivas tablas de páginas. marco es a memoria física lo que página a memoria virtual Tabla de páginas Dirección física
ESTRUCTURAS DE DATOS - TABLAS DE PAGINAS • La tabla de páginas contiene la siguiente información: • Flag de validación • nº de marco (memoria física) • información de control • Cuando el contenido de una página se altera el núcleo se encarga de actualizar la página correspondiente • TABLA DE DESCRIPTORES • Descriptor Página de memoria Dirección virtual Tabla de páginas Dirección física
ESTRUCTURAS DE DATOS - TABLAS DE PAGINAS • La variable mem_map (mm/memory.c) apunta a esta tabla de descriptores • La estructura page (<linux/mm.h>) define el formato de cada descriptor. Contiene los siguientes campos: • Los valores que puede tomar el campo flags (<linux/mm.h>) de la estructura anterior se muestran en la siguiente tabla: typedef struct page { [...] void *virtual; struct list_head list; Struct address_space *mapping; Unsigned long index; struct page *next_hash, **prev_hash; atomic_t count; unsigned long flags; struct list_head lru; wait_queue_head_t wait; struct zone_struct *zone; } mem_map_t; Mostrar Tabla Mostrar Tabla
CAT PAG DESPLAZAMIENTO Es necesario mantener la tabla de páginas en memoria, sin embargo, dado el espacio de direccionamiento de cada proceso sería imposible. Otro problema que surge con este tipo de tablas tiene que ver con la velocidad. Si la tabla de un proceso es muy grande, acceder a ella ralentizaría la ejecución del mismo. Como solución, Linux descompone la tabla de páginas original en distintos niveles. Este conjunto de tablas se denomina directorio de páginas. PAG OFFSET ESTRUCTURAS DE DATOS - TABLAS DE PAGINAS addr addr
El directorio de tablas de páginas contiene en cada entrada la dirección base de la tabla de páginas correspondiente. Se utilizan los 10 bits de mayor peso de la dirección lineal (31-22) como índice en el directorio. Cada tabla de páginas contiene en cada entrada la dirección base de una página física o marco. Se utilizan los siguientes 10 bits de la dirección lineal (21-12) como índice en la tabla. Los restantes 12 bits de la dirección lineal se utilizan como desplazamiento dentro del marco de página. CAT PAG DESPLAZAMIENTO PAG OFFSET ESTRUCTURAS DE DATOS - DIRECTORIO DE PAGINAS GLOBAL addr addr
Para la arquitectura x86 de Intel, se utiliza una descomposición en dos niveles de las tablas de páginas (figura anterior). Sin embargo, Linux soporta otro tipo de arquitecturas basadas en 3 niveles, por lo que introduce una tabla intermedia para darles soporte. Si la arquitectura pertenece a la familia x86, Linux utiliza la tabla intermedia que contiene un único descriptor. ESTRUCTURAS DE DATOS - DIRECTORIO DE PAGINAS GLOBAL Directorio Intermedio Paginas Memoria fisica
Cada proceso (task_struct) tiene un campo mm de tipo mm_struct que almacena la información de su espacio de direcciones virtual. El campo pgd es del tipo pgd_t: typedef unsigned long pgd_t; Mantiene el directorio de páginas utilizado para resolver la dirección física dada una dirección virtual. Cada mm_struct tiene un conjunto de objetos pgd_t de tamaño PTRS_PER_PGD (1024). task_struct mm_struct mm count pgd mmap mmap_avl mmap_sem ESTRUCTURAS DE DATOS - DIRECTORIO DE PAGINAS GLOBAL
task_struct mm_struct mm count pgd mmap mmap_avl mmap_sem ESTRUCTURAS DE DATOS - DIRECTORIO DE PAGINAS GLOBAL Para localizar una direccion (addr), es necesario saber a que pgd_t pertenece: pgd = mm->pgd[addr >> 22]; y determinar la entrada correspondiente en la table de descriptores intermedia: pmd = (pmd_t *) pgd; Una vez sabemos a qué entrada pmd_t corresponde la dirección, se consulta el último nivel del árbol: un arreglo de PTRS_PER_PTE (1024) objetos de tipo pte_t asociado a la estructura pmd_t: pte = pmd[(addr>>PAGE_SHIFT) & (PTRS_PER_PTE - 1)];
DATA CODE ESTRUCTURAS DE DATOS – CACHÉ DE PÁGINAS • Linux mantiene en memoria una caché de páginas. • Todas las páginas en memoria asociadas a un i-nodo se registran en una lista de hash. Las páginas pueden corresponder a: • código ejecutado por los procesos • contenido de archivos proyectados • en memoria • La caché se gestiona dinámicamente. En caso de que el contenido de una página asociada a un i-nodo deba cargarse en memoria, se asigna una nueva página y se inserta en la caché, leyéndose su contenido desde el disco. Proceso Memoria Disco
DATA CODE ESTRUCTURAS DE DATOS – CACHÉ DE PÁGINAS De esta forma, en los siguientes accesos al contenido de la página, su carga ya no será necesaria, puesto que está presente en memoria. Cuando Linux se encuentra falto de memoria, selecciona páginas para su descarte. Aquellas páginas de la caché que no han tenido accesos desde hace tiempo se descartan. Funciones como page_unuse y try_to_swap_out se emplean con este fin. Linux también utiliza este mecanismo de caché de páginas para las lecturas sobre archivos. Las escrituras de datos y manipulaciones de directorios se efectúan mediante el buffer caché. Proceso Memoria
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S • Linux utiliza el principio del Buddysystem para asignar y liberar eficientemente bloques de páginas. • El núcleo mantiene una lista de grupos de páginas disponibles. • El tamaño de los grupos es fijo, siendo asignados un número de páginas igual a potencias de 2. • 0 Grupos de 1 página • 1 Grupos de 2 páginas • ... • 5 Grupos de 32 páginas • Cada grupo hace referencia a páginas contiguas en memoria.
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S • BUDDY SYSTEM: • Petición de asignación • busca un grupo disponible dentro de la lista que contiene grupos de páginas de tamaño igual o inmediatamente superior al especificado. • El grupo se divide en 2 partes: • tantas páginas como tamaño de • memoria especificado • resto de páginas que continúan • disponibles
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S Las páginas que no son utilizadas se insertan en las otras listas. El tamaño de los grupos es predeterminado. Si sobrasen 24 páginas, se distribuirían en un grupo de 16 y otro de 8. Dentro de cada lista, se comprobaría si el grupo de páginas adyacentes se encuentra disponible, en ese caso se fusionan los grupos y pasan a la lista de grupos de tamaño inmediatamente superior. Así sucesivamente hasta llegar al tope. Este proceso se repite si en vez de ser páginas que sobran de una asignación, son páginas que han sido liberadas.
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S La tabla free_area (mm/page_alloc.c) contiene la dirección del primer descriptor de grupo de páginas para cada tamaño de grupo: La tabla free_area_struct (mm/page_alloc.c) contiene la dirección del primer descriptor de grupo de páginas para cada tamaño de grupo: static struct free_area_struct free_area[NR_MEM_LISTS]; 34536 struct free_area_struct { 34537 struct page *next; 34538 struct page *prev; 34539 unsigned int * map; 34540 }; Mostrar Figura Mostrar Tabla Mostrar Funciones
mem_map mem_map_t mem_map_t map 56 4 mem_map_t map 0 Estructura free_area free_area
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S 382 /* 383 * The old interface name will be removed in 2.5: 384 */ 385 #define get_free_pageget_zeroed_page 409 /* 410 * Common helper functions. 411 */ 412 unsigned long __get_free_pages (unsigned int gfp_mask, unsigned int order) 413 { 414 struct page * page; 415 416 page = alloc_pages(gfp_mask, order); 417 if (!page) 418 return 0; 419 return (unsigned long) page_address(page); 420 } 422 unsigned long get_zeroed_page(unsigned int gfp_mask) 423 { 424 struct page * page; 425 426 page = alloc_pages(gfp_mask, 0); 427 if (page) { 428 void *address = page_address(page); 429 clear_page(address); 430 return (unsigned long) address; 431 } 432 return 0; 433 }
A S I G N A C I Ó N Y L I B E R A C I Ó N D E P Á G I N A S 435 void __free_pages(struct page *page, unsigned int order) 436 { 437 if (!PageReserved(page) && put_page_testzero(page)) 438 __free_pages_ok(page, order); 439 } 441 void free_pages(unsigned long addr, unsigned int order) 442 { 443 if (addr != 0) 444 __free_pages(virt_to_page(addr), order); 445 }
ASIGNACIÓN Y LIBERACION DE ZONAS DE MEMORIA (NÚCLEO) • Linux ofrece 2 tipos de funciones para asignar zonas de memoria del espacio de direccionamiento propio del núcleo: • kmalloc y kfree: páginas contiguas en memoria central • - Útiles para la gestión de zonas pequeñas • - Ineficaces con zonas de grandes tamaños • - bloques de tamaño fijo • vmalloc y vfree: páginas no contiguas en memoria central • - El tamaño de la memoria “desperdiciada” • es menos importante kmalloc y kfree vmalloc y vfree
firstfree bh_next firstfree next ASIGNACIÓN Y LIBERACION DE ZONAS DE MEMORIA (NÚCLEO) En la implementación de kmalloc y kfree, Linux utiliza listas de zonas disponibles. Existe una para cada tamaño de zona. Aunque kmalloc pida un tamaño específico, Linux busca dentro de la lista de tamaño inmediatamente superior. Cada una de las listas lleva asociado un descriptor con la estructura size_descriptor (mm/kmalloc.c) El número de páginas varía según el tamaño de los bloques almacenados en la lista. Como mínimo se establece tantas como sean necesarias para formar un bloque. firstfree Mostrar Tabla Listas de bloques de memoria disponibles
firstfree bh_next firstfree next ASIGNACIÓN Y LIBERACION DE ZONAS DE MEMORIA (NÚCLEO) El inicio de cada grupo de páginas contiene un descriptor con la estructura page_descriptor. Cada grupo de páginas se descompone en una tabla de bloques de tamaño fijo. Al principio de cada bloque se encuentra un descriptor de bloque con la estructura block_header. Mostrar Tabla firstfree Mostrar Tabla Listas de bloques de memoria disponibles
kmalloc y kfree 1577 void kfree (const void *objp) 1578 { 1579 kmem_cache_t *c; 1580 unsigned long flags; 1581 1582 if (!objp) 1583 return; 1584 local_irq_save(flags); 1585 CHECK_PAGE(virt_to_page(objp)); 1586 c = GET_PAGE_CACHE(virt_to_page(objp)); 1587 __kmem_cache_free(c, (void*)objp); 1588 local_irq_restore(flags); 1589 } 1535 void * kmalloc (size_t size, int flags) 1536 { 1537 cache_sizes_t *csizep = cache_sizes; 1538 1539 for (; csizep->cs_size; csizep++) { 1540 if (size > csizep->cs_size) 1541 continue; 1542 return _kmem_cache_alloc(flags & GFP_DMA ? 1543 csizep->cs_dmacachep : csizep->cs_cachep, flags); 1544 } 1545 return NULL; 1546 }
vmalloc y vfree 38753 void vfree(void * addr) 38754 { 38755 struct vm_struct **p, *tmp; 38756 38757 if (!addr) 38758 return; 38759 if ((PAGE_SIZE-1) & (unsigned long) addr) { 38760 printk("Trying to vfree() bad address (%p)\n", addr); 38761 return; 38762 } 38763 for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) { 38764 if (tmp->addr == addr) { 38765 *p = tmp->next; 38766 vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), 38767 tmp->size); 38768 kfree(tmp); 38769 return; 38770 } 38771 } 38772 printk("Trying to vfree() nonexistent vm area (%p)\n", 38773 addr); 38774 } 38776 void * vmalloc(unsigned long size) 38777 { 38778 void * addr; 38779 struct vm_struct *area; 38780 38781 size = PAGE_ALIGN(size); 38782 if (!size || size > (max_mapnr << PAGE_SHIFT)) 38783 return NULL; 38784 area = get_vm_area(size); 38785 if (!area) 38786 return NULL; 38787 addr = area->addr; 38788 if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) { 38789 vfree(addr); 38790 return NULL; 38791 } 38792 return addr; 38793 }
DATA CODE BLOQUEO DE PÁGINAS EN MEMORIA Linux, al arrancar un proceso, evita cargar todas las páginas que forman parte del espacio de direccionamiento de éste utilizando la paginación bajo demanda. De la misma forma, cuando el núcleo necesita memoria central puede decidir liberar aquellas páginas que no han sido utilizadas en un periodo de tiempo, escribiéndolas en memoria secundaria (en caso de haber sido modificadas). Para evitar que un proceso se vea suspendido por el núcleo mientras espera por la carga de sus páginas, Linux permite a los procesos privilegiadosbloquear ciertas páginas en memoria. Existen diversas llamadas al sistema que permiten a un proceso especificar que sus páginas no deben ser descartadas de la memoria. Proceso Memoria Disco
DISPOSITIVOS DE SWAP • Cuando el núcleo necesita memoria resuelve el problema eliminando páginas. Si estas páginas han sido modificadas, será necesario guardarlas en disco: • Archivo proyectado en memoria • se rescribe en el archivo. • Datos • se guarda en un dispositivo swap. • Linux puede llegar a utilizar varios dispositivos swap; por este motivo, cuando se ha de guardar una página, se exploran los dispositivos de swap activos hasta encontrar un lugar donde escribirla. • Funciones utilizadas: • Inicialización de dispositivo • mkswap • Activación de dispositivo • swapon • Desactivación de dispositivo • swapoff • Descartar páginas de la memoria • kswapd
DISPOSITIVOS DE SWAP El núcleo guarda en memoria una lista de dispositivos de swap activos. Utiliza una tabla de descriptores, donde cada posición describe uno de ellos. La estructura de cada descriptor se llama swap_info_struct (<linux/swap.h>) Los campos swap_map y swap_lockmap son utilizados para mantener actualizadas las páginas usadas. Cuando se descarta una página de la memoria, se le asigna una página en un dispositivo swap y la dirección anterior se memoriza para poder recargarla posteriormente. Mostrar Tabla
DISPOSITIVOS DE SWAP Existen varias macroinstrucciones que manipulan estas direcciones (<asm/pgtable.h>) El proceso encargado de descartar páginas de la memoria, kswapd, se lanza al arrancar el sistema y su misión consiste en descartar las páginas inútiles de la memoria. Sólo podrá quitar aquellas que tengan el campo age del descriptor de página a 0. Cuando un dispositivo se desactiva todas las páginas guardadas en él vuelven a cargarse en memoria. Mostrar Tabla
TRATAMIENTO DE EXCEPCIONES Es el procesador (a través del MMU) quien provoca las excepciones en ciertos accesos a memoria: • do_wp_page • do_swap_page • do_no_page • handle_pte_fault • handle_mm_fault • do_page_fault • Acceso incompatible con la protección asociada a una página en memoria. • Acceso a una pagina no presente en memoria. Las funciones usadas en el tratamiento de una excepción se definen en mm/memory.c:
TRATAMIENTO DE EXCEPCIONES La función que se encarga de gestionar las excepciones en la arquitectura x86 es do_page_fault, declarada en el archivo /arch/i386/mm/fault.c Primero obtiene el descriptor de la región de memoria afectada mediante la función find_vma, y luego comprueba el tipo de error: - Si el error lo ha causado una pagina no presente en el segmento de la pila, se llama a la función expand_stack, para aumentar el tamaño de ésta. - Si el error se debe a un acceso en escritura en una region protegida en lectura, el error se señala enviandole al proceso actual la señal SIGSEV. - Si el error es igual al anterior, pero debido a una copia en escritura, se llama a la funcion do_wp_page. - Si el error se debe a una página no presente en memoria, se llama a la función do_no_page, para cargarla.
TRATAMIENTO DE EXCEPCIONES do_wp_page: Gestiona la copia en escritura. Cuando un proceso accede en escritura a una página compartida y protegida en lectura exclusiva, se asigna una nueva página mediante la funcion ___get_free_page, y se comprueba si la página afectada es compartida por varios procesos. En caso afirmativo se copia su contenido en la nueva página, y se inserta en la tabla de páginas del proceso actual a través de set_pte. El número de referencias a la anterior página se decrementa por una llamada a free_page. En el caso de que la página afectada no sea compartida, su protección simplemente se modifica para hacer posible la escritura.
TRATAMIENTO DE EXCEPCIONES 942 static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, 943 unsigned long address, pte_t *page_table, pte_t pte) 944 { 945 struct page *old_page, *new_page; 946 947 old_page = pte_page(pte); 948 if (!VALID_PAGE(old_page)) 949 goto bad_wp_page; 950 951 if (!TryLockPage(old_page)) { 952 int reuse = can_share_swap_page(old_page); 953 unlock_page(old_page); 954 if (reuse) { 955 flush_cache_page(vma, address); 956 establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); 957 spin_unlock(&mm->page_table_lock); 958 return 1; /* Minor fault */ 959 } 960 }
TRATAMIENTO DE EXCEPCIONES do_swap_page: Carga en memoria el contenido de una pagina situada en el espacio de swap. Si una operación swapin está asociada a la región de memoria que contiene la página, se llama a esta función, en caso contrario se llama a la función swap_in. En ambos casos, la página asignada se inserta en el espacio de direccionamiento del proceso actual.
TRATAMIENTO DE EXCEPCIONES 1111 static int do_swap_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, 1113 pte_t * page_table, pte_t orig_pte, int write_access) 1114 { 1115 struct page *page; 1116 swp_entry_t entry = pte_to_swp_entry(orig_pte); 1117 pte_t pte; 1118 int ret = 1; 1119 1120 spin_unlock(&mm->page_table_lock); 1121 page = lookup_swap_cache(entry); 1122 if (!page) { 1123 swapin_readahead(entry); 1124 page = read_swap_cache_async(entry); 1125 if (!page) { 1126 /* 1127 * Back out if somebody else faulted in this pte while 1128 * we released the page table lock. 1129 */ 1130 int retval; 1131 spin_lock(&mm->page_table_lock); 1132 retval = pte_same(*page_table, orig_pte) ? -1 : 1; 1133 spin_unlock(&mm->page_table_lock); 1134 return retval; 1135 } 1136 ret = 2; 1137 }
TRATAMIENTO DE EXCEPCIONES do_no_page: Acceso a una página no presente en memoria. Se comprueba si la pagina ha sido descartada de la memoria y esta en el espacio swap: - do_swap_page En caso negativo se comprueba si existe una operación de memoria nopage asociada a la región que contiene la página. En caso afirmativo se usa esta operación para cargar enl contenido en memoria, insertando la paigna en la tabla de páginas correspondiente. En caso negativo se asigna una nueva pagina rellenada con 0’s, mediante la función ___get_free_page.
TRATAMIENTO DE EXCEPCIONES 239 static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, 1240 unsigned long address, int write_access, pte_t *page_table) { 1242 struct page * new_page; 1243 pte_t entry; 1245 if (!vma->vm_ops || !vma->vm_ops->nopage) 1246 return do_anonymous_page(mm, vma, page_table, write_access, address); 1247 spin_unlock(&mm->page_table_lock); 1249 new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, 0); 1251 if (new_page == NULL) return 0; 1253 if (new_page == NOPAGE_OOM) return -1; 1259 if (write_access && !(vma->vm_flags & VM_SHARED)) { 1260 struct page * page = alloc_page(GFP_HIGHUSER); 1261 if (!page) { 1262 page_cache_release(new_page); 1263 return -1; } … … 1265 copy_user_highpage(page, new_page, address); 1266 page_cache_release(new_page); 1267 lru_cache_add(page); 1268 new_page = page; } 1271 spin_lock(&mm->page_table_lock); 1299 update_mmu_cache(vma, address, entry); 1300 spin_unlock(&mm->page_table_lock); 1301 return 2; /* Major fault */ 1302 }