fork
exit
brk
malloc
);
execve
mmap
munmap
PAGE_OFFSET
zdefiniowana
w include/asm-i386/page.h na 0xC0000000 = 3*230, co oznacza
maksymalny rozmiar przestrzeni adresowej procesu równy 3GB.
task_struct
(include/linux/sched.h)struct task_struct { /* ... */ struct mm_struct *mm; /* ... */ struct mm_struct *active_mm; /* ... */ };
mm
active_mm
mm
, dla wątków jądra
jest to przestrzeń adresowa ostatnio wykonywanego procesu użytkownika.
mm_struct
(include/linux/sched.h)struct mm_struct { struct vm_area_struct * mmap; /* list of VMAs */ struct vm_area_struct * mmap_avl; /* tree of VMAs */ struct vm_area_struct * mmap_cache; /* last find_vma result */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ int map_count; /* number of VMAs */ struct rw_semaphore mmap_sem; /* ... */ struct list_head mmlist; /* List of all active mm's. These are globally strung * together off init_mm.mmlist, and are protected * by mmlist_lock */ /* ... */ unsigned long rss, total_vm, locked_vm; unsigned long def_flags; /* ... */ };
mmap
mmap_avl
mmap_cache
find_vma
;
pgd
mm_users
mm_count
map_count
mmap_sem
mmlist
mm_struct
w listę cykliczną;
rss
total_vm
locked_vm
def_flags
mmap_avl
jest wykorzystywane tylko dla dużej liczby
struktur VMA. Gdy map_count < AVL_MIN_MAP_COUNT
(obecnie 32) to mmap_avl == NULL
.
Ponieważ obszary przestrzeni adresowej opisywane przez struktury VMA nie zachodzą na siebie nie ma znaczenia
czy mmap
i mmap_avl
są sortowane według ich adresów początkowych, czy końcowych.
vm_area_struct
(include/linux/mm.h)struct vm_area_struct { struct mm_struct * vm_mm; /* The address space we belong to. */ unsigned long vm_start; /* Our start address within vm_mm. */ unsigned long vm_end; /* Our end address within vm_mm. */ /* linked list of VM areas per task, sorted by address */ struct vm_area_struct *vm_next; pgprot_t vm_page_prot; /* Access permissions of this VMA. */ unsigned long vm_flags; /* Flags, listed below. */ /* AVL tree of VM areas per task, sorted by address */ short vm_avl_height; struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; /* ... */ /* Function pointers to deal with this struct. */ struct vm_operations_struct * vm_ops; /* Information about our backing store: */ unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ struct file * vm_file; /* File we map to (can be NULL). */ /* ... */ };
vm_mm
vm_start
vm_end
vm_next
vm_mm->mmap
;
vm_page_prot
vm_flags
vm_avl_height
, vm_avl_left
, vm_avl_right
vm_mm->mmap_avl
o korzeniu w danej strukturze,
vm_ops
vm_pgoff
vm_file
NULL
;
vm_area_struct
obejmuje pewną całkowitą liczbę stron, a vm_start
i vm_end
są zawsze wielokrotnościami rozmiaru strony.
Obszary przestrzeni adresowej mogą być rozdzielane na mniejsze przy usuwaniu fragmentu przestrzeni
adresowej lub zmianie jego praw dostępu. Sąsiednie obszary mogą też być łączone jeśli spełnione są odpowiednie
kryteria zgodności: mają one takie same prawa dostępu i nie są odwzorowaniem plików.
Niektóre flagi dla obszarów pamięci (vm_flags
):
VM_READ
, VM_WRITE
, VM_EXEC
VM_MAYREAD
, VM_MAYWRITE
, VM_MAYEXEC
VM_SHARED
VM_GROWSDOWN
VM_GROWSUP
VM_DENYWRITE
VM_LOCKED
VM_IO
vm_page_prot
, zapisane w tablicach stron i kontrolowane przez
jednostkę zarządzania pamięcią (MMU) nie mogą odpowiadać wszystkim możliwym kombinacjom
flag VM_READ
, VM_WRITE
i VM_EXEC
.
W związku z tym w praktyce posiadanie prawa do zapisu oznacza także posiadanie prawa do odczytu,
zaś posiadanie prawa do odczytu - posiadanie prawa do wykonywania.
vm_operations_struct
(include/linux/mm.h)struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access); };
copy_mm
(kernel/fork.c)copy_mm(unsigned long clone_flags, struct task_struct * tsk)
jest wołana przez do_fork
w celu utworzenia struktur opisujących przestrzeń adresową
procesu potomnego na podstawie przestrzeni adresowej rodzica.
Linux wykorzystuje mechanizm kopiowania przy zapisie (COW - Copy On Write),
co oznacza, że same dane ze stron przestrzeni adresowej kopiowane są dopiero przy próbie ich
modyfikacji przez jeden z procesów.
Parametry:
clone_flags
do_vfork
;
dla copy_mm
istotna jest tylko flaga CLONE_VM
oznaczająca tworzenie
nowego wątku - procesu współdzielącego przestrzeń adresową z rodzicem.
tsk
current
).
CLONE_VM
zwiększa current->mm->mm_users
,
i przypisuje na tsk->mm
oraz tsk->active_mm
bieżącą przestrzeń adresową
(current->mm
).
-ENOMEM
;
mm_init
) ustawia w nowym deskryptorze niektóre pola (w szczególności mm_users
i mm_count
na 1); przydziela pamięć na nowy katalog stron, w razie niepowodzenia zwracając -ENOMEM
;
dup_mmap
kopiującą struktury VMA oraz (przy wykorzystaniu copy_page_range
)
tablice stron (i oznaczającą strony jako przeznaczone do kopiowania przy zapisie);
current->mm->mmlist
).
__exit_mm
(kernel/exit.c)__exit_mm(struct task_struct * tsk)
jest wołana przez do_exit
w celu zwolnienia struktur opisujących przestrzeń adresową
procesu.
Istnieje też funkcja exit_mm
, której jedynym działaniem jest wywołanie __exit_mm
.
Parametr:
tsk
__exit_mm
jest wywołanie mmput
(z kernel/fork.c) dla tsk->mm
.
mmput:
mm->mm_users
mm->mmlist
exit_mmap
(z mm/mmap.c) zwalniającą struktury VMA i tablice stron;
mmdrop
zwalniającą pamięć zajętą przez katalog stron i deskryptor pamięci
do_mmap_pgoff
(mm/mmap.c)sys_mmap2
lub dla zachowania zgodności old_mmap
wywołuje funkcjęstatic inline long do_mmap2(
unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
current->mm->mmap_sem
wołaunsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long pgoff)
.
Parametry:
file
struktura określająca plik do odwzorowania (jeśli nowy obszar ma odwzorowywać
plik)
addr
adres liniowy, od którego należy rozpocząć szukanie wolnego obszaru
len
długość żądanego obszaru
prot
żądane prawa dostępu do obszaru: PROT_NONE
dla obszaru niedostępnego
lub bitowa suma dowolnych spośród PROT_READ
, PROT_WRITE
, PROT_EXEC
flags
flagi dla regionu
pgoff
przesunięcie wewnątrz pliku file
obszaru do odwzorowania
(w wielokrotnościach rozmiaru strony)
MAP_ANONYMOUS
MAP_SHARED
MAP_PRIVATE
MAP_SHARED
MAP_FIXED
addr
MAP_NORESERVE
MAP_LOCKED
MAP_GROWSDOWN
MAP_ANONYMOUS
) sprawdza istnienie operacji
file->f_op->mmap
addr
MAX_MAP_COUNT == 65536
(include/linux/sched.h)
get_unmapped_area
, która:
MAP_FIXED
sprawdza czy addr
jest wielokrotnością rozmiaru strony;
jeśli tak to go zwraca, jeśli nie - zwraca -EIVAL
file
ma specjalną operację file->f_op->get_unmapped_area
(system plików ext2 nie ma takiej operacji)
zwraca zwrócony przez nią adres
arch_get_unmapped_area
, która
przeglądając przy użyciu funkcji find_vma
przestrzeń adresową procesu
znajduje pierwszy wolny obszar addresów liniowych odpowiedniej długości za addr
lub zwraca -ENOMEM
MAP_SHARED
lub MAP_PRIVATE
) i czy nie zachodzi
jeden z następujących błędnych przypadków:
do_munmap
w celu usunięcia poprzedniego mapowania obejmującego ten sam obszar
MAP_PRIVATE
(więc zmian nie można zapisać w pliku)
sprawdza czy dostępne jest wystarczająco dużo pamięci (chyba że ustawiono MAP_NORESERVE
)
file->f_op->mmap
do_munmap
(mm/mmap.c)sys_munmap
wywołuje z zamkniętym semaforem current->mm->mmap_sem
funkcjęint do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
Parametry:
mm
addr
len
addr
addr
zwraca 0
addr
a kończy za addr + len
i należy go podzielić na dwa, sprawdza czy nie spowoduje to przekroczenia maksymalnej liczby obszarów
unmap_fixup
, która:
addr+len
, skraca oryginalny obszar uaktualniając jego strukturę VMA
i wstawia obie do struktur deskryptora pamięci