Linux Kernel (Ядро линукса) (часть 1)


Выделение интервала линейных адресов

Теперь обсудим, как выделяются новые интервалы линейных адресов. Функция do mmap создает и инициализирует новую область памяти для процесса current. После успешного выделения область памяти может быть слита с другими областями, принадлежащими процессу.

Функция работает со следующими параметрами:

указатель file на файловый объект и смещение offset внутри файла используются, когда новая область памяти должна отображать файл. Эта тема обсуждается в главе 16. В этом разделе мы предполагаем, что отображение файла в память не происходит, и оба параметра равны null;
- addr— этот линейный адрес определяет, откуда должен начаться поиск свободного интервала;
- len — длина интервала линейных адресов;
- prot — этот параметр задает права доступа к страницам, включенным в область памяти. Возможными флагами являются prot read, prot write, prot exec и prot none. Первые три означают то же самое, что флаги
vm_read, vm_write и vm_exec. Флаг prot_none показывает, что у процесса нет ни одного из этих прав;
- flag — этот параметр задает остальные флаги области памяти:
• MAP_GROWS DOWN, MAP_LOCKED, MAP_DENYWRITE И MAP_EXECUTABLE СМЫСЛ
этих флагов аналогичен смыслу флагов, перечисленных в табл. 9.5;
• map shared и map private — первый флаг означает, что страницы в области памяти могут быть совместно использованы несколькими процессами, а второй имеет противоположный эффект. Оба флага связаны С флагом VM_SHARED В дескрипторе vm_area_struct;
• map fixed — начальный линейный адрес интервала должен в точности совпадать с адресом, переданным в параметре addr;
• map anonymous — с областью памяти не ассоциирован никакой файл • map noreserve— функция не обязана производить предварительную проверку свободных страничных кадров;
• map populate — функция должна заранее выделить страничные кадры, необходимые для отображения, устанавливаемого областью памяти.
Этот флаг имеет значение только для областей, отображающих файлы, и областей совместно используемой памяти IPC
• map nonblock— имеет значение, только когда установлен флаг мар_ populate: во время предварительного выделения страничных кадров функцию нельзя блокировать.
Функция do mmapO выполняет некоторые предварительные проверки значения параметра offset, а затем вызывает функцию do mmap pgoff . В этой главе мы предполагаем, что выделяемый интервал линейных адресов не будет отображать файл на диске — отображение файлов. Здесь же мы приведем описание функции do mmap pgoff для анонимных областей памяти.
Функция выполняет следующие действия:
1. Проверяет корректность значений параметров и возможность удовлетворения запроса. В частности, функция проверяет наличие следующих препятствий для выполнения запроса:
• интервал линейных адресов имеет нулевую длину или включает в себя адреса, большие, чем task size;
• процесс уже отобразил слишком много областей памяти. Иначе говоря, значение в поле map count дескриптора памяти mm, принадлежащего этому процессу, превышает максимальную допустимую величину;
• параметр flag показывает, что страницы нового интервала линейных адресов должны быть заблокированы в оперативной памяти, а процессу не разрешено создавать заблокированные области памяти, или количество страниц, заблокированных процессом, превышает порог, значение которого хранится В поле signal->rlim[RLIMIT_MEMLOCK] .rlim_cur ДеСК- риптора процесса.
Если выполнено любое из этих условий, функция do mmap pgoff заканчивает работу, возвращая отрицательное значение. Если интервал линейных адресов имеет нулевую длину, функция возвращает управление, не выполнив никаких действий.
2. Вызывает функцию get unmapped area , чтобы получить интервал линейных адресов для новой области.
3. Вычисляет флаги новой области памяти, комбинируя значения параметров
prot и flags:
vm_flags = calc_vm_prot_bits(prot,flags) | calc_vm_flag_bits(prot,flags) |
mm->def flags | VM MAYREAD | VM MAYWRITE | VM MAYEXEC;
if (flags & MAP_SHARED)
vm_flags |= VM_SHARED | VM_MAYSHARE;
Функция caic_vm_prot_bits о устанавливает флаги vm_read, vm_write и vm exec в поле vm_f lags, только если установлены соответствующие флаги PROT_READ, PROT_WRITE И PROT_EXEC В параметре prot. Функция calc_vm_flag_bits () устанавливает флаги VM_GROWSDOWN, VM_DENYWRITE, VM_EXECUTABLE И VM_LOCKED В ПОЛе vm_f lags, ТОЛЬКО еСЛИ установлены СООТ-
ветствующие флаги map_growsdown, map_denywrite, map_executable и map locked в параметре flags. В поле vm fiags устанавливается еще несколько флагов: vm_mayread, vm_maywrite, vm_mayexec, флаги, устанавливаемые по умолчанию для всех областей памяти и хранящиеся в поле mm->def_f lags5, а также оба флага VM_SHARED И VM_MAYSHARE, если страницы области памяти должны совместно использоваться другими процессами.
4. Вызывает функцию find vma prepare , чтобы найти объект-область памяти, который будет предшествовать новому интервалу, а также позицию новой области в красно-черном дереве:
for (;;) {vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (!vma || vma->vm_start >= addr + len) break;
if (do_munmap (mm, addr, len)) return -ENOMEM;}
Кроме этого, функция find vma prepare проверяет, существует ли область памяти, пересекающаяся с новым интервалом. Это имеет место, когда функция возвращает ненулевой адрес, указывающий на область, которая начинается до конца нового интервала. В таком случае функция do mmap pgoff ВЫЗЫВает do munmap , Чтобы удаЛИТЬ НОВЫЙ интервал И повторяет шаг с начала 5. Проверяет, не приведет ли вставка новой области памяти к ситуации, в которой адресное пространство процесса (mm->total_vm«PAGE_SHIFT) +1еп превышает порог, хранящийся В поле signal->rlim[RLIMIT_AS] .rlim_cur дескриптора процесса. Если проверка дает положительный результат, функция возвращает код ошибки -enomem. Обратите внимание, что провер
ка производится на этом шаге, а не на шаге 1 одновременно с другими проверками. Дело в том, что некоторые области памяти могли быть удалены на шаге .
6. Возвращает код ошибки -enomem, если флаг map noreserve не был установлен в параметре flags, новая область памяти содержит закрытые страницы, доступные для записи, а свободных страничных кадров недостаточно. Эта заключительная проверка выполняется функцией security_vm_
enough_memory.
7. Если новый интервал является закрытым (флаг vm_shared не установлен) и не отображает файл, хранящийся на диске, функция вызывает функцию vma mergeO для проверки, может ли предшествующая область памяти быть расширена так, чтобы она включала в себя новый интервал. Естественно, предшествующая область должна иметь в точности те же флаги, что хранятся в локальной переменной vm fiags. Если предшествующая область памяти может быть расширена, функция vma mergeO одновременно пытается слить ее со следующей областью (это происходит, когда новый интервал заполняет пустоту” между двумя областями памяти, и все три области имеют одинаковые флаги). Если функции удастся расширить предшествующую область памяти, выполнение продолжится с шага .
8. Выделяет структуру vm area struct для новой области памяти, вызывая функцию slab-аллокатора kmem cache alloc о .
9. Инициализирует новый объект-область памяти (на который указывает
vma):
vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; vma->vm_flags = vm_flags;
vma->vm_page_prot = protection_map[vm_flags & OxOf];
vma->vm_ops = NULL;
vma->vm_pgoff = pgoff;
vma->vm_file = NULL;
vma->vm_private_data = NULL;
vma->vm_next = NULL;
INIT_LIST_HEAD(&vma->shared);
10. Если флаг map_shared установлен (и новая область памяти не отображает файл, хранящийся на диске), значит, область является анонимной и совместно используемой. Для ее инициализации функция вызывает функцию shmem zero setup . Анонимные совместно используемые области
применяются, в основном, для межпроцессного взаимодействия
11. Вызывает функцию vma iinko для занесения новой области в список областей памяти и красно-черное дерево.
12. Увеличивает размер адресного пространства процесса в поле totai vm дескриптора памяти.
13. Если флаг vm locked установлен, функция вызывает функцию make pages presentо, чтобы выделить все страницы области памяти подряд и заблокировать их:
if (vm_flags & VM_LOCKED) {nun->locked_vm += len » PAGE_SHIFT; make_pages_present(addr, addr + len);}
Функция makepagespresent о, В СВОЮ Очередь, ВЫЗЫВает функцию
get_user_pages():write = (vma->vm_flags & VM_WRITE) != 0;
get_user_pages(current, current->mm, addr, len, write, 0, NULL, NULL);
Функция get user pages () перебирает в цикле все начальные линейные адреса страниц между addr и addr+ien. Для каждого из них она вызывает функцию foiiow_page(), чтобы проверить, имеется ли отображение в физическую страницу в Таблицах Страниц процесса current. Если такой физической страницы нет, функция get user pages вызывает функцию handie mm fauit о, которая, как мы увидим в разд. "Обработка ошибочного адреса внутри адресного пространства", выделяет один страничный кадр и заполняет запись Таблицы Страниц в соответствии с полем vm_f lags дескриптора области памяти.
14. В завершение своей работы функция возвращает линейный адрес новой области памяти.
Освобождение интервала линейных адресов
Когда ядро должно удалить интервал линейных адресов из адресного пространства текущего процесса, оно вызывает функцию do munmapO, которая принимает следующие параметры: адрес mm дескриптора памяти процесса, начальный адрес интервала start и его длину len. Интервал, подлежащий удалению, обычно не соответствует какой-то конкретной области памяти; он может находиться внутри одной области или охватывать несколько областей.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...