Страницы
В качестве базовой единицы памяти, которой управляет менеджер памяти, страница обладает большим количеством состояний, за которыми необходимо следить. Например, ядру необходимо знать, когда страница становится свободной для повторного выделения. Для этого ядро использует описатель страниц. Каждой физической странице в памяти назначается свой описатель страницы.
Этот раздел описывает различные поля в описателе страницы и то как их использует менеджер памяти. Структура страницы определена в include/linux/mm.h.
include/linux/mm.h
170 struct page {
171 unsigned long flags;
172
173 atomic_t count;
174 struct list_head list;
175 struct address_space *mapping;
176 unsigned long index;
177 struct list_head lru; 178
179 union {
180 struct pte_chain *chain;
181
182 pte_addr_t direct;
183 } pte;
184 unsigned long private; 185
196 #if defined(WANT_PAGE_VIRTUAL)
197 void *virtual;
198
199 #endif
200 };
Глава 4• Управление памятью
Flags
Атомарные флаги описывают состояние страниц фреймов. Каждый флаг представлен одним битом 32-битового значения. Некоторые вспомогательные функции позволяют нам манипулировать отдельными флагами и тестировать их. Кроме этого, некоторые вспомогательные функции позволяют нам получать доступ к значениям битов, соответствующих отдельным флагам. Сами флаги, как и вспомогательные функции, определены в include/linux/page-flags.h. Табл. 4.1 описывает некоторые флаги, которые могут быть установлены в поле flags структуры страницы.
Таблица 4.1. Значение flag для page->flags
Флаг
Описание
PG_locked
PG_error PG_referenced
PG__uptodate
PG_dirty PG_lru
PG_active PG_slab
PG_highmem
Страница заблокирована, и ее нельзя трогать. Этот бит используется при вводе-выводе на диск, устанавливается перед операцией ввода-вывода и снимается после нее
Обозначает, что для этой страницы произошла ошибка
Обозначает, что эта страница была запрошена для выполнения операции ввода-вывода. Используется для определения того, находится ли страница в списке активных или неактивных страниц
Обозначает, что содержимое страницы верно и устанавливается после операции чтения в эту страницу. Этот флаг взаимоисключаем с PG_error
Обозначает модифицированную страницу
Страница находится в списке наименее часто используемых [least recently used (lru) ]. См. более подробное описание структуры lru далее в этом разделе
Обозначает, что страница находится в списке активных страниц
Эта страница принадлежит к блоку памяти, созданному выделителем блоков, описывается в разделе «Выделение секций» в этой главе
Означает что эта страница находится в верхней области памяти (ZONE_HIGHMEM) и поэтому не может быть сразу отображена в виртуальное адресное пространство ядра. Страницы из верхней области памяти определяются во время загрузки в mem_init () (см. подробности в гл. 8, «Загрузка ядра»)
PG_checked
Элемент файловой системы ext2. Убран в версии 2.5
PG_arch_l
Бит архитектурно-специфического состояния страницы
Страницы
Таблица 4.1. Значение flag для page->flags (Окончание)
PG_reserved Помечает страницу, которую нельзя выгрузить в своп память, которая
не существует или выделена при загрузке системы
PG_private Обозначает, что страница верна и устанавливается, если
page->private содержит правильное значение
PG_writeback Обозначает, что страница перезаписывается
PG_mappedtodisk Эта страница содержит блоки, выделенные на системном диске
PG_reclaim Обозначает, что страницу можно перераспределить
PG_compound Обозначает, что страница является частью страницы более высокого
уровня
Count
Поле count служит в качестве счетчика ссылок на страницу. Значение 0 означает, что фрейм станицы доступен для повторного использования. Положительное значение означает количество процессов, могущих получить доступ к данным этой страницы1.
List
Поле list - это структура, хранящая указатели на следующий и предыдущий элементы двусвязного списка. Двусвязный список, к которому принадлежит данная страница, определяется частью, связанной с состоянием страницы.
Mapping
Каждая страница может быть ассоциирована со структурой address_space, хранящей информацию для отображения файла в память. Поле mapping является указателем на address_space, членом которого является данная страница; address_space - это набор страниц, принадлежащих объекту памяти (например, inode). Более подробно использование address_space описывается в гл. 7, «Планировщик и синхронизация ядра», в подразд. 7.14.
Iru
Поле Iru хранит указатели на следующий и предыдущий элементы в списке последних использованных (Least Recently Used, LRU). Этот список связан с перераспределением памяти и состоит из двух списков: active_list, содержащего используемые страницы, и inactive_list, хранящего страницы, годные для повторного использования.
1 Страница освобождается, когда хранимые в ней данные больше не требуются.
Глава 4 • Управление памятью
4.1.1.5 virtual
virtual - это указатель на соответствующий странице виртуальный адрес. В системе с верхней памятью1, отображение памяти может выполняться динамически, для чего необходимо выполнять перерасчет виртуального адреса. В этом случае это значение становится равным NULL.
Составные страницы
Составные страницы - это страницы более высокого уровня. Для включения поддержки составных страниц в ядре во время компиляции необходимо включить «Huge TLB Page Support». Составные страницы объединяют более одной страницы, первая из которых называется головной страницей, а последняя хвостовой страницей. У всех составных страниц устанавливается бит PG_compound в page->f lags, a page->lru. next указывает на голову страницы.
Зоны памяти
Не все создаваемые страницы равноценны. На некоторых компьютерных архитектурах определены константы, в рамках которых можно использовать некоторые физические адреса. Например, на х86 некоторые шины ISA могут адресовать только 16 Мб оперативной памяти. Несмотря на то что на РРС таких констант нет, концепция зон памяти портируется и на эту платформу для упрощения архитектурно-независимой части кода. В архитектурно-зависимой части РРС кода эти зоны перекрываются. Другие подобные константы могут использоваться, если в системе присутствует больше оперативной памяти, чем можно адресовать линейным способом.
Зоны памяти составляются из фреймов страниц или физических страниц, поэтому фреймы страниц выделяются из определенных зон памяти. В Linux существует три зоны памяти: ZONE__DMA (использующая фреймы страниц DMA), ZONE_NORMAL (не DMA-страницы с виртуальным отображением в память) и ZONE_HIGHMEM (страницы, чьи адреса не находятся в пространстве виртуальных адресов).
Описатель зоны памяти
Как и любой объект, управляемый ядром, зона памяти имеет структуру zone, хранящую всю информацию об этой зоне. Структура zone определена в include/linux/ mmzone.h. Далее мы рассмотрим поближе несколько наиболее часто используемых полей этой структуры:
1 Верхняя память - это физическая память, которая превышает адресуемое виртуально пространство. См. разд. 4.2, «Зоны памяти».
Зоны памяти
include/linux/mmzone.h бб struct zone {
70 spinlock_t lock;
71 unsigned long free_pages;
72 unsigned long pages_min/ pages_low, pages_high; 73
74 ZONE_PADDING (_padl_)
75
76 spinlock_t lru_lock;
77 struct list_head active_JList;
78 struct list_head inactive_list;
79 atomic_t refill_counter;
80 unsigned long nr_active;
81 unsigned long nr_inactive;
82 int all_unreclaimable; /* Все страницы закрепляются */
83 unsigned long pages_scanned; /* с момента последнего восстановления */ 84
85 ZONE_PADDING (_pad2_)
103 int temp_priority;
104 int prev__priority;
109 struct free_area free_area[MAX_ORDER];
135 wait_queue_head_t * wait_table;
13 6 unsigned long wait_table_size;
137 unsigned long wait_table_bits;
13 9 ZONE_PADDING (_pad3_)
157 } ____ cacheline_maxaligned_in_smp;
Lock
Описатель зоны нужно блокировать во время работы с этой зоной для предотвращения ошибок чтения-записи. Поле lock хранит кольцевую блокировку, защищающую описатель от этих ошибок.