Когда процесс создается посредством распараллеливания, он стартует со своей директорией страниц и своей страницей. Таким образом программа контроля корректности использования страниц следит почти за всей памятью процесса.
Программа контроля do_page_fault() считывает некорректный адрес из регистра cr2. Код ошибки (считанный в sys_call.S) позволяет определить режим доступа - пользователя/супервизора и причину ошибки - защита записи или неправильная страница. Формирователь управляется do_wp_page() и позднее do_no_page().
Если нарушение адреса превышает TASK_SIZE, процесс получает SIGKILL. [Зачем этот контроль? Такое может произойти только в режиме ядра из-за защиты на уровне сегмента]
Эти процедуры обладают тонкостями т.к. они могут вызываться по прерыванию. Вы не можете предположить, что это текущая задача.
Страница некорректна - страница данных, которая не была загружена.
Во всех случаях в первую очередь вызывается get_empty_pgtable() чтобы гарантировано определить существование таблицы страниц, которая накрывает некорректный адрес. В случае 3 get_empty_page() вызывается чтобы обеспечить страницу с требуемым адресом и в случае замещаемой страницы вызывается swap_in().
В случае 2 программа контроля вызывает share_page(), чтобы посмотреть является ли страница разделяемой каким либо другим процессом. В случае неудачи она считывает страницу из исполняемой программы или библиотеки (Она повторяет вызов shre_page() в случае, если другой процесс делал тем временем то же самое). Любая часть страницы сверх значения brk обнуляется.
Считывание страницы с диска вычисляется как основная ошибка (mjr_flt). Это происходит с swap_in() или когда происходит считывание из выполняемой программы или библиотеки. Другие случаи интерпретируются как второстепенные ошибки (min_flt).
Когда найдена разделяемая страница, то она защищена для записи. Процесс, который пишет в разделяемую страницу, затем должен будет пройти через do_wp_page(), которая выполняет COPY-ON-WRIGHT.
do_wp_page() выполняет следующее:
- посылает SIGSEGV, если какой-либо пользовательский процесс пишет в текущую code_space.
- Если старая страница не разделяется, она становится незащищенной. Иначе get_free_page() и copy_page(). Для страницы устанавливается грязный флаг из старой страницы. Уменьшается значение счетчика карты старой страницы.
6.8. Листание (paging)
Листание (paging) оперирует со страницей в отличии от подкачки (swapping), которая используется в отношении любых процессов. Мы будем использовать здесь термин "подкачка" для того, чтобы ссылаться на листание, т.к. Linux только листает и не замещает, но более привычным является термин "замещать" (swap), чем "листать" (page). Страницы ядра никогда не замещаются. Очищенные страницы также не читаются для замещения. Они освобождаются и перезагружаются, когда требуется. Программа подкачки поддержи вает один бит информации старения, являющимся битом PAGE_ACCESSED во входах таблицы страниц.
Linux использует множество файлов подкачки или устройства, которые могут быть включены и выключены посредством системных вызовов swapon и swapoff. Каждый файл подкачки или устройство описано посредством struct swap_info_struct (swap.c)
static struct swap_info_struct {
unsigned long flags;
struct inode *swap_file;
unsigned int swap_device;
unsigned char *swap_map;
char *swap_lockmap;
int lowest_bit;
int highest bit;
} swap_info[MAX_SWAPFILES];
Поле флагов (SWP_USED или SWP_WRITEOK) используется для управления доступом к файлам подкачки. Когда флаг SWP_WRITEOK сброшен, для этого файла не будет выделяться пространство. Это используется системным вызовом swapoff, когда он делает невозможным использование файла. Когда вызов swapon добавляет новый файл подкачки, то устанавливается SWP_USED. Статическая переменная nr_swapfiles содержит количество активных файлов подкачки. Поля lowest_bit и highest_bit связывают свободные области в файле подкачки и используются, чтобы увеличить скорость поиска свободной области подкачки.
Программа пользователя mkswap инициализирует устройство подкачки или файл. Первая страница включает заголовок ("SWAP-SPACE") в последних 10 байтах и содержит область битмап. Первоначальные нулевые значения в битмап сигнализируют о плохих страница х. "1" в битмап означает, что соответствующая страница свободна. Такой странице память никогда не выделяется, таким образом сразу необходимо провести инициализацию.
Системный вызов swapon() осуществляется из программы пользователя обычно из /etc/rc. Пара страниц памяти выделяется для swap_map и swap_lockmap.
swap_map содержит один байт на каждую страницу файла подкачки. Инициализируется из битмап и содержит 0 для допустимых страниц и 128 для неиспользуемых страниц. Используется для поддержки счета запросов на замещение каждой страницы в файле подкачки. swap_lockmap содержит один бит на каждую страницу, который используется, чтобы гарантировать взаимное исключение при чтении или записи в файл подкачки.
Когда страница памяти готова к тому, чтобы быть замещенной, индекс области замещения получается путем вызова get_swap_page(). Этот индекс затем загружается в биты 1-31 входа таблицы страниц, таким образом замещаемая страница может быть размещена, когда это необходимо, программой контроля корректности использования страниц do_no_page().
Верхние 7 битов индекса дают файл подкачки (или устройство), а нижние 24 бита дают номер страницы на этом устройстве. Это позволяет создавать до 128 файлов, каждый из которых предоставляет область до 64GB, но пространство свыше этого требует, что бы swap_map было бы большим. Вместо этого размер файла подкачки ограничивается 16MB потому, что swap_map тогда занимает 1 страницу.
Функция swap_duplicate() используется в copy_page_tables(), чтобы разрешить дочернему процессу наследовать замещаемые страницы во время распараллеливания. Это сразу увеличивает значение счетчика для этой страницы, поддержанного в swap_map. Каждый процесс будет замещен в отдельной копии страницы при обращении к ней.
swap_free() уменьшает счетчик, поддерживаемый в swap_map. Когда счетчик сбрасывает в 0, страница может быть перезагружена с помощью get_swap_page(). Эта функция вызывается каждый раз, когда замещаемая страница читается в память (swap_in()) или когда страница готова к тому, чтобы быть сброшенной (free_one_table() и т.п.).
[ Назад | Оглавление | Далее ]