Функция try_to_unuse
Функция try to unuse принимает в качестве параметра индекс, идентифицирующий область подкачки, подлежащую переводу в неактивное состояние.
Она загружает выгруженные страницы и обновляет все Таблицы Страниц, которые выгружали страницы в эту область. С этой целью функция просматривает адресные пространства всех потоков ядра и процессов, начиная с дескриптора памяти init mm, используемого в качестве маркера. Эта функция выполняется очень долго, как правило, с разрешенными прерываниями. Поэтому очень важна синхронизация с другими процессами.
Функция try to unuse о перебирает элементы массива swap map области подкачки. Когда она находит используемый страничный слот, она вначале загружает страницу в память, а затем начинает поиск процессов, ссылающихся на эту страницу. Порядок этих двух операций исключительно важен для избежания конфликтов одновременного обращения. Пока выполняется операция ввода/вывода, страница остается заблокированной, и ни один процесс не может к ней обратиться. Когда ввод/вывод закончен, страница снова блокируется функцией try to unuse о, чтобы ее не мог выгрузить какой-нибудь управляющий тракт ядра. Конфликта удается избежать, поскольку каждый процесс просматривает кэш страниц перед запуском операции выгрузки или загрузки (см. разд. "Кэш подкачки" далее в этой главе). Наконец, функция try to unuse о помечает рассматриваемую область подкачки как область, в которую запрещена запись (флаг swp writeok сброшен), и ни один процесс не может выполнить выгрузку в страничные слоты этой области.
Впрочем, функция try to unuse о может быть вынуждена несколько раз перебрать элементы массива swap map, содержащего счетчики области подкачки. Это может произойти, если какие-то области памяти, хранящие ссылки на выгруженные страницы, исчезнут во время одного перебора элементов, а впоследствии снова появятся в списках процессов.
Вспомним, например, описание функции do munmapO Как только какой-нибудь процесс освобождает интервал линейных адресов, функция do munmap удаляет из списка процесса все области памяти, включавшие линейные адреса, затронутые в этой операции. Впоследствии функция снова заносит в список процесса области памяти, которые были освобождены лишь частично. Функция do munmapO отвечает за освобождение выгруженных страниц, принадлежащих интервалу освобожденных линейных адресов. Она достойна похвалы за то, что не освобождает выгруженные страницы, принадлежащие областям памяти, которые должны будут вернуться в список процесса.
Итак, функция try_to_unus, возможно, не сумеет найти процесс, ссылающийся на данный страничный слот из-за того, что соответствующая область памяти будет временно отсутствовать в списке процесса. Чтобы справиться с этой ситуацией, функция try to unuse о продолжает перебор элементов массива swap map, пока все счетчики ссылок не примут нулевые значения. В конце концов, "призрачные” области памяти, на которые ссылаются выгруженные страницы, снова появятся в списках процессов, и функция try to unuse о успешно освободит все страничные слоты.
Теперь мы опишем основные действия, выполняемые функцией try_to_ unuse Она входит в цикл по счетчикам ссылок в массиве swap map области подкачки, полученной через параметр. Этот цикл прерывается, и функция возвращает код ошибки, если текущий процесс получает сигнал. Для каждого счетчика ссылок функция выполняет следующие действия:
1. Если счетчик равен нулю (нет страниц) или значению swap map bad, функция переходит к следующему страничному слоту.
2. В противном случае Она вызывает функцию read_swap_cache_async , чтобы загрузить страницу в память. Операция загрузки состоит из выделения нового страничного кадра, если это необходимо, и заполнения его данными из страничного слота и занесения страницы в кэш страниц.
3. Затем функция ждет, пока новая страница не будет корректно заполнена данными с диска, и блокирует ее.
4. Пока функция находилась на предыдущем шаге, выполнение процесса могло быть приостановлено. Поэтому функция снова проверяет, равен ли нулю счетчик ссылок страничного слота. Если равен, значит, эта страница была освобождена другим управляющим трактом ядра, и функция переходит к следующему страничному слоту.
5. Вызывает функцию unuse process о для каждого дескриптора памяти в двунаправленном списке, голова которого находится в поле init mm Эта функция, требующая очень много времени, сканирует все записи Таблицы Страниц процесса, владеющего данным дескриптором памяти, и заменяет каждое вхождение идентификатора выгруженной страницы на физический адрес страничного кадра. Для отражения этих действий функция также уменьшает счетчик страничного слота в массиве swap map (если он не равен swap map max) и увеличивает счетчик ссылок страничного кадра.
6. Вызывает функцию shmem unuse , чтобы проверить, является ли выгруженная страница совместно используемой при межпроцессном взаимодействии, и корректно обработать эту ситуацию
7. Проверяет значение счетчика ссылок страницы. Если оно равно swap_map_ мах, значит, страничный слот является постоянным”. Чтобы освободить его, функция своей властью записывает единицу в счетчик ссылок.
8. Кэш подкачки тоже может владеть страницей (в этом случае он участвовал в увеличении счетчика ссылок). Если страница принадлежит кэшу подкачки, функция вызывает функцию swap writepage для сброса содержимого страницы на диск (если страница "грязная”) и функцию deiete from swap cache о для удаления страницы из кэша подкачки и уменьшения ее счетчика ссылок.
9. Устанавливает флаг PG dirty дескриптора страницы, снимает блокировку со страничного кадра и уменьшает его счетчик ссылок (чтобы компенсировать увеличение, выполненное на шаге 5).
10. Проверяет флаг tif need resched текущего процесса. Если он установлен, вызывает функцию schedule о, чтобы освободить процессор. Перевод области подкачки в неактивное состояние является долгим делом, и ядро должно позволить другим процессам в системе выполняться, как им нужно. С этого шага функция try to unuse о продолжит свое выполнение после того, как данный процесс снова будет выбран планировщиком.
11. Переходит к шагу 1 и рассматривает следующий страничный слот.
Функция продолжает работу, пока каждый счетчик ссылок в массиве swap map не примет нулевое значение. Вспомним, что даже если функция приступит к рассмотрению следующего страничного слота, счетчик ссылок предыдущего слота может остаться положительным. Дело в том, что призрачный” процесс может по-прежнему ссылаться на страницу, чаще всего из- за того, что некоторые области памяти были временно удалены из списка процесса, просмотренного на шаге 5. В конце концов, функция try_to_ unuse о отловит” все ссылки. Тем временем, однако, страница уже не находится в кэше подкачки, она разблокирована, а ее копия все еще хранится в страничном слоте области подкачки, переводимой в неактивное состояние.
Можно ожидать, что такая ситуация приведет к потере данных. Например, предположим, что некоторый призрачный процесс обращается к страничному слоту и начинает загружать выгруженную страницу. Поскольку страницы больше нет в кэше подкачки, процесс заполняет новый страничный кадр данными, прочитанными с диска. Однако этот страничный кадр будет отличаться от страничных кадров, принадлежащих процессам, которые, как предполагается, используют эту страницу совместно с призрачным процессом.
Эта проблема не возникает при переводе области подкачки в неактивное состояние, потому что вмешательство со стороны призрачного процесса может произойти, только если выгруженная страница принадлежит закрытому анонимному отображению в память9. В таком случае страничный кадр обраба
тывается с помощью механизма копирования при записи”, описанного в главе 9, и поэтому вполне допустимо присваивать различные страничные кадры процессам, ссылающимся на страницу. Однако функция try_to_unuse помечает страницу как грязную (шаг 9), иначе функция shrink iist о может впоследствии удалить страницу из Таблицы Страниц какого-нибудь процесса, не сохранив ее в другой области подкачки.
Предыдущая страница | 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 108 109 110 111 | Следующая страница