Главная » Ядро Linux » Работа с областями памяти

0

Ядру часто необходимо  определять,  соответствует ли  та  или иная  область памяти в  адресном пространстве процесса заданному критерию, например,  существует  ли заданный адрес в  области памяти. Эти операции являются основой работы функции mmap () , которая будет рассмотрена в  следующем разделе, и выполнять их приходится часто. Несколько  полезных для этого функций  объявлены в  файле

<linux/mm.h>.

Функция find_vma( )

Функция f ind_vma  ()  определена в файле  mm/mmap.с.

Эта функция позволяет найти  в заданном адресном пространстве ту первую  область  памяти, для  которой значение поля  vm_end  больше  заданного адреса  addr. Другими  словами, эта функция позволяет найти  первую  область  памяти, которая содержит  адрес  addr  или  начинается с адреса, большего адреса  addr.  Если  такой  области памяти не существует, то функция возвращает значение NULL.

В  противном  случае  возвращается указатель   на  соответствующую  структуру vm_area_struct . Обратите внимание, что найденная область  VMA может  начинаться с адреса, большего адреса  addr , и этот адрес не обязательно принадлежит,  найденной области  памяти. Результат  выполнения функции find_vma  ()  кэшируется в поле map_cach e дескриптора памяти. Поскольку очень  велика  вероятность того, что после  одной  операции с областью  памяти последуют  еще  операции с ней  же, то процент попаданий в кэш  получается достаточно большим (на практике получаются  значения порядка 30-40%).  Проверка кэшированных результатов выполняется очень быстро.  Если  нужный адрес  в кэше  не найден, то выполняется поиск  по всем областям памяти, связанным с заданным дескриптором. Этот поиск  выполняется с помощью красно-черного дерева  следующим образом.

struct vm_area_struct * find_vma(struct mm_struct *mm, unsigned long addr)

{

struct vm_area_struct *vma = NULL;

if (mm) {

vma = mm->mmap_cache;

if (! (vma && vma->vm_end > addr && vma->vm start <= addr)) {

struct rb node * rb_node;

rb node = mm->mm_rb.rb_node;

vma = NULL;

while (rb_node) {

struct vm_area_struct * vma_tmp;

vma_tmp = rb_entry (rb_node,

struct vm_area_struct, vm_rb);

if (vma_tmp->vm_end > addr) {

vma = vma_tmp;

if (vma_tmp->vm_start <= addr)

break;

rb_node = rb_node->rb_left;

} else

}

rb_node = rb_node->rb_right;

if (vma)

mm->mmap_cache = vma;

}

}

return vma;

}

Вначале выполняется  проверка поля   vma_cach e  на  предмет   того,  содержит ли кэшированная область  VMA необходимый адрес.   Обратите внимание,  что  простая проверка того,  является ли  значение поля   vm_end   большим  addr , не  гарантирует что  проверяемая область  памяти является первой,  в которой есть  адреса, большие addr .  Поэтому, для  того  чтобы  кэш  в этой  ситуации оказался полезным, проверяемый  адрес  должен  принадлежать кэшированной области памяти. К  счастью, это  как раз  и  соответствует случаю  выполнения  последовательных операций с  одной  и  той же  областью  VMA.

Если  кэш  не  содержит нужную  область  VMA,  то  функция должна  выполнять поиск  по  красно-черному дереву  Это  выполняется путем  проверки узлов  дерева.   Если значение поля  vma_end для  области памяти текущего узла  больше  addr , то текущим становится левый  дочерний узел, в противном случае — правый. Функция завершает свою  работу,  как  только   находится область  памяти,  которая содержит адрес  addr . Если  такая  область  VMA не  найдена, то  функция  продолжает поиск по  дереву  и возвращает ту область  памяти,  которая начинается после  адреса  addr .  Если  вообще не найдена ни  одна  область  памяти, то возвращается значение NULL.

Функция find_vma_prev( )

Функция  find_vma_pre v ()   работает   аналогично функции  fin d   vma () , но  дополнительно она  еще  возвращает последнюю область  VMA, которая  заканчивается перед  адресом   addr .  Эта  функция также  определена в файле  mma/mmap.c и  объявлена  в файле   <linux/ram.h>  следующим образом.

struct vm_area_struct * find vma_prev(struct mm_struct *mm, unsigned long addr, struct vm_area_struct **pprev)

Параметр ppre v после  возвращения из  функции  содержит указатель на  предыдущую  область  VMA.

Функция find_VMA_intersection()

Функция f ind_vma_intersectio n ()  возвращает первую область памяти, которая перекрывается с указанным интервалом адресов. Эта функция определена в файле  <linux/mm.h> следующим образом. Это функция с подстановкой тела.

static inline struct vm_area_struct * find_vma_intersection(

struct mm_struct *mm, unsigned long start_addr, unsigned long end addr)

{

struct vm_area_struct *vma;

vma=find_vma(mm,start_addr);

if (vma && end_addr <= vma->vm_start)

vma = NULL;

return vma;

}

Первый параметр — адресное пространство, в котором выполняется поиск, параметр  start_add r  — это  первый адрес  интервала адресов, а параметр end_add r — последний адрес  интервала.

Очевидно, что  если  функция find_vma( )   возвращает значение NULL,  то  это  же значение будет  возвращать и  функция  find_vma_intersection() .  Если  функция

find_vma  ()   возвращает существующую область  VMA, то функция find_vma_intersectio n ()  возвратит ту же область  только  тогда, когда  эта  область  не начинается после конца данного диапазона адресов.  Если  область памяти, которая возвращается функцией find_vma  () , начинается после  последнего адреса  из указанного диапазона, то функция f ind_vma_intersectio n ()  возвращает значение NULL.

Источник: Лав,  Роберт. Разработка ядра  Linux, 2-е  издание. : Пер.  с англ.  — М.  : ООО  «И.Д.  Вильяме» 2006. — 448 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии