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


Чтение из файла

Функция generic_file_read Служит ДЛЯ реализации метода read ДЛЯ обыч- ных файлов и файлов блочных устройств почти во всех дисковых файловых системах. Эта функция принимает следующие параметры:
- fiip — адрес файлового объекта;
- buf — линейный адрес области памяти режима пользователя, в которой должны сохраняться символы, прочитанные из файла;
- count — количество символов, которые следует прочитать;
- ppos — указатель на переменную, содержащую смещение, с которого должно начаться чтение (как правило, это поле f pos файлового объекта
fiip).

На первом шаге функция инициализирует два дескриптора. Первый хранится в локальной переменной locai iov типа iovec. Она содержит адрес (buf) и длину (count) буфера режима пользователя, который будет принимать данные, прочитанные из файла. Второй дескриптор хранится в локальной переменной kiocb типа kiocb. Она используется для отслеживания завершения текущей операции синхронного или асинхронного ввода/вывода. Основные поля дескриптора kiocb
Функция generic_file_read() инициализирует дескриптор kiocb, ВЫПОЛНЯЯ макрос init sync kiocb, который устанавливает поля объекта для синхронной операции. В частности, макрос устанавливает поле ki key в значение
к I ocb_s yn с_ке y, поле ki_fiip — в значение fiip, а поле ki_obj — в значение current.
Затем функция generic_file_read вызывает функцию generic file_aio_
read , передавая ей адреса только что заполненных дескрипторов iovec и kiocb. Последняя функция возвращает значение, как правило, показывающее количество байтов, фактически прочитанных из файла. Функция generic_ f iie read заканчивает работу, возвращая это значение.
Функция generic_file_aio_read представляет собой процедуру общего назначения, используемую всеми файловыми системами для реализации как синхронных, так и асинхронных операций чтения. Функция принимает четыре параметра: адрес iocb дескриптора kiocb, адрес iov массива дескрипторов iovec, длину этого массива и адрес переменной ppos, в которой хранится текущий указатель файла. Когда ВЫЗОВ делает функция generic file readO, массив дескрипторов iovec состоит из единственного элемента, описывающего буфер режима пользователя, который будет принимать данные.
Вариант системного вызова readO, называемый readv, позволяет приложению определить несколько буферов режима пользователя, по которым ядро
"разбрасывает" данные, прочитанные из файла, и функция generic_
file_aio_read предусматривает такой случай. В последующем изложении мы будем предполагать, что данные, прочитанные из файла, копируются в единственный буфер режима пользователя. Догадаться о дополнительных действиях, необходимых при использовании нескольких буферов, совсем нетрудно.

Далее мы опишем действия, предпринимаемые функцией generic_fiie_
aio_read(). Ради простоты, мы ограничимся самым общим случаем: синхронная операция, выполняемая системным вызовом readO для файла с кэшем страниц. Далее в этой главе мы разъясним поведение этой функции в других случаях. Как обычно, мы не будем обсуждать обработку ошибок и аномальных ситуаций.
Итак, функция выполняет следующие действия:
1. Вызывает access oko, чтобы проверить корректность буфера режима пользователя, описываемого дескриптором iovec. Поскольку адрес начала и длина были получены от служебной процедуры sys reado, их нужно проверять перед использованием Если параметры не корректны, функция возвращает код ошибки -еfault.
2. Устанавливает дескриптор операции чтения. Это структура данных типа read descriptor t, в которой хранится текущее состояние операции чтения файла, относящейся к единственному буферу режима пользователя.
3. Вызывает функцию do_generic_fiie_read, передавая ей указатель на файловый объект fiip, указатель на смещение ppos, адрес только что выделенного дескриптора операции чтения и адрес функции fiie_read_ actor .
4. Возвращает количество байтов, скопированных в буфер режима пользователя, Т. е. значение ПОЛЯ written структуры read descriptor t.
Функция do_generic_fiie_read читает запрошенные страницы с диска и копирует их в буфер режима пользователя. В частности, она выполняет следующие действия:
1. Получает объект address space, соответствующий читаемому файлу. Его адрес находится В filp->f_mapping.
2. Получает владельца объекта address space, т. е. индексный дескриптор, который будет владеть страницами, подлежащими заполнению данными из файла. Его адрес хранится в поле host объекта address space. Если читаемый файл является файлом блочного устройства, владельцем является индексный дескриптор специальной файловой системы bdev, а не индексный дескриптор, на который указывает filp->f_dentry->d_inode
3. Считает, что файл разбит на страницы (по 4096 байтов). По файловому указателю ppos функция вычисляет логический номер страницы, содержащей первый запрошенный байт— индекс страницы в адресном пространстве и сохраняет его в локальной переменной index. Кроме того, функция сохраняет в локальной переменной offset смещение первого запрошенного байта внутри страницы.
4. Запускает цикл для чтения всех страниц, содержащих запрошенные байты. Количество байтов, которые надо прочитать, хранится в поле count дескриптора read_descriptor_t.
5. За один проход цикла функция пересылает страницу данных, при этом, если index4096+offset превышает размер файла, хранящийся в поле i size индексного дескриптора, функция выходит из цикла и переходит к шагу 23.
6. Вызывает cond reschedO, чтобы проверить флаг tif need resched теку- щего процесса и, если флаг установлен, вызвать функцию schedule .
7. Если дополнительные страницы должны быть прочитаны заранее, функция вызывает ДЛЯ ЭТОГО функцию page_cache_readahead . Мы ОТКЛадыва- ем обсуждение опережающего чтения до разд. "Опережающее чтение файлов ".
8. Вызывает функцию find get page , передавая ей в качестве параметров указатель на объект address_space И значение index. Вызванная функция просматривает кэш страниц в поисках дескриптора страницы, содержащей запрошенные данные.
9. Если функция find get page () возвратила null, значит, запрошенной страницы нет в кэше. В таком случае функция выполняет следующие действия:
• вызывает handie ra miss о для подстройки параметров системы опережающего чтения;
• выделяет новую страницу;
• вставляет дескриптор новой страницы в кэш, для чего вызывает add to page cache . Вспомним, что эта функция устанавливает у новой страницы флаг PG iocked;
• вставляет дескриптор новой страницы в список LRU, вызвав
lru_cache_add
• переходит к шагу 14, чтобы начать чтение данных из файла.
10. Если функция достигла этой точки, значит, страница находится в кэше. Функция проверяет флаг PG uptodate. Если он установлен, данные, хра
нящиеся в странице, свежие, и нет необходимости читать их с диска. Функция переходит к шагу 17.
11. Данные на странице не имеют смысла и должны быть прочитаны с диска. Функция получает исключительный доступ к странице, вызывая функцию lock_page. функция lock page о приостанавливает текущий процесс, если флаг PG iocked установлен, до тех пор, пока флаг не будет сброшен.
12. Итак, страница заблокирована текущим процессом. Однако не исключено, что какой-то другой процесс удалил страницу из кэша непосредственно перед предыдущим шагом. Поэтому функция проверяет, содержит ли поле mapping дескриптора страницы значение null. В этом случае она разблокирует страницу, вызвав функцию uniock page , а затем уменьшит счетчик обращений к странице (увеличенный функцией f ind get page ) и вернется к шагу 5, начав все заново с той же страницей.
13. Если функция дошла до этого шага, значит, страница заблокирована и все еще находится в кэше. Функция снова проверяет флаг PG uptodate, потому что другой управляющий тракт ядра мог завершить необходимую операцию чтения в момент между шагами 10 и 11. Если флаг установлен, функция вызывает функцию uniock page и переходит к шагу 17, пропуская операцию чтения.
14. В этот момент можно начать фактическую операцию ввода/вывода. Функция вызывает метод readpage объекта address space данного файла. Соответствующая функция отвечает за активизацию пересылки данных с диска в страницу. Действия этой функции в отношении обычных файлов и файлов блочных устройств обсуждаются чуть позже.
15. Если флаг PG uptodate все еще сброшен, функция ждет, пока страница не будет фактически прочитана, вызывая функции iock_page. Страница, заблокированная на шаге 11, будет разблокирована сразу после окончания операции чтения. Поэтому текущий процесс приостанавливается, пока не завершится ввод/вывод.
16. Если значение index превышает размер файла в страницах (это число получается в результате деления значения поля i size индексного дескриптора на 4096), функция уменьшает счетчик обращений страницы и выходит из цикла, переходя на шаг 23. Этот случай имеет место, когда файл, читаемый этим процессом, был усечен параллельным процессом.
17. Сохраняет в локальной переменной nr количество байтов страницы, подлежащих копированию в буфер режима пользователя. Это значение равно размеру страницы (4096 байтов), за исключением тех случаев, когда значение offset не равно нулю (что возможно только для первой или по
следней страницы запрошенных данных), либо файл содержит меньше байтов, чем было запрошено.
18. Вызывает функцию mark_page_accessed, чтобы установить флаг PG referenced или PG active, отметив тот факт, что страница использует- ся процессом, и ее нельзя выгружать. Если одна и та же страница (или ее часть) читается несколько раз в результате последовательных ВЫЗОВОВ функции do_generic_file_read, ЭТОТ шаг выполняется только при первом чтении.
19. В этот момент следует копировать данные из страницы в буфер режима пользователя. С этой целью функция do_generic_fiie_read вызывает функцию fiie read actorо, адрес которой был получен в качестве параметра. Со своей стороны, функция fiie read actor о выполняет следующие действия:
• вызывает функцию kmap , которая устанавливает постоянное отображение страницы в адресное пространство ядра, если эта страница находится в верхней памяти
• вызывает функцию copy to userо, которая копирует данные из
страницы в адресное пространство режима пользователя. Обратите внимание, что эта операция может блокировать процесс из- за обработки ошибок типа "обращения к странице” в адресном пространстве режима пользователя;
• вызывает функцию kunmapo для отмены постоянного отображения страницы в адресное пространство ядра;
• обновляет ПОЛЯ count, written И buf Дескриптора read descriptor t.
20. Обновляет локальные переменные index и offset в соответствии с количеством байтов, фактически переданных в буфер режима пользователя. Как правило, если последний байт страницы был скопирован в буфер режима пользователя, переменная index увеличивается на единицу, а переменная offset приравнивается к нулю. В противном случае index не увеличивается, а в offset записывается количество байтов, успешно скопированных из страницы в буфер режима пользователя.
21. Уменьшает счетчик обращений дескриптора страницы.
22. Если поле count дескриптора read descriptor t не равно нулю, значит, нужно продолжить чтение данных из файла. Функция переходит к шагу 5, чтобы прочитать в цикле следующую страницу данных из файла.
23. Все запрошенные (или доступные) байты прочитаны. Функция обновляет структуру данных опережающего чтения fiip->f_ra, чтобы отметить тот факт, что данные последовательно читаются из файла (см. разд. "Опережающее чтение файлов" далее в этой главе).
24. Присваивает переменной ppos значение index4096+offset, отмечая следующую позицию для последовательного обращения на случай будущих системных ВЫЗОВОВ read ИЛИ write .
25. Вызывает функцию update atime , чтобы сохранить текущее время в поле i atime индексного дескриптора файла и пометить индексный дескриптор как грязный”. После этого функция завершает работу.

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