Linux Kernel (Ядро линукса) (часть 3)


Сейчас МЫ ПОЯСНИМ работу функции

generic_file_aio_write_nolock. Ради
простоты, мы ограничимся самым общим случаем: операция в обычном режиме была запущена системным вызовом write для кэшируемого файла. Далее в этой главе мы опишем, как функция ведет себя в других случаях. Как всегда, мы не будем обсуждать обработку ошибок и аномальных ситуаций.
Функция выполняет следующие действия:
1. Вызывает функцию access oko, чтобы проверить корректность буфера режима пользователя, описанного дескриптором iovec (начальный адрес и длина были получены от служебной процедуры sys_write, поэтому их надо проверить перед использованием; см. главу 10). Если параметры недопустимы, функция возвращает код ошибки -еfault.
2. Определяет адрес inode индексного дескриптора, соответствующего файлу, В который производится запись (file->f_mapping->host). ВСПОМНИМ, что если это файл блочного устройства, то индексный дескриптор принадлежит специальной файловой системе
3. Записывает в поле current->backing_dev_info адрес дескриптора backing_dev_info ЭТОГО файла (file->f_mapping->backing_dev_info). Фактически, это присваивание позволит текущему процессу записывать на диск "грязные” страницы, которыми владеет fiie->f mapping, даже если соответствующая очередь запросов переполнена (см. главу 17).
4. Если флаг o append в поле fiie->fiags установлен, а файл обычный (не файл блочного устройства), то функция устанавливает указатель ppos на конец файла, чтобы новые данные добавлялись к нему.
5. Выполняет несколько проверок размера файла. Например, операция записи не должна увеличивать обычный файл настолько, что он превысит лимит для данного пользователя, хранящийся в элементе current->signai-> riim[RLiMiT_FsizE] (см. главу 3), и лимит для файловой системы, хранящийся в поле inode->i_sb->s_maxbytes. Кроме того, если файл не является
"большим файлом” (флаг o largefile в поле fiie->f_fiags сброшен), его размер не может превышать 2 Гбайт. Если любое из этих ограничений нарушено, функция уменьшает количество байтов, подлежащих записи.
6. Если флаг suid файла установлен, функция сбрасывает его. Она также сбрасывает флаг sgid, если файл исполняемый Мы ведь не хотим, чтобы пользователи могли модифицировать файлы setuid?
7. Сохраняет текущее время суток в поле inode->mtime (это время последней операции записи в файл) и в поле inode->ctime (время последнего изменения индексного дескриптора) и помечает индексный дескриптор как "грязный”.
8. Запускает цикл для обновления всех страниц файла, вовлеченных в операцию записи. На каждом шаге цикла функция выполняет следующие действия:
• вызывает функцию find iock page о для поиска страницы в кэше Если вызванная функция находит страницу, она увеличивает ее счетчик обращений и устанавливает флаг PG iocked;
• если страницы нет в кэше, функция выделяет новый страничный кадр и вызывает функцию add to page cache о, чтобы занести страницу в кэш. Как было сказано в главе 75, эта функция также увеличивает счетчик обращений и устанавливает флаг PG iocked. Кроме того, функция заносит новую страницу в список неактивных страниц в зоне памяти
• вызывает метод prepare write объекта address space индексного дескриптора (fiie->f_mapping). Соответствующая функция отвечает за выделение и инициализацию голов буферов для страницы. В последующих разделах мы обсудим, как эта функция работает с обычными файлами и файлами блочных устройств;
• если буфер находится в верхней памяти, функция задает отображение буфера режима пользователя в адресное пространство ядра Затем она вызывает функцию copy f rom user, чтобы скопировать символы из буфера режима пользователя в страницу, а затем отменяет отображение в адресное пространство ядра;
• вызывает метод commit write объекта address space индексного деск- риптора (fiie->f_mapping). Функция, реализующая метод, помечает соответствующие буферы как грязные”, чтобы они впоследствии были записаны на диск. В следующих двух разделах мы обсудим, как эта функция работает с обычными файлами и файлами блочных устройств;
• вызывает функцию unlock_page, чтобы сбросить флаг PG locked и возобновить выполнение процессов, ждущих эту страницу, если таковые имеются;
• вызывает функцию mark_page_accessed, Чтобы обновить информацию о состоянии страницы для алгоритма утилизации памяти
• уменьшает счетчик обращений к странице, чтобы компенсировать его увеличение в начале цикла;
• на этом шаге цикла загрязнена” еще одна страница, и функция проверяет, превысила ли доля грязных” страниц в кэше некоторый фиксированный порог (обычно составляющий 40% от количества страниц в системе). Если это так, функция вызывает функцию writeback_ inodes о, чтобы принудительно записать на диск несколько десятков страниц
• вызывает функцию cond_resched, ЧТОбы проверить флаг TIF_NEED_ res сне d текущего процесса и, если флаг установлен, вызвать функцию
schedule.
9. Итак, все страницы файла, вовлеченные в операцию записи, обработаны.
Функция обновляет значение ppos, чтобы установить указатель сразу после последнего записанного символа.
10. Устанавливает поле current->backing_dev_info В NULL
11. Завершает работу, возвращая количество фактически записанных байтов.
Методы preparewrite и commit_write для обычных файлов
МетОДЫ prepare write И commit_write объекта address space Специализируют общую операцию записи, реализованную функцией generic_file_write для обычных файлов и файлов блочных устройств. Оба они вызываются один раз для каждой страницы файла, которая участвует в операции записи.
Каждая дисковая файловая система определяет свой собственный метод prepare write. Как и в случае с операцией чтения, метод является интерфейсом к общей функции. Например, в файловой системе Ext2 метод prepare write обычно реализован следующей функцией:
int ext2_prepare_write(struct file file, struct page page,
unsigned from, unsigned to){
return block_prepare_write(page, from, to, ext2_get_block);}
Функция ext2_get_biock уже упоминалась ранее в разд. "Чтение файла". Она преобразует номер блока в файле в логический номер блока, представляющий позицию данных в физическом блочном устройстве.

Функция biock_prepare_write подготавливает буферы и головы буферов страницы файла, для чего выполняет следующие шаги:
1. Проверяет, является ли страница страницей буферов (установлен ли флаг PG Private). ЕСЛИ флаг сброшен, функция вызывает функцию create_ empty buffers , чтобы выделить головы для всех буферов, включенных в страницу
2. Для каждой головы буфера, входящего в страницу и затронутого операцией записи, функция выполняет следующие действия:
• сбрасывает флаг BH New, если он установлен;
• если флаг BH Mapped не установлен, функция выполняет следующие дополнительные действия:
п вызывает специфичную для файловой системы функцию, адрес которой— get biock был получен в качестве параметра. Вызванная функция выполняет поиск среди дисковых структур файловой системы и находит логический номер блока для буфера (это номер относительно начала раздела диска, но не начала обычного файла). Функция, специфичная для файловой системы, сохраняет этот номер в поле b biocknr соответствующей головы буфера и устанавливает ее флаг BH Mapped. Функция get biock может выделить новый физический блок для файла (например, если затребованный блок попадает в дыру” в обычном файлеВ этом случае она устанавливает флаг BH New;
п проверяет значение флага BH New. Если он установлен, вызывает функцию uranap underlying metadata , чтобы проверить, содержит ли какая-нибудь страница буферов блочного устройства в кэше страниц буфер, ссылающийся на тот же блок на диске. Эта функция
вызывает функцию find get biock для поиска старого блока в
кэше страниц Если такой блок обнаруживается, функция сбрасывает его флаг BH Dirty и ждет окончания операции ввода/вывода для этого буфера. Кроме того, если операция записи не переписывает целый буфер в странице, функция заполняет нулями не переписанный участок буфера. Затем она переходит к рассмотрению следующего буфера на странице;
• если операция записи не переписывает целый буфер, а флаги BH Deiay и BH Uptodate не установлены (то есть блок был выделен в структурах
файловой системы, а буфер в оперативной памяти не содержит корректный образ данных), функция вызывает функцию ii_rw_biock() для блока, чтобы прочитать его содержимое с диска
3. Блокирует текущий процесс, пока все операции чтения, запущенные на шаге 2, не будут завершены.
4. Возвращает 0.
Когда метод prepare_write возвращает управление, функция generic_file_ write обновляет страницу, записывая в нее данные, хранящиеся в адресном пространстве режима пользователя. Затем она вызывает метод commit write объекта address space. ЭТОТ метод реализуется функцией generic_commit_ write почти во всех дисковых не журналируемых файловых системах.

Функция generic commit write ВЫПОЛНЯет следующие действия:
1. Вызывает функцию biock_commit_write, которая выполняет следующие действия:
• рассматривает все буферы на странице, затронутые операцией записи. Для каждого буфера устанавливает флаги BH Uptodate И BH_Dirty его головы;
• помечает соответствующий индексный дескриптор как грязный”. Как было показано в главе 75, для этого может потребоваться занесение индексного дескриптора в список грязных” индексных дескрипторов суперблока;
• если ни один из буферов на странице не является устаревшим, устанавливает флаг PG uptodate для страницы;
• устанавливает флаг PG dirty и помечает страницу как грязную в базисном дереве (см. разд. ”Базисное дерево” главы 15).
2. Проверяет, увеличился ли файл в результате операции записи. В этом случае функция обновляет поле i size индексного дескриптора этого файла.
3. Возвращает 0.

Предыдущая страница | 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 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...