Зоны

Зоны

В связи с ограничениями аппаратного обеспечения, ядро не может рассматривать все страницы памяти как идентичные. Некоторые страницы, в связи со значениями их физических адресов памяти, не могут использоваться для некоторых типов задач. Из-за этого ограничения ядро делит физическую память на зоны. Ядро использует зоны, чтобы группировать страницы памяти с аналогичными свойствами. В частности, операционная система Linux должна учитывать следующие недостатки аппаратного обеспечения, связанные с адресацией памяти.

• Некоторые аппаратные устройства могут выполнять прямой доступ к памяти (ПДП, DMA, Direct Memory Access) только в определенную область адресов.

• На некоторых аппаратных платформах для физической адресации доступны большие объемы памяти, чем для виртуальной адресации. Следовательно, часть памяти не может постоянно отображаться в адресное пространство ядра.

В связи с этими ограничениями, в операционной системе Linux выделяют три зоны памяти.

• ZONE_DMA. Содержит страницы, которые совместимы с режимом DMA.

• ZONE_NORMAL. Содержит страницы памяти, которые отображаются в адресные пространства обычным образом.

• ZONE_HIGHMEM. Содержит "верхнюю память", состоящую из страниц, которые не могут постоянно отображаться в адресное пространство ядра.

Эти зоны определяются в заголовочном файле <linux/mmzone.h>.

То, как используется разделение памяти на зоны, зависит от аппаратной платформы. Например, для некоторых аппаратных платформ нет проблем с прямым доступом к памяти ни по какому адресу. Для таких платформ зона ZONE_DMA является пустой, и для всех типов выделения памяти используется зона ZONE_NORMAL.

Как противоположный пример можно привести платформу x86, для которой устройства ISA[61] не могут выполнять операции DMA в полном 32-разрядном пространстве адресов, так как устройства ISA могут обращаться только к первым 16 Мбайт физической памяти. Следовательно, зона ZONE_DMA для платформы x86 содержит только страницы памяти с физическими адресами в диапазоне 0-16 Мбайт.

Аналогично используется и зона ZONE_HIGHMEM. To, что аппаратная платформа может отображать и чего она не может отображать в адресное пространство ядра, отличается для разных аппаратных платформ. Для платформы x86 зона ZONE_HIGHMEM — это вся память, адреса которой лежат выше отметки 896 Мбайт. Для других аппаратных платформ зона ZONE_HIGHMEM пуста, так как вся память может непосредственно отображаться. Память, которая содержится в зоне ZONE_HIGHMEM, называется верхней памятью[62] (high memory). Вся остальная память в системе называется нижней памятью (low memory).

Зона ZONE_NORMAL обычно содержит все, что не попало в две предыдущие зоны памяти. Для аппаратной платформы x86, например, зона ZONE_NORMAL содержит всю физическую память от 16 до 896 Мбайт. Для других, более удачных аппаратных платформ, ZONE_NORMAL — это вся доступная память. В табл. 11.1 приведен список зон для аппаратной платформы x86.

Таблица 11.1. Зоны памяти для аппаратной платформы x86

Зона Описание Физическая память ZONE_DMA Страницы памяти, совместимые с ПДП < 16 Мбайт ZONE_NORMAL Нормально адресуемые страницы 16 - 896 Мбайт ZONE_HIGHMEM Динамически отображаемые страницы > 896 Мбайт

Операционная система разделяет страницы системной памяти на зоны, чтобы иметь пулы страниц для удовлетворения требований выделения памяти. Например, пул зоны ZONE_DMA дает возможность ядру удовлетворить запрос на выделение памяти, которая необходима для операций DMA. Если нужна такая память, ядро может просто выделить необходимое количество страниц из зоны ZONE_DMA. Следует обратить внимание, что зоны не связаны с аппаратным обеспечением— это логическое группирование, которое позволяет ядру вести учет страниц; памяти.

Хотя некоторые запросы на выделение памяти могут требовать страницы из определенной зоны, это требование не обязательно может быть жестким. Например, выделение памяти для ПДП требует страницы из зоны ZONE_DMA, а для обычного выделения памяти могут подойти страницы как из зоны ZONE_NORMAL так и из зоны ZONE_DMA. Конечно, для удовлетворения запросов по обычному выделению памяти ядро будет стараться выделять страницы из зоны ZONE_NORMAL, чтобы сохранить страницы в зоне ZONE_DMA для случая, когда эти страницы действительно нужны, Если же наступает решающий момент (становится недостаточно памяти), то ядро может обратиться к любой доступной и подходящей зоне.

Каждая зона представлена с помощью структуры struct zone, которая определена в файле <linux/mmzone.h> в следующем виде.

struct zone {

 spinlock_t             lock;

 unsigned long          free_pages;

 unsigned long          pages_min;

 unsigned long          pages_low;

 unsigned long          pages_high;

 unsigned long          protection[MAX_NR_ZONES];

 spinlock_t             lru_lock;

 struct list_head       active_list;

 struct list_head       inactive_list;

 unsigned long          nr_scan_active;

 unsigned long          nr_scan_inactive;

 unsigned long          nr_active;

 unsigned long          nr_inactive;

 int                    all_unreclaimable;

 unsigned long          pages_scanned;

 int                    temp_priority;

 int                    prev_priority;

 struct free_area       free_area[MAX_ORDER];

 wait_queue_head_t      *wait_table;

 unsigned long          wait_table_size;

 unsigned long          wait_table_bits;

 struct per_cpu_pageset pageset[NR_CPUS];

 struct pglist_data     *zone_pgdat;

 struct page            *zone_mem_map;

 unsigned long          zone_start_pfn;

 char                   *name;

 unsigned long          spanned_pages;

 unsigned long          present_pages;

};

Эта структура большая, но в системе всего три зоны и соответственно три такие структуры. Рассмотрим наиболее важные поля данной структуры.

Поле lock— это спин-блокировка, которая защищает структуру от параллельного доступа. Обратите внимание, что она защищает только структуру, а не страницы, которые принадлежат зоне. Для защиты отдельных страниц нет блокировок, хотя отдельные части кода могут блокировать данные, которые могут оказаться в указанных страницах.

Поле free_pages — это количество свободных страниц в соответствующей зоне. Ядро старается поддерживать свободными хотя бы pages_min страниц зоны, если это возможно (например, с помощью вытеснения на диск).

Поле name — это строка, оканчивающаяся нулем, которая содержит имя соответствующей зоны (что не удивительно). Ядро инициализирует указанное поле при загрузке системы с помощью кода, который описан n файле mm/page_alloc.с. Три зоны имеют имена "DMA", "Normal" и "HighMem".