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_cache
на предмет того, содержит ли кэшированная область VMA необходимый адрес. Обратите внимание, что простая проверка того, является ли значение поля vm_end
большим addr
, не гарантирует что проверяемая область памяти является первой, в которой есть адреса, большие addr
. Поэтому, для того чтобы кэш в этой ситуации оказался полезным, проверяемый адрес должен принадлежать кэшированной области памяти. К счастью, это как раз и соответствует случаю выполнения последовательных операций с одной и той же областью VMA.
Если кэш не содержит нужную область VMA, то функция должна выполнять поиск по красно-черному дереву. Это выполняется путем проверки узлов дерева. Если значение поля vma_end
для области памяти текущего узла больше addr
, то текущим становится левый дочерний узел, в противном случае — правый. Функция завершает свою работу, как только находится область памяти, которая содержит адрес addr
. Если такая область VMA не найдена, то функция продолжает поиск по дереву и возвращает ту область памяти, которая начинается после адреса addr
. Если вообще не найдена ни одна область памяти, то возвращается значение NULL
.
Функция find_vma_prev()
Функция find_vma_prev()
работает аналогично функции find_vma()
, но дополнительно она еще возвращает последнюю область VMA, которая заканчивается перед адресом addr
. Эта функция также определена в файле mma/mmap.c
и объявлена в файле
следующим образом.
struct vm_area_struct* find vma_prev(struct mm_struct *mm,
unsigned long addr, struct vm_area_struct **pprev);
Параметр pprev
после возвращения из функции содержит указатель на предыдущую область VMA.
Функция find_vma_intersection()
Функция find_vma_intersection()
возвращает первую область памяти, которая перекрывается с указанным интервалом адресов. Эта функция определена в файле
следующим образом. Это функция с подстановкой тела.
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_addr
— это первый адрес интервала адресов, а параметр end_addr
— последний адрес интервала.
Очевидно, что если функция find_vma()
возвращает значение NULL
, то это же значение будет возвращать и функция find_vma_intersection()
. Если функция find_vma()
возвращает существующую область VMA, то функция find_vma_intersection()
возвратит ту же область только тогда, когда эта область find_vma()
, начинается после последнего адреса из указанного диапазона, то функция find_vma_intersection()
возвращает значение NULL
.
Функции mmap()
и do_mmap()
: создание интервала адресов
Функция do_mmap()
используется ядром для создания нового линейного интервала адресов. Говорить, что эта функция создает новую область VMA, — технически не корректно, поскольку если создаваемый интервал адресов является смежным с существующим интервалом адресов и у этих интервалов одинаковые права доступа, то два интервала объединяются в один. Если это невозможно, то создается новая область VMA В любом случае функция do_mmap()
— это функция, которая добавляет интервал адресов к адресному пространству процесса, независимо от того, создается ли при этом новая область VMA или расширяется существующая.
Функция do_mmap()
объявлена в файле
следующим образом.
unsigned long do_mmap(struct file *file,
unsigned long addr, unsigned long len,
unsigned long prot,
unsigned long flag,
unsigned long offset);