En el último artículo, aprender el diseño de memoria de los programas de espacio de usuario basados en el bloqueo involucra operaciones relacionadas con VMA. En esta sección, se usa un ejemplo simple para aprender profundamente qué es VMA y cómo está organizado.
Primer vistazo a la estructura de VMA
struct vm_area_struct {
/* The first cache line has the info for VMA tree walking. */
unsigned long vm_start; /* Our start address within vm_mm. */
unsigned long vm_end; /* The first byte after our end address
within vm_mm. */
/* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next, *vm_prev;
struct rb_node vm_rb;
/* Second cache line starts here. */
struct mm_struct *vm_mm; /* The address space we belong to. */
pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, see mm.h. */
/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap interval tree.
*
* For private anonymous mappings, a pointer to a null terminated string
* in the user process containing the name given to the vma, or NULL
* if unnamed.
*/
union {
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
const char __user *anon_name;
};
} ;
- vma_start representa la dirección de inicio de este vma
- vma_end representa la dirección final de este vma
- Debido a que vma se vinculará a través de una lista doblemente vinculada, habrá punteros vm_next y vm_prev
- Al mismo tiempo, para encontrar la comodidad, vma también está organizada por árboles rojos y negros, vm_rb es el nodo de árbol rojo y negro de vma
- vm_mm es la estructura mm_struct a la que pertenece este vma
- vm_page_prot significa el permiso correspondiente a este vma, ya sea legible, editable, ejecutable, etc.
Todavía tomamos prestada esta imagen, puede ver los miembros mmp y mmp_rb en mm_struct en task_struct.
struct mm_struct {
struct {
struct vm_area_struct *mmap; /* list of VMAs */
struct rb_root mm_rb;
u64 vmacache_seqnum; /* per-thread vmacache */
......
Después de comprender los datos de la organización de VMA, todavía utilizamos el ejemplo de ayer para obtener la información de cada segmento de VMA a través del módulo del controlador
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/mm.h>
static int mpid=1;
static void print_vma(struct task_struct *task)
{
struct mm_struct *mm;
struct vm_area_struct *vma;
int count=0;
mm = task->mm;
printk("This mm_struct has %d vma\n", mm->map_count);
for(vma = mm->mmap; vma; vma=vma->vm_next){
printk("vma number %d: \n", ++count);
printk("Start address 0x%lx, End address 0x%lx\n", vma->vm_start, vma->vm_end);
}
printk("Code segment start=0x%lx, end=0x%lx\n"
"Data Segment start=0x%lx, end=0x%lx\n"
"Stack segment start=0x%lx\n",
mm->start_code, mm->end_code, mm->start_data, mm->end_data, mm->start_stack);
}
static int vma_start()
{
struct task_struct *task;
printk("Got the process id =%d\n", mpid);
for_each_process(task) {
if(task->pid == mpid){
printk("%s[%d]\n", task->comm, task->pid);
print_vma(task);
}
}
return 0;
}
static void vma_exit()
{
printk("print segment info module exit!\n");
}
module_init(vma_start);
module_exit(vma_exit);
module_param(mpid, int, 0);
Obtenemos el pid de la aplicación y luego pasamos los parámetros del módulo al módulo del controlador. Si coincide el mismo pid, se imprimen el nombre del proceso (campo de comunicación) y el campo PID (pid). Al mismo tiempo, obtenga cuántos vma tiene el proceso actual, imprima la dirección de inicio y la dirección final de cada vma.
Obtenga la información vma del proceso a través del comando de mapas
root:/data # cat /proc/4766/maps
00400000-0047c000 r-xp 00000000 103:23 6918 /data/vma
0048b000-0048e000 rw-p 0007b000 103:23 6918 /data/vma
0048e000-0048f000 rw-p 00000000 00:00 0
38382000-383a4000 rw-p 00000000 00:00 0 [heap]
78941af000-78941fb000 rw-p 00000000 00:00 0
78941fb000-78941fc000 r--p 00000000 00:00 0 [vvar]
78941fc000-78941fd000 r-xp 00000000 00:00 0 [vdso]
7fc0ed3000-7fc0f9d000 rw-p 00000000 00:00 0 [stack]
Mire la información de impresión de nuestro controlador nuevamente
[ 2432.979096] Got the process id =4766
[ 2432.979495] vma[4766]
[ 2432.979500] This mm_struct has 8 vma
[ 2432.979504] vma number 1:
[ 2432.979508] Start address 0x400000, End address 0x47c000
[ 2432.979511] vma number 2:
[ 2432.979515] Start address 0x48b000, End address 0x48e000
[ 2432.979518] vma number 3:
[ 2432.979522] Start address 0x48e000, End address 0x48f000
[ 2432.979525] vma number 4:
[ 2432.979529] Start address 0x38382000, End address 0x383a4000
[ 2432.979532] vma number 5:
[ 2432.979536] Start address 0x78941af000, End address 0x78941fb000
[ 2432.979539] vma number 6:
[ 2432.979543] Start address 0x78941fb000, End address 0x78941fc000
[ 2432.979547] vma number 7:
[ 2432.979551] Start address 0x78941fc000, End address 0x78941fd000
[ 2432.979554] vma number 8:
[ 2432.979558] Start address 0x7fc0ed3000, End address 0x7fc0f9d000
[ 2432.979564] Code segment start=0x400000, end=0x47b76f
Data Segment start=0x48b770, end=0x48d348
Stack segment start=0x7fc0f9ba00
A través de este ejemplo, entendemos claramente que cada vma se usa para describir cada segmento, y la información de cada segmento se describe en detalle a través de la estructura vm_area_struct. Y cada vma está vinculada a través de una lista doblemente vinculada. La función principal de la lista vinculada es facilitar la eliminación y la adición; otra forma de organización del árbol rojo y negro es facilitar la búsqueda.