netlib.narod.ru | < Назад | Оглавление | Далее > |
В Linux ведется отсортированный по приоритету список действительных устройств свопинга (и файлов, но для простоты в настоящем разделе мы часто называем «устройствами» и то, и другое). Когда возникает необходимость распределить страницу свопинга, Linux распределяет ее на устройстве свопинга с наивысшим приоритетом, которое еще не заполнено.
В системе Linux также выполняется циклический переход от одного незаполненного устройства свопинга с равным приоритетом к другому, то есть применяется ротация устройств свопинга, что позволяет повысить производительность свопинга путем распределения запросов страничного обмена по нескольким дискам. Во время ожидания, пока один диск выполняет первый запрос, второй запрос отправляется к следующему диску. Поэтому оптимальная настройка состоит в распределении разделов свопинга по нескольким аналогичным дискам и присвоении им одинакового приоритета; более медленные диски должны иметь более низкий приоритет.
Однако ротация может также замедлять свопинг. Если несколько устройств свопинга на одном и том же диске имеют одинаковый приоритет, приходится снова и снова перемещать головки чтения/записи диска от одного устройства свопинга на диске к другому; именно в такой ситуации печально знаменитый коэффициент различия в скорости между оперативной памятью и диском, составляющий порядка 1000000, почти невозможно замаскировать.
К счастью, системный администратор может избежать этой проблемы, правильно распределив приоритеты свопинга. Истинный наследник Unix, система Linux всегда предоставляет системному администратору возможность сделать свою жизнь невыносимой, но она также всегда позволяет стать истинным триумфатором.
Простейшая схема состоит в присвоении каждому устройству свопинга на одном и том же диске разных значений приоритета; это позволяет избежать наихудших ситуаций, но вместе с тем, вероятно, не будет являться наилучшим решением.
Однако, поскольку это несложно и позволяет избежать наихудшего варианта, такой принцип применяется в системе по умолчанию, если администратор сам не назначает приоритеты.
Устройства свопинга представлены типом struct swap_info_struct (строка 17554). Массив этих объектов struct swap_info определен в строке 37834. Функции в различных файлах манипулируют и используют swap_info для управления свопингом; мы приступим к их изучению чуть позже. Однако эти функции станут намного более понятными, если вначале мы изучим некоторые члены объекта struct swap_info_struct:
Член объекта swap_list, определенный в строке 37832, включает индекс заголовка списка (т.е. его заглавный член — см. определение объекта struct swap_list_t в строке 17627); этот индекс равен –1, если список пуст. Он также включает член со сбивающим с толку названием next, который позволяет определить следующее устройство свопинга, на котором мы должны попытаться распределить страницу. Поэтому данный член next представляет собой итеративный курсор. Он равен –1, если список пуст или если в настоящее время пространство свопинга заполнено.
37879: Функция get_swap_page получает страницу на доступном незаполненном устройстве свопинга с наивысшим приоритетом; она возвращает ненулевой код с описанием входа, если таковой найден, или 0, если в системе пространство свопинга заполнено.
37885: Позволяет продолжить итерацию с того места, где она закончилась в последний раз. Если список пуст или не осталось больше места для свопинга, функция здесь выполняет возврат.
37891: Иначе, есть основания надеяться, что где-то еще есть пространство для свопинга и функции get_swap_page остается только его найти. Прохождение по этому циклу повторяется до тех пор, пока функция не найдет свободный вход (что более вероятно) или не просмотрит каждое устройство свопинга и придет к заключению, что ни на одном из них не осталось свободного места (что менее вероятно).
37894: Просмотр массива swap_map текущего устройства свопинга в поисках свободного элемента с использованием функции scan_swap_map (строка 37838), которая также обновит члены lowest_bit и highest_bit, если такой вход будет найден. Параметр offset будет содержать либо 0, либо возвращаемый вход.
37897: Текущее устройство свопинга смогло распределить страницу. Теперь функция get_swap_page наращивает итеративный курсор члена swap_list, чтобы запросы правильно распределялись между устройствами свопинга. Если достигнут конец списка данного устройства свопинга или следующее устройство свопинга имеет более низкий приоритет по сравнению с текущим, итерация возобновляется с начала списка. Это влечет за собой два важных последствия:
37910: На текущем устройстве не было места для свопинга или текущее устройство не было доступно для записи (что в данном контексте означает одно и то же). Поэтому ядро переходит к следующему устройству и возвращается в начало списка, если достигнут его конец и возврат в начало еще не произошел.
37916: Если функция get_swap_page достигла конца списка и уже один раз возвращалась в его начало, это значит, что она просмотрела все устройства свопинга и не нашла ни на одном из них свободного места. Поэтому она должна сделать вывод, что больше нет места для свопинга и возвратить 0.
37923: Функция swap_free — это противоположность функции get_swap_page; она освобождает один вход свопинга.
37939: Выполнив ряд простых проверок непротиворечивости параметров, функция swap_free проверяет, не имеет ли устройство, на котором она освобождает страницу свопинга, более высокий приоритет свопинга по сравнению с устройством, которое должно рассматриваться следующим. Если это действительно так, она воспринимает это в качестве указания о том, что нужно переустановить итератор объекта swap_list на начало списка. Следующее обращение функции get_swap_page, начиная с начала списка, обнаружит вновь освобожденное пространство с более высоким приоритетом.
37944: Корректировка членов lowest_bit и/или highest_bit, если вновь освобожденная страница лежит за определенными ими пределами. Можно видеть, что если функция swap_free освобождает страницу на устройстве, которое перед этим было полностью заполнено, она обычно корректирует либо lowest_bit, либо highest_bit, но не оба эти члена. В результате диапазон становится шире, чем он должен быть, и поэтому распределение страниц свопинга может стать немного медленнее, чем должно быть. Но это происходит крайне редко. Так или иначе, диапазон принимает более правильные значения по мере распределения и освобождения дополнительного числа страниц свопинга.
37950: Подсчет коэффициента использования каждого элемента массива swap_map ведется только вплоть до максимума, SWAP_MAP_MAX (это значение установлено директивой #define равным 32767 в строке 17551). После достижения этого максимума ядро не знает, насколько выше может быть истинный коэффициент использования; поэтому оно не может безопасно уменьшать это значение. Иначе, функция swap_free уменьшает коэффициент использования и увеличивает общее число свободных страниц.
38161: Функция sys_swapoff удаляет указанное устройство или файл свопинга из списка устройств свопинга, если это возможно.
38178: Поиск в списке объектов swap_info_structs соответствующего входа, установка р в качестве указателя на этот элемент, type в качестве индекса этого элемента и prev в качестве индекса предшествующего элемента, prev равен –1 при удалении первого элемента.
38195: Если функция sys_swapoff просмотрела весь список и не нашла соответствия, то ей, безусловно, было передано недействительное имя. Она возвращает ошибку.
38198: Если член prev имеет отрицательное значение, функция sys_swapoff удаляет первый элемент в списке; она соответствующим образом обновляет swap_list.head. Это, вероятно, эквивалентно
swap_list.head = swap_info[swap_list.head].next
но быстрее, поскольку требует меньшего числа операций разадресации.
38203: Если удаляемое устройство является тем следующим устройством, на котором ядро в ином случае попыталось бы выполнить свопинг, итеративный курсор переустанавливается на начало списка. Это может слегка замедлить выполнение следующего распределения, но не слишком значительно; так или иначе, этот случай на практике должен встречаться крайне редко.
38209: Если устройство нельзя было освободить, поскольку оно все еще используется, его восстанавливают на соответствующем месте в списке. Если это было одно из нескольких устройств свопинга с одинаковым приоритетом, оно может в конечном итоге оказаться не в том же относительном положении, как прежде: скажем, оно станет первым устройством с этим приоритетом, а не последним, но все еще будет находиться в порядке сортировки по приоритетам. Создается впечатление, что действие по удалению элемента из списка устройств свопинга, когда есть еще вероятность, что его придется сразу же возвращать назад, является довольно расточительным: почему бы не подождать, пока мы не сможем убедиться, что его действительно можно удалить? Ответ состоит в том, что вызов функции try_to_unuse (строка 38105) в предыдущей строке может привести, через цепочку вызовов функций, к прохождению по swap_list. Код, который приведет к выполнению этого, может оказаться в неопределенном состоянии, если к данному моменту удаляемое устройство свопинга все еще будет находиться в массиве swap_list.
38223: Если это свопинг в разделе диска, функция sys_swapoff освобождает свою ссылку на него.
38244: Функция sys_swapoff заканчивает свою работу, обнуляет поля и освобождает распределенную память. В частности, в этой строке выполняется очистка бита SWP_USED, чтобы ядро могло узнать, что устройство свопинга не доступно для использования, если оно будет пытаться снова выполнить на него свопинг. Затем функция sys_swapoff очищает индикатор err и готовится вернуть код успешного выполнения.
38300: Функция sys_swapon, противоположность функции sys_swapoff, добавляет устройство или файл свопинга к списку системы.
38321: Поиск неиспользуемого входа. Это довольно тонкая операция. На основании имени nr_swapfiles можно сделать вывод, что это — число используемых файлов (или устройств) свопинга, но это не так. В действительности, это максимальное индексное значение члена swap_info, которое встретилось до настоящего времени; оно никогда не уменьшается. (Это значение позволяет отслеживать верхнюю отметку данного массива.) Поэтому циклический проход по всем этим входам в массиве swap_info должен либо обнаружить неиспользуемый вход, либо оставить р, после последнего наращивания цикла, указывающим на адрес после входа nr_swapfiles. В последнем случае, если значение nr_swapfiles меньше MAX_SWAPFILES, это значит, что все используемые входы компактно расположены в левой части массива, и цикл оставляет р указывающим на свободный слот в правой части. Когда это происходит, выполняется обновление nr_swapflles. Интересно, что этот цикл все равно работал бы правильно, даже если бы значение nr_swapfiles представляло собой число активных устройств свопинга, а не верхнюю отметку. Однако если мы изменим смысл переменной nr_swapfiles, то будет нарушена работа кода в другом месте этого файла.
38328: В массиве swap_info был найден неиспользуемый вход; теперь функция sys_swapon начинает его заполнять. Некоторые из представленных здесь значений изменятся.
38338: Если бит SWAP_FLAGS_PREFER установлен, то желаемый приоритет закодирован в младших 15 битах переменной swap_flags. (Константы, используемые в этой и в нескольких следующих строках, определены, начиная со строки 17510.) Иначе приоритет не был задан. Как было упомянуто ранее, в этом случае применяемое по умолчанию действие состоит просто в присвоении каждому новому устройству постепенно уменьшающегося приоритета в надежде получить приемлемую производительность свопинга без помощи человека.
38344: Проверка того, что файл или устройство, которое ядро предполагает применить для свопинга, может быть открыто.
38352: Проверка того, предоставлен ли функции sys_swapon файл или раздел. Если функция S_ISBLK возвращает true, это блочное устройство представляет собой раздел диска. В этом случае функция sys_swapon должна проверить, можно ли открыть это блочное устройство и не выполняет ли ядро уже на нем свопинг.
38375: Аналогичным образом, если это не раздел, функция sys_swapon должна проверить, что это обычный файл. Если это так, она должна проверить, что ядро уже не выполняет свопинг в этот файл.
38384: Если обе проверки оканчиваются неудачей, функция sys_swapon не получила запрос выполнить свопинг в допустимый раздел диска или файл; она отвергает попытку.
38396: Чтение заголовка страницы с устройства свопинга в объект swap_header; это объект типа union swap_header, который определен в строке 17516.
38400: Проверяет логическую последовательность байтов, которая сообщает, к какой версии относится этот заголовок свопинга. Эту последовательность байтов записывает программа mkswap.
38412: Свопинг версий 1. Здесь страница заголовка рассматривается как большое битовое отображение, в котором каждый бит представляет применимую страницу для использования в остальной части устройства. Страница заголовка, как и все страницы, имеет размер 4 Кбайт или 32 Кбит. Поскольку каждый бит представляет одну страницу, на устройстве можно размещать 32768 страниц с общим объемом 128 Мб в расчете на одно устройство свопинга. (Фактически, немного меньше, поскольку последние 10 байтов заголовка отведены для сигнатуры, и поэтому мы не можем предполагать, что доступны соответствующие 80 страниц; для свопинга также нельзя использовать страницу заголовка.) Если устройство меньше этого размера, некоторые из битов в заголовке просто не будут использоваться. В строке 38417 функция входит в цикл для проверки того, какие страницы являются применимыми, и для установки значений членов lowest_bit, highest_bit и создаваемого ей объекта swap_info_struct.
Отметим, что битовое отображение заголовка не поддерживается вечно: в действительности, оно освобождается после выхода из функции sys_swapon. Ядро использует отображение свопинга для отслеживания того, какие страницы используются; это битовое отображение заголовка используется только для установки lowest_bit и других членов объекта swap_info_struct.
38427: Распределяет отображение свопинга и устанавливает все его коэффициенты использования в 0.
38440: Свопинг версии 2 существено ослабляет ограничения на размер области свопинга (максимальный размер составляет около 2 Гб), а также предусматривает хранение информации заголовка немного более естественным и эффективным способом. В этом случае член info объекта swap_header содержит информацию, необходимую для функции sys_swapon.
38451: Это новая версия заголовка свопинга не требует от функции sys_swapon, чтобы она рассматривала заголовок как битовое отображение для вычисления значений lowest_bit, highest_bit и max — значение lowest_bit всегда равно 1, а другие два значения можно вычислить за постоянное время из информации, явно хранимой в заголовке. Это и быстрее, и проще по сравнению с циклом, который проверяет 32768 битов и выполняет вдвое больше присваиваний! Тем не менее, эта и остальная работа концептуально во многом аналогична выполнявшейся ранее; функция sys_swapon только получает большую часть необходимых для нее значений непосредственно из заголовка устройства свопинга и не должна их вычислять.
Теперь становится очевидным, что автор в одном из предыдущих абзацев допустил неточность; в действительности, свопинг версии 2 все же немного ослабляет ограничения по размерам. В этой версии 80 страниц в конце файла не являются недоступными из-за сигнатуры заголовка свопинга, поэтому каждое отдельное устройство может иметь еще 320 Кб области свопинга. Однако предел все равно составляет около 128 Мб.
38491: Функция sys_swapon закончила чтение заголовков. Она устанавливает первый элемент отображения устройства свопинга в значение SWAP_MAP_BAD (строка 17552), чтобы помочь ядру предотвратить попытку выполнить свопинг в страницу заголовка.
38492: Распределяет и обнуляет отображение блокировки.
38499: Обновляет общее число доступных страниц свопинга и выводит сообщение об этом. (Она вычитает 10 из величины сдвига в строке 38502, чтобы вывод был в килобайтах, где 210 составляет 1 Кб.)
38505: Вставка нового элемента в логический список устройств свопинга, как всегда, в порядке сортировки по приоритетам. Этот код функционально идентичен соответствующему коду в функции sys_swapoff и поэтому нет разумных оснований вести их отдельно. Оба эти фрагмента кода может заменить простая встроенная функция.
38519: Очистка и выход.
netlib.narod.ru | < Назад | Оглавление | Далее > |