Gestión de la memoria El subsistema de gestión de memoria es una de las partes más importantes del sistema operativo. Desde los inicios de la informática,

Slides:



Advertisements
Presentaciones similares
III - Gestión de memoria
Advertisements

Conocimiento, Uso y Evaluación de Medicamentos Genéricos
DATSI, FI, UPM José M. Peña Programación en C DATSI, FI, UPM José M. Peña Programación en C.
Los números del 0 al cero uno dos tres cuatro cinco 6 7 8
Administración de memoria
Universidad San Martín de Porres
1 LA UTILIZACION DE LAS TIC EN LAS MICROEMPRESAS GALLEGAS. AÑO mayo 2005.
1 LA UTILIZACION DE LAS TIC EN LAS PYMES GALLEGAS AÑO de Junio de 2005.
TEMA 2 MÚLTIPLOS Y DIVISORES
02- Plan Organización Docente v.2 Noviembre 2009 SIES – SISTEMA INTEGRADO DE EDUCACIÓN SUPERIOR.
01- OFERTA FORMATIVA v.2 Noviembre 2009 SIES – SISTEMA INTEGRADO DE EDUCACIÓN SUPERIOR.
Aladdín-respuestas 1.Vivía 2.Era 3.Amaba 4.Quería 5.Gustaban 6.Se sentía 7.Salía 8.Tenía 9.Decidió 10.escapó 11. Se vistió 12. Conoció 13. Vio 14. Pensó
Respuestas Buscando a Nemo.
Objetivo: Los estudiantes van a usar vocabulario del desayuno para comprender un cuento. Práctica: 1. ¿Te gusta comer? 2. ¿Te gusta beber Mt. Dew.
SISTEMAS OPERATIVOS GESTION DE MEMORIA INTEGRANTES Lizeth Chandi
Fernando Escribano Pro 1º de Bachillerato
Mulán /75 puntos. 1.Querían 2.Gustaban 3.Escuchó 4.Dijo 5.Tenía 6.Ayudaron 7.Maquillaron 8.Arreglaron 9.Dio 10.Estaba 11.Iba 12.Quería 13.Salió 14.Gritó
CLASE 3 SOFTWARE DEL MICROPROCESADOR
60 razones para seguir vivo
William Shakespeare ( greg.), fue un dramaturgo, poeta y actor inglés. Conocido en ocasiones como el Bardo de Avon (o.
TELEFONÍA IP.
EQUIPO ·# 3 SISTEMAS OPERATIVOS
Parte 3. Descripción del código de una función 1.
Vocabulario querer comerlo -paja por supuesto - madera
FUNCIONES DE UNA VARIABLE REAL
Indicadores CNEP Escuela
Introducción a los Sistemas Operativos Memoria Virtual
Ecuaciones Cuadráticas
Concepto de programa. Directorio Concepto de programa. Analisis del problema. Resolucion del problema. Desarroollo de un programa. Partes constitutivas.
¡Primero mira fijo a la bruja!
Informática II Prof. Dr. Gustavo Patiño MJ
Informática II 1 Diego Fernando Serna RestrepoSemestre 2011/2.
¿Qué es un conjunto? Un conjunto es una colección de objetos considerada como un todo. Los objetos de un conjunto son llamados elementos o miembros del.
Tema II Unidad de memoria. 2 Unidad de memoria 2.1 Definiciones y conceptos básicos Localización Capacidad Unidad de transferencia
SISTEMAS OPERATIVOS UNIDAD 1..
Programación en Lenguaje Ensamblador.
¿Qué es un PUNTERO?: Un puntero es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la dirección de memoria de otra variable. No.
Teoría de Sistemas Operativos
Almacenamiento y Recuperación de la Información 2do Semestre 2005 Wenceslao Palma M.
Estructuras de control
Herramienta FRAX Expositor: Boris Inturias.
Paginación-Segmentación Fundamentos Translación de Direcciones Tabla de páginas Segmentación Emely Arráiz Ene-Mar 08.
HILOS Y COMUNICACIÓN ENTRE PROCESOS
Práctica 7 AOC. Gestión de la pila Una pila es una estructura de datos caracterizada por que el último dato que se almacena es el primero que se obtiene.
Tema 10: Gestión de Memoria
Administración de memoria
Semana 5 Subprogramas..
PAGINACIÓN Y SEGMENTACIÓN
Archivos.
Administración de Memoria Memoria Virtual
Sistema de archivos Sistemas operativos.
Tema 10.3: Asignación de Espacio No Contiguo. Tema 10.3: 2 Silberschatz, Galvin and Gagne ©2005 Fundamentos de los Computadores (ITT, Sist. Electr.),
Asignación de Espacio No Contiguo
Soporte HW para Administración de Memoria Cecilia Hernández
Estructura del sistema de Archivos de
Archivos Programación I MC Beatriz Beltrán Martínez.
Gestión de procesos Sistemas Operativos Edwin Morales
Tema VII Memoria Virtual.
1 Descripción y control de procesos Capítulo 3. 2 Requerimientos de un SO relacionados con procesos Ejecutar concurrentemente múltiples procesos para.
Memoria virtual.
Breve introducción a la arquitectura de 32 bits intel.
CONCEPTOS FUNDAMENTALES DEL NIVEL DEL SISTEMA OPERATIVO
Breve introducción a la arquitectura de 32 bits intel.
Sistemas de Archivos Sistemas Operativos.  Se debe proporcionar un almacenamiento secundario que respalda a la memoria principal  El Sistema de archivos.
Teoría de Sistemas Operativos Memoria Departamento de Electrónica 2º Semestre, 2003 Gabriel Astudillo Muñoz
INTERRUPCIONES – ABRAZO MORTAL
Metodología de Programación Ayudantía 4 lelagos.ublog.cl 2009.
MEMORIA DINÁMICA.
Gestión de Memoria – Parte 2
P ROCESO DE E NSAMBLADO Cámara Vázquez Berenice Rubí.
Transcripción de la presentación:

Gestión de la memoria El subsistema de gestión de memoria es una de las partes más importantes del sistema operativo. Desde los inicios de la informática, ha existido la necesidad de utilizar más memoria de la que se dispone físicamente en el sistema. Entre las diversas estrategias desarrolladas para resolver este problema, la de mayor éxito ha sido la memoria virtual. 2

Gestión de la memoria La memoria virtual hace que parezca que el sistema dispone de más memoria de la que realmente tiene, compartiéndola entre los distintos procesos conforme la necesitan. El subsistema de gestión de memoria ofrece: Espacio de direcciones grande: El sistema operativo hace que el sistema parezca tener una gran cantidad de memoria. Protección: Cada proceso del sistema tiene su propio espacio de direcciones virtuales. 3

Gestión de la memoria Proyección en Memoria (Memory Mapping): La proyección de memoria se utiliza para asignar un fichero sobre el espacio de direcciones de un proceso. Asignación Equitativa de Memoria Física: El subsistema de gestión de memoria permite que cada proceso del sistema se ejecute con una cantidad de memoria justa de toda la memoria física disponible Memoria virtual compartida: Hay veces que es necesario que varios procesos compartan memoria. El subsistema de memoria realiza esta tarea con gran facilidad. 4

Memoria virtual Un proceso no utiliza todo el código y los datos contenidos en su memoria virtual dentro de un periodo de tiempo determinado. No sería deseable cargar todo su código y datos en la memoria física donde podría terminar sin usarse. Para solventar este problema, Linux usa una técnica llamada Paginación Por Demanda que sólo copia la memoria virtual de un proceso en la memoria física del sistema cuando el proceso trata de utilizarla. 5

Memoria virtual Linux necesita gestionar todas estas áreas de memoria virtual. El contenido de la memoria virtual de cada proceso se describe mediante una estructura mm_struct a la cual se apunta desde la estructura task_struct del proceso. La estructura mm_struct contiene punteros a una lista de estructuras vm_area_struct, cada una de las cuales representa un área de memoria virtual dentro del proceso. 6

Memoria virtual 7

Memoria virtual Cuando un proceso reserva memoria virtual, en realidad Linux no reserva memoria física para el proceso. Lo que hace es describir la memoria virtual creando una nueva estructura vm_area_struct. Ésta se une a la lista de memoria virtual del proceso. Cuando el proceso intenta acceder a una dirección virtual dentro de la nueva región de memoria, el sistema emitirá un fallo de página (al no encontrar la entrada en la tabla de páginas del proceso). La tarea de Linux es cargar la página deseada a partir de la información contenida en dicha región. 8

Modelo abstracto de memoria virtual Cada una de estas páginas tiene asociado un único número; el número de marco de página (PFN: Page Frame Number). En este modelo de paginación (suponiendo una arquitectura de 32 bits como x86), una dirección virtual está compuesta por dos partes: un número de página virtual (20 bits) y un desplazamiento (12 bits). Cada vez que el procesador encuentra una dirección virtual ha de extraer el desplazamiento y el número de marco de página. 9

Modelo abstracto de memoria virtual Una tabla de páginas teórica contiene la siguiente información: Flag de Válido: indica si la entrada de la tabla de páginas es válida o no. El número de marco de página físico: indica la página física a la que está asociada. Información de control de acceso: Describe cómo se puede utilizar la página. ¿Se puede leer? ¿Contiene código ejecutable? 10

Modelo abstracto de memoria virtual 11

Intercambio (swapping) Si un proceso necesita cargar una página en memoria física y no hay ninguna página física libre, el sistema operativo tiene que crear espacio para la nueva página eliminando alguna otra página de memoria física. Si la página a descartar no se ha modificado, no es necesario guardarla. Simplemente, se puede desechar. Si ha sido modificada, su contenido debe preservarse para accesos posteriores. Esta página ha de guardarse en un fichero de swap. 12

Memoria compartida Con los mecanismos de memoria virtual se puede conseguir fácilmente que varios procesos compartan memoria. Todos los accesos a memoria se realizan a través de las tablas de páginas y cada proceso tiene su propia tabla de páginas. Para que 2 procesos compartan una misma página de memoria física, simplemente, debe aparecer el número de marco de esa página física en sus tablas de páginas. 13

Control de acceso Las entradas de la tabla de páginas también contienen información relativa al control de acceso. Además de la información almacenada en las entradas de la tabla de páginas, también existe información de acceso en los descriptores de las regiones de memoria virtual (VMA). Se puede utilizar fácilmente la información de control de acceso para comprobar que el proceso no está accediendo a memoria de forma inapropiada. 14

Control de acceso En un procesador x86 una entrada de la tabla de páginas contiene, además de la base de la dirección de una página, algunos flags que indican entre otras cosas que operaciones se pueden aplicar sobre la página. En una arquitectura de 32 bits con tamaño de página fijo de 4Kbytes (como en x86) sólo se necesitan los 20 bits de mayor peso de los 32 bits que componen una dirección para identificar la base de una página. Por tanto los 12 bits restantes se aprovechan para almacenar información importante acerca de la página. 15

Control de acceso A continuación se muestran los flags más importantes que se almacenan en la tabla de páginas para cada entrada: _PAGE_PRESENT: Activo si la página está físicamente en memoria. _PAGE_RW: 0 si la página es sólo de lectura y 1 si es de lectura-escritura (no existen páginas sólo de escritura). _PAGE_USER: Activo si la página pertenece al espacio de usuario e inactivo si pertenece al núcleo. 16

Control de acceso _PAGE_WT: Indica la política de caché de la página. writethrought (0): Actualiza inmediatamente los datos escritos en la caché en memoria principal. writeback (1): Sólo se actualizan los cambios escritos en la memoria caché en la memoria principal cuando la línea de caché va a ser sustituida. _PAGE_ACCESSED: Activo si la página ha sido accedida recientemente. _PAGE_DIRTY: Activo si la página ha sido modificada. 17

Cachés Linux emplea varias cachés para la gestión de la memoria. Estas cachés son las siguientes: Buffer Cache: Contiene buffers de datos que son utilizados por los manejadores de dispositivos de bloques. Estos buffers son de tamaño fijo y contienen información que ha sido transferida desde un dispositivo de bloques. Cache de Páginas: Se utiliza para acelerar el acceso a imágenes de ejecutables y datos en disco. Se utiliza para guardar el contenido lógico de un fichero. 18

Cachés Cache de Intercambio: Es una caché que contiene páginas del fichero de intercambio. Caches Hardware: Son una o varias cachés normalmente implementadas en el propio procesador (L1 y L2) y una caché con entradas de tablas de páginas llamada TLB (Translation Lookaside Buffer). El procesador guarda en la TLB las entradas de tablas de páginas accedidas más recientemente, evitando leer siempre la tabla de páginas de memoria cada vez que se realiza un acceso a memoria (para datos o instrucciones). 19

Tabla de páginas en Linux Linux supone 3 niveles de tablas de páginas: las entradas de los 2 primeros niveles apuntan a tablas de páginas y las del último a páginas de memoria (cada nivel contiene el PFN de las páginas del siguiente nivel). Para traducir una dirección virtual a una física, el procesador tiene que tomar el contenido de cada uno de los campos de las tablas de páginas, convertirlos en desplazamientos de la página física que contiene la tabla de páginas y leer el número de marco de página del siguiente nivel de la tabla de páginas. 20

Tabla de páginas en Linux Esta operación se repite tres veces hasta que se encuentra el número de la página física que contiene la dirección virtual. Ahora el último campo de la dirección virtual se utiliza para encontrar el dato dentro de la página (desplazamiento). A continuación se muestra una figura que ilustra lo comentado. 21

Tabla de páginas en Linux 22

Paginación por demanda Cuando un proceso accede a una dirección virtual que no tiene una entrada válida en la tabla de páginas, el procesador informará sobre el fallo de página a Linux. El fallo de página indica la dirección virtual donde se produjo el fallo de página y el tipo de acceso que lo causó. Linux debe encontrar la vm_area_struct que representa el área de memoria donde sucedió el fallo de página. 23

Paginación por demanda Si no hay ninguna estructura vm_area_struct para la dirección virtual que produjo el fallo de página entonces el proceso ha accedido a una dirección de memoria virtual ilegal. Linux enviará al proceso la señal SIGSEGV, y si el proceso no ha instalado un manejador de señales para esta señal entonces morirá. Lo siguiente que hace Linux es comprobar el tipo de fallo de página producido y los tipos de acceso permitidos para el área de memoria virtual en cuestión. 24

Paginación por demanda Si el proceso ha intentado acceder a la memoria de forma ilegal también se le señalará un error de memoria. Una vez que Linux ha determinado que el fallo de página es legal, tiene que tratarlo. Linux ha de diferenciar entre páginas que están en un fichero de intercambio y aquellas que son parte de una imagen ejecutable localizadas en algún lugar del disco (nunca han estado en memoria física). Esto lo hace utilizando la entrada en la tabla de páginas de la página que causó el fallo. 25

Paginación por demanda Si la entrada de la tabla de páginas es inválida pero tiene información, el fallo de página se debe a que la página está en esos momentos en un fichero de intercambio. Si no contiene información habrá que buscar en el mapa de memoria de la región de memoria virtual a la que pertenece para extraer la dirección en memoria secundaria. Cuando la página necesitada es cargada en memoria física, las tablas de páginas del proceso y la TLB son actualizadas. 26

Intercambiando y liberando páginas Cuando queda poca memoria física, el subsistema de gestión de memoria de Linux tiene que intentar liberar páginas físicas. Este trabajo es realizado por el demonio de intercambio del núcleo (kswapd). Si hay suficientes páginas libres, el demonio de intercambio se vuelve a dormir hasta que el temporizador vuelva a expirar otra vez, en caso contrario el demonio intentará reducir el número de páginas ocupadas. 27

Intercambiando y liberando páginas El demonio puede reducir el número de páginas físicas ocupadas en memoria de tres formas distintas. Estas son las siguientes: Reduciendo el tamaño de la caché de páginas y el buffer cache: eliminar páginas de ficheros proyectados en memoria y buffers de dispositivos de bloques. Enviando a disco páginas compartidas: Habrá que modificar todas las entradas de las tablas de páginas de todos los procesos afectados. 28

Intercambiando y liberando páginas Enviando a disco o descartando páginas: Se eligen las mejores candidatas a enviar a disco. Esto es, liberando las páginas físicas en base a su antigüedad (campo age) Las páginas se envian a disco sólo si los datos que contienen no se pueden recuperar de otra forma (“dirty”). Las páginas bloqueadas en memoria no se pueden intercambiar ni descartar. La entrada en la tabla de páginas se establece a inválida y se inserta información acerca de donde está la página en el fichero de intercambio. 29

Copy-on-Write Cuando se invoca a la primitiva fork, Linux no duplica las páginas de memoria que son necesarias para el nuevo proceso. Lo que se hace es apuntar las entradas de la tabla de páginas del nuevo proceso a las páginas del proceso padre. Cuando alguna de las páginas es modificada por alguno de los procesos, entonces el núcleo pasa a realizar la duplicación de dicha página. 30

Copy-on-Write La forma de llevar a cabo este proceso consiste en establecer los permisos de estas páginas a sólo-lectura pero sabiendo que dichas páginas se pueden modificar (información almacenada en las regiones de memoria virtual del proceso: vma modificable). Cuando ocurre una violación de acceso a estas páginas es cuando se realiza la duplicación propiamente dicha. 31

Estructuras de datos El fichero <asm/page.h> define los tipos utilizados para representar las entradas en las tablas de páginas. Estas son las siguientes: 32

Estructuras de datos Además existen varias macros. Estas son las siguientes: 33

Estructuras de datos El fichero <linux/mm.h> define el formato de la estructura mem_map_t (struct page). Esta estructura se utiliza para mantener la información acerca de cada página de memoria física. Los campos relevantes de está estructura son los siguientes: 34

Estructuras de datos Las constantes siguientes, declaradas en el archivo <linux/mm.h> definen el estado de una página. Estas son las siguientes: 35

Estructuras de datos La estructura free_area_struct, declarada en el fichero fuente <mm/page_alloc.c> define el formato de los descriptores de la lista de grupos. 36

Estructuras de datos La estructura free_area_struct, declarada en el fichero fuente <mm/page_alloc.c> define el formato de los descriptores de la lista de grupos. 37

Función do_page_fault (<arch/i386/mm/fault.c>) Esta función se llama cuando ocurre un fallo de página. 6980 asmlinkage void do_page_fault(struct pt_regs *regs, 6981 unsigned long error_code) 6982 { 6983 struct task_struct *tsk; 6984 struct mm_struct *mm; 6985 struct vm_area_struct * vma; 6986 unsigned long address; 6987 unsigned long page; 6988 unsigned long fixup; 6989 int write; /* Nos indica si se fue a escribir */ /* se obtiene la dirección que provocó el fallo de página Esto sólo es válido en x86, que utiliza el registro cr2 */ 6992 __asm__("movl %%cr2,%0":"=r" (address)); 38

Función do_page_fault /* Tomamos la información de gestión de la memoria del proceso actual desde la tabla de procesos */ 6994 tsk = current; 6995 mm = tsk->mm; 6996 /* Si fue una interrupción o no fue en el contexto de usuario (fue el núcleo) no se tomará en cuenta el fallo */ 6999 if (in_interrupt() || mm == &init_mm) 7000 goto no_context; 7001 /* Se extrae el segmento de memoria virtual que contiene la dirección o puede contenerla: su final > address */ 7004 vma = find_vma(mm, address); 39

Función do_page_fault /* Si no se ha encontrado ningún segmento --> bad_area */ 7005 if (!vma) 7006 goto bad_area; /* Si la dirección pertenece al rango de direcciones del proceso  good_area */ 7007 if (vma->vm_start <= address) 7008 goto good_area; /* Si la dirección no está contenida en la vma, pero esta crece hacia abajo (p.e. la pila), la dirección se toma como válida */ 7009 if (!(vma->vm_flags & VM_GROWSDOWN)) 7010 goto bad_area; 40

Función do_page_fault /* Si el fallo de página es en modo usuario se comprueba que el proceso no se ha salido de la pila. */ 7011 if (error_code & 4) { /*El bit 2 de error_code indica si se está en modo usuario +32: existen instrucciones como “pusha” que realizan un post-incremento más tarde (32 bits por dirección) */ 7016 if (address + 32 < regs->esp) 7017 goto bad_area; 7018 } /* Intenta expandir el segmento para contener la nueva dirección. Si falla  bad_area */ 7019 if (expand_stack(vma, address)) 7020 goto bad_area; 41

Función do_page_fault /* En este punto se tiene una vm_area buena para el acceso realizado. Por tanto, podemos tratar el fallo de página */ 7023 good_area: 7024 write = 0; /* Bit 0 de error_code: 0 la página no estaba en memoria 1: la página estaba en memoria pero se violaron sus protecciones de acceso Bit 1 de error_code: 0 para una lectura y 1 para una escritura */ 7025 switch (error_code & 3) { 7026 default: /* case 3 */ /* La página está en memoria y se intentó escribir sobre ella [11]. Al entrar en este este caso, también se entra por el caso 2. */ 42

Función do_page_fault /* No se hace nada salvo imprimir un error si el núcleo se compiló para depurar y este fue quien provocó el fallo. */ 7027 #ifdef TEST_VERIFY_AREA 7028 if (regs->cs == KERNEL_CS) 7029 printk("WP fault at %08lx\n", regs->eip); 7031 #endif 7031 /* fall through */ 7032 case 2: /* write, not present */ /* Si se intentó escribir y el segmento es de sólo-lectura [10] --> bad_area */ 7033 if (!(vma->vm_flags & VM_WRITE)) 7034 goto bad_area; /* Si el segmento es de lectura-escritura se continua y write = 1<-- Se intentó escribir */ 7035 write++; 7036 break; /* De aquí no pasan los case 2 y 3*/ 43

Función do_page_fault /* Se está intentando leer un segmento sin permisos de lectura [01] (violación de las protecciones de acceso). */ 7037 case 1: /* read, present */ 7038 goto bad_area; /* Se va a leer una página que no está en memoria. [00]*/ 7039 case 0: /* read, not present */ Si no hay permisos de lectura o de ejecución --> bad_area, en otro caso, fallo de página */ 7040 if(!(vma->vm_flags & (VM_READ|VM_EXEC) )) 7041 goto bad_area; 7042 } /* Se intenta cargar la página o hacer el COW. */ 7047 if (!handle_mm_fault(tsk, vma, address, write)) 7048 goto do_sigbus; 7057 return; 44

Función do_page_fault /* Fallo de protección por un intento de escribir una dirección protegida o por intento de acceder a una dirección que no pertenece al proceso */ 7062 bad_area: /* Si el fallo lo provocó un proceso de usuario, se le envía una señal SIGSEGV (“segmentation fault”) */ 7066 if (error_code & 4) { 7067 tsk->tss.cr2 = address; 7068 tsk->tss.error_code = error_code; 7069 tsk->tss.trap_no = 14; 7070 force_sig(SIGSEGV, tsk); 7071 return; 7072 } 45

Función do_page_fault /* Se llega a este punto si es un problema del núcleo: Aún no se ha dado el caso (sin contar el de la NOTA)*/ 7086 no_context: /* ¿Está preparado el núcleo para manipular esta excepción? */ 7088 if((fixup=search_exception_table(regs->eip))!=0) { /* El núcleo puede tratar la excepción y se carga el contador de programa con la nueva dirección */ 7089 regs->eip = fixup; 7090 return; 7091 } 7092 /* NOTA: Hay un caso especial: en el arranque, el núcleo provoca un error para comprobar las protecciones de escritura de la MMU y lo trata adecuadamente en esta zona de la función, sin necesidad de capturar la excepción. */ 46

Función do_page_fault /* Si no se trata del test de la MMU */ /* El núcleo no sabe como tratar la excepción y muestra posibles errores */ 7109 if (address < PAGE_SIZE) 7110 printk(KERN_ALERT "Unable to handle kernel" 7111 "NULL pointer dereference"); 7112 else 7113 printk(KERN_ALERT "Unable to handle kernel" 7114 "paging request"); /* Se provoca la detención del sistema */ 7128 die(“Ops”, regs, error_code); 7129 do_exit(SIGKILL); 47

Función do_page_fault /* Si no se pudo cargar la página se envía una señal SIGBUS al proceso. */ 7134 do_sigbus: /* Se actualiza el estado de la tarea y se le envía una señal SIGBUS al proceso */ 7139 tsk->tss.cr2 = address; 7140 tsk->tss.error_code = error_code; 7141 tsk->tss.trap_no = 14; 7142 force_sig(SIGBUS, tsk); /* Si la tarea era el núcleo, se vuelve a atrás para intentar tratar la excepción o detener la ejecución del sistema. (bit 2 de error_code==0 en modo núcleo) */ 7145 if (!(error_code & 4)) 7146 goto no_context; 7147 } 48

Función handle_mm_fault (<mm/memory.c>) Esta función obtiene la dirección de la página a la que se ha accedido y realiza la llamada para cargar la página en memoria física o para hacer una COW. 32725 int handle_mm_fault(struct task_struct *tsk, 32726 struct vm_area_struct * vma, 32727 unsigned long address, int write_access){ 32729 pgd_t *pgd; 32730 pmd_t *pmd; 32731 /* Se obtiene un puntero a la entrada correspondiente a address en la tab. de pág. global para el proceso */ 32732 pgd = pgd_offset(vma->vm_mm, address); /* Se obtiene un puntero a la entrada correspondiente a address en la t. de pág. Intermedia (en x86 coinciden). */ 32733 pmd = pmd_alloc(pgd, address); 49

Función handle_mm_fault /* Si la entrada en la tabla intermedia (un puntero a una tabla de páginas) no es nula */ 32734 if (pmd) { /* Se trata de localizar la página que contiene a address en la tabla de páginas a partir de la tabla intermedia */ 32735 pte_t * pte = pte_alloc(pmd, address); 32736 if (pte) { /* Si se localiza la página, se intenta cargar la página si no está en memoria y si lo está se establecen los flags adecuados realizando una COW en caso necesario */ 32737 if (handle_pte_fault(tsk, vma, address, 32738 write_access, pte)) { 32740 return 1; 32741 } 32742 } 32743 } 32744 return 0; /* Se retorna 0 en caso de error */ 32745 } 50

Macro pgd_offset (<include/asm-i386/ pgtable.h>) Esta macro obtiene un puntero a la entrada de la tabla de páginas global (o directorio) en cuya correspondiente tabla de páginas intermedia se encuentra la tabla de páginas donde se encuentra address. Se obtiene a partir de su base y desplazamiento dentro de la misma (primeros bits de address). /* Para ello suma la base de la tabla de páginas global a los bits (22) de mayor peso de address (que contienen el desplazamiento dentro de dicha tabla) */ 11284 #define pgd_offset(mm, address) \ 11285 ((mm)->pgd + ((address) >> PGDIR_SHIFT)) 51

Función pmd_alloc (<include/asm-i386/ pgtable.h>) Esta función obtiene un puntero a la entrada de la tabla intermedia en cuya correspondiente tabla de páginas se encuentra address. /* En x86 no existe tabla intermedia (PMD) por eso se devuelve la dirección calculada para la tabla global PGD. Linux supone que la PMD es de tamaño 1 y que por tanto, está incluida en la PGD. Con esto se consigue abstraer el código de Linux de una arquitectura específica */ 11454 extern inline pmd_t * pmd_alloc(pgd_t * pgd, 11455 unsigned long address) 11456 { 11457 return (pmd_t *) pgd; 11458 } 52

Función pte_alloc (<include/asm-i386/ pgtable.h>) Esta función obtiene un puntero a la entrada de la tabla de páginas asociada a address. Si no existe la tabla de páginas, la crea. 11422 extern inline pte_t * pte_alloc(pmd_t * pmd, 11423 unsigned long address) 11424 { /* Se extrae de address el desplazamiento dentro de la tabla de páginas: desde el bit 22 al 12 */ 11425 address = (address >> (PAGE_SHIFT-2)) & 11426 4*(PTRS_PER_PTE - 1); 53

Función pte_alloc /* Si el valor de la entrada es 0 entonces no existe tabla de páginas. Hay que crear una nueva tabla de páginas --> getnew */ 11428 if (pmd_none(*pmd)) 11429 goto getnew; /* Si la entrada de la tabla de páginas intermedia es incorrecta, se trata un error */ 11430 if (pmd_bad(*pmd)) 11431 goto fix; /* Si la página apuntada por la entrada de la tabla de páginas intermedia es válida y está en memoria, se devuelve su dirección: (Dir. base de la PMD) + (desplazamiento dentro de ella) */ 11432 return (pte_t *) (pmd_page(*pmd) + address); 54

Función pte_alloc /* Se obtiene una página para tabla de páginas. */ 11433 getnew: /* Al buscar una página libre se mira primero en la caché con get_pte_fast. El núcleo tiene una caché páginas de tablas de páginas recientemente liberadas llamada pte_quitcklist. */ 11435 unsigned long page =(unsigned long)get_pte_fast(); 11436 /* Si no se encuentra ninguna página libre en la caché, la carga mediante la función get_pte_slow. */ 11437 if (!page) 11438 return get_pte_slow(pmd, address); 55

Función pte_alloc /* Si get_pte_fast encontró una página libre se inserta en la entrada de la tabla intermedia. */ 11439 pmd_val(*pmd) = _PAGE_TABLE + __pa(page); /* Se devuelve la dirección de la entrada de la tabla de páginas (dirección de la página + desplazamiento) */ 11440 return (pte_t *) (page + address); 11441 } /* Se ha detectado un error, se imprime un mensaje */ 11442 fix: 11443 __bad_pte(pmd); 11444 return NULL; 11445 } 56

Función handle_pte_fault (<mm/memory.c>) Esta función lee la página solicitada o realiza la llamada para realizar una COW. 32690 static inline int handle_pte_fault( 32691 struct task_struct *tsk, 32692 struct vm_area_struct * vma, unsigned long address, int write_access, pte_t * pte) 32694 { 32695 pte_t entry; 32698 entry = *pte; /* entrada de la tabla de páginas */ 57

Función handle_pte_fault /* Si la página no está en memoria */ 32700 if (!pte_present(entry)) { /* Si además la página nunca ha estado en memoria física (no tiene asignada una entrada en una tabla de páginas)*/ 32701 if (pte_none(entry)) /* Se realiza un mapeo de la página leyéndola e insertando su entrada correspondiente en la tabla de páginas */ 32702 return do_no_page(tsk, vma, 32703 address, write_access, pte); /* La página no está en memoria, pero ya había sido mapeada, por tanto, se lee del fichero de swap */ 32704 return do_swap_page(tsk, vma, address, pte, 32705 entry, write_access); 32706 } 58

Función handle_pte_fault /* Si la página está en memoria, se concluye que hubo una violación de las protecciones de la página. */ /* Se marca la página como accedida en entry y en pte */ 32708 entry = pte_mkyoung(entry); 32709 set_pte(pte, entry); /* Se actualiza la tlb */ 32710 flush_tlb_page(vma, address); 59

Función handle_pte_fault /* Si se quiere escribir */ 32711 if (write_access) { /* Si se intenta escribir en una página protegida contra escritura hay que hacer una COW ya que el segmento al que pertenecía no estaba protegido contra escritura */ 32712 if (!pte_write(entry)) /* Si la página es de sólo-lectura hay que hacer una COW*/ 32713 return do_wp_page(tsk, vma, address, pte); /* Se está intentando escribir en una página que lo permite, y se marca como escrita (bit dirty=1) */ 32715 entry = pte_mkdirty(entry); 32716 set_pte(pte, entry); /* Se actualiza la TLB */ 32717 flush_tlb_page(vma, address); 32718 } 32720 return 1; 32721 } 60

Función do_wp_page (<mm/memory.c>) Esta función es la encargada de realizar la copia en escritura (Copia-On-Write) 32401 static int do_wp_page(struct task_struct * tsk, 32402 struct vm_area_struct * vma, unsigned long address, pte_t *page_table) 32404 { 32405 pte_t pte; 32406 unsigned long old_page, new_page; 32407 struct page * page_map; 32408 /*entrada en la tabla de páginas*/ 32409 pte = *page_table; /* Se obtiene una nueva página de memoria libre, que se utilizará para hacer la COW */ 32410 new_page = __get_free_page(GFP_USER); 61

Función do_wp_page /* Esta función no es atómica, por lo tanto, se comprueba que tras solicitar la nueva página, esta no se ha copiado ya. Esto se realiza con las siguientes preguntas: */ /* ¿Ya está la entrada correspondiente a la página en la tabla de páginas? La nueva entrada en la tabla de páginas y la antigua ya no deberían coincidir */ 32413 if (pte_val(*page_table) != pte_val(pte)) 32414 goto end_wp_page; /* ¿La página no está en memoria? Antes estaba -> Es una nueva página que puede ser que no se haya duplicado */ 32415 if (!pte_present(pte)) 32416 goto end_wp_page; 62

Función do_wp_page /* ¿La página ya tiene el permiso de escritura activado? Antes no lo tenía y nosotros no lo hemos hecho */ 32417 if (pte_write(pte)) 32418 goto end_wp_page; /* Se obtiene la dirección de la página física en memoria pte=entrada en la tabla de páginas, old_page=dirección de la página en memoria*/ 32419 old_page = pte_page(pte); /* Si se ha mapeado la página a un número mayor que el número de páginas físicas, se ha producido un error */ 32420 if (MAP_NR(old_page) >= max_mapnr) 32421 goto bad_wp_page; 63

Función do_wp_page /* Se incrementa el número de fallos de página “minor”, aquellos que se resuelven sin acceder a disco. Una COW no necesita acceder a disco */ 32422 tsk->min_flt++; /* Se obtiene el descriptor de la página en memoria (estructura que describe la página) */ 32423 page_map = mem_map + MAP_NR(old_page); /* La copia se puede evitar si: - Nosotros somos el único usuario (count=1) - Hay otro usuario, pero éste es el “swap cache” */ 64

Función do_wp_page 32432 switch (&page_map->count) { 32433 case 2: /* hay 2 usuarios */ /* Si no está en la caché de swap entonces hay que hacer la COW ya que el otro usuario no es la caché */ 32434 if (!PageSwapCache(page_map)) 32435 break; /* Si hay más de un usuario haciendo uso de la copia en la caché de swap entonces hay que hacer la COW (+ de 1 usuario */ 32436 if (swap_count(page_map->offset) != 1) 32437 break; /* Si definitivamente el otro usuario era la caché pues se borra de esta porque la página va a ser modificada */ 32438 delete_from_swap_cache(page_map); 32439 /* FallThrough */ 65

Función do_wp_page 32440 case 1: /* Si sólo había un usuario real (también puede venir del case 2 entonces... */ /* Se marca la página como “dirty” y “writable” */ 32445 set_pte(page_table, pte_mkdirty(pte_mkwrite(pte))); /* Se actualiza la TLB */ 32446 flush_tlb_page(vma, address); 32447 end_wp_page: /* Si se había reservado una página, se libera porque no es necesaria porque la página sólo tiene un usuario. Luego se retorna de la función */ 32448 if (new_page) 32449 free_page(new_page); 32450 return 1; 32451 } 66

Función do_wp_page /* Hay que hacer la COW. Si la nueva página no se creó-> error */ 32454 if (!new_page) 32455 return 0; 32456 /* Si la página fue reservada se incrementa el número de páginas residentes del proceso */ 32457 if (PageReserved(mem_map + MAP_NR(old_page))) 32458 ++vma->vm_mm->rss; /* Se copia el contenido de la página original en la página reservada (con un memcpy) */ 32459 copy_cow_page(old_page, new_page); 67

Función do_wp_page /* Se marca la página como “dirty” y “writable” y coloca el resto de protecciones indicadas en su VMA */ 32463 set_pte(page_table, 32464 pte_mkwrite(pte_mkdirty(mk_pte(new_page, 32465 vma->vm_page_prot)))); /* Se decrementa el contador de usuarios de la antigua página ya que ahora este proceso tiene su propia copia */ 32466 free_page(old_page); 32468 return 1; 32469 68

Función do_wp_page /* Si se ha mapeado la página a un número mayor que el número de páginas físicas, se ha producido un error, se muestra información y se mata el proceso que provocó el fallo */ 32470 bad_wp_page: 32471 printk("do_wp_page: bogus page at address " 32472 "%08lx (%08lx)\n", address, old_page); 32473 send_sig(SIGKILL, tsk, 1); /* Si se había reservado una página para realizar la COW, se libera, puesto que no se va a utilizar */ 32474 if (new_page) 32475 free_page(new_page); 32476 return 0; 32477 } 69

Función try_to_swap_out (<mm/vmscan.c>) Esta función se llama para intentar liberar una página siempre que se pueda (no esté bloqueada ni reservada). Esta función se llama periódicamente a partir del proceso kswapd. 38863 static int try_to_swap_out(struct task_struct * tsk, 38864 struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask) 38866 { 38867 pte_t pte; 38868 unsigned long entry; 38869 unsigned long page; 38870 struct page * page_map; 38871 38872 pte = *page_table; /*entrada en la tabla de pág.*/ 70

Función try_to_swap_out /* Si la página no está en memoria, no se puede liberar */ 38873 if (!pte_present(pte)) 38874 return 0; /* Se extrae la dirección de la página física */ 38875 page = pte_page(pte); /* Si la página es mayor que el número de páginas físicas de memoria presentes en el sistema, se devuelve un error*/ 38876 if (MAP_NR(page) >= max_mapnr) 38877 return 0; /* Se extrae el descriptor de la página física */ 38879 page_map = mem_map + MAP_NR(page); 71

Función try_to_swap_out /* Se devuelve error si la página está Reservada, Bloqueada o está siendo accedida en una operación de DMA*/ 38880 if (PageReserved(page_map) 38881 || PageLocked(page_map) 38882 || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))) 38883 return 0; /* Si la página es ‘joven’ no es buena idea liberarla porque se viola el Principio de Localidad Temporal, por tanto, se marca como ‘antigua’, para que un intento de intercambio futuro si se puede realizar */ 38885 if (pte_young(pte)) { /* Se hace más vieja a la página */ 38888 set_pte(page_table, pte_mkold(pte)); 38889 set_bit(PG_referenced, &page_map->flags); 38890 return 0; 38891 } 72

Función try_to_swap_out /* Si la página ya está en la “swap cache”, se incrementa el número de referencias a ella en la swap caché */ 38899 if (PageSwapCache(page_map)) { 38900 entry = page_map->offset; 38901 swap_duplicate(entry); /* Se actualiza page_table a entry*/ 38902 set_pte(page_table, __pte(entry)); 38903 drop_pte: /* Se decrementa el número de páginas residentes del proceso, puesto que dejará de estar en memoria */ 38904 vma->vm_mm->rss--; 73

Función try_to_swap_out /* Decrementa el número de referencias a la página y se libera si llega a cero */ 38906 __free_page(page_map); 38907 return 0; 38908 } /* Si la página no ha sido modificada (se puede recuperar del disco), se borra la entrada de la tabla de páginas y se libera */ 38920 if (!pte_dirty(pte)) { 38921 pte_clear(page_table); 38922 goto drop_pte; 38923 } /* Si no se puede hacer una operación de E/S no se hace el swap. Recursos ocupados */ 38927 if (!(gfp_mask & __GFP_IO)) 38928 return 0; 74

Función try_to_swap_out /* En este punto se sabe que la página está a dirty, por tanto se ha de guardar a disco */ /* Si el segmento tiene implementada su propia operación de swapout se invoca */ 38945 if (vma->vm_ops && vma->vm_ops->swapout) { 38946 pid_t pid = tsk->pid; /* Se limpia la entrada en la tabla de páginas */ 38947 pte_clear(page_table); /* Se decrementa el numero de paginas residentes en memoria del proceso */ 38949 vma->vm_mm->rss--; /* Si hay un error en su operación de swapout se mata al proceso enviándole la señal SIGBUS */ 38951 if (vma->vm_ops->swapout(vma, page_map)) 38952 kill_proc(pid, SIGBUS, 1); 75

Función try_to_swap_out /* Se decrementa el número de referencias a la página */ 38953 __free_page(page_map); 38954 return 1; 38955 } /* Se obtiene una nueva entrada en la caché de swap */ 38961 entry = get_swap_page(); 38962 if (!entry) 38963 return 0; /* No queda espacio en el swap */ /* Se decrementa el número de páginas residentes del proceso en memoria */ 38965 vma->vm_mm->rss--; /* Se incrementa el numero de páginas del proceso que se han guardado en la zona de intercambio */ 38966 tsk->nswap++; 76

Función try_to_swap_out /* Se actualiza page_table a entry indicando ahora que la página está en la caché de swap */ 38967 set_pte(page_table, __pte(entry)); /* Se verifica la entrada entry en la caché de swap (si es correcta) y se incrementa el número de referencias que hay apuntando a esa entrada en la swap caché */ 38970 swap_duplicate(entry); /* Se asocia la página (struct page) a la entrada de la caché */ 38971 add_to_swap_cache(page_map, entry); /* Se realiza la copia al área de swap asíncronamente */ 38977 rw_swap_page(WRITE, entry, (char *) page, 0); /* Se decrementa el número de referencias a la página */ 38979 __free_page(page_map); 38980 return 1; 38981 } 77

FIN