Главная страница Межпроцессное взаимодействие (состязание) get block, и обработчик кэша блоков находит нужный блок, считывая его при необходимости. О копировании данных в адресное пространство пользователя из найденного блока заботится функция sys copy на 270-й строке. Затем блок освобождается, чтобы позже он мог быть удален из кэша. (После того как get block находит нужный блок, тот исключается из списка LRU и пребывает вне его до тех пор, пока счетчик использования в заголовке буфера не обнулится. Вызов put block уменьшает значение этого счетчика и, если настало время, возвращает буфер в LRU-список). Код в 280-й строке файла определяет, заполнился ли блок при записи. Правда, сейчас это уже не принципиально, так как функция put block теперь игнорирует значение, передаваемое ей во втором аргументе, и всегда добавляет освободившиеся блоки в конец LRU-последовательности. Функция read map преобразует логическое смещение в файле в физический номер блока, пользуясь для этого информацией i-узла. Те блоки, которые достаточно близки к началу файла, попадут в одну из первых семи зон (то есть в одну из тех зон, что хранятся в самом i-узле). При этом, чтобы узнать, какая из зон необходима, требуется только несложная арифметика. Для блоков, расположенных дальше, может понадобиться считать один или два блока косвенной адресации. Функция rdjndir вызывается, когда необходимо считать косвенный блок. Это действие вынесено в самостоятельную процедуру потому, что данные на диске могут храниться в разных форматах, в зависимости от версии файловой системы и от оборудования, на котором файловая система была сформирована. Функция выполняет необходимые преобразования, чтобы все остальные подпрограммы видели данные только в одной форме. Функция read ahead преобразует логическое положение в физический адрес блока, вызывает get block, в результате чего блок оказывается в кэше, и немедленно возвращает его. В конце концов, сделать с ним она все равно ничего не может. Задача read ahead лишь в том, чтобы увеличить вероятность найти данные в кэше, если они скоро понадобятся. Обратите внимание, что read ahead вызывается только из главного цикла в main. Ее вызов не является частью выполнения read. Важно понять, что эта функция вызывается после того, как пользователю отправлен ответ, чтобы он мог продолжать свою работу, пока файловая система дожидается завершения упреждающего чтения. Сама функция read ahead написана так, чтобы запрашивать всего один блок. Реально трудится вызываемая ею подпрофамма rahead, последняя в файле read.c. В rahead заложена та жизненная концепция, что если немного больше - хорошо, то намного больше - еще лучше. Так как дискам и прочим накопителям часто требуется много времени, чтобы найти первый запрошенный блок, но зато они могут быстро считывать несколько смежных блоков, делается ставка на то, что получится считать много последовательных блоков ценой небольших дополнительных трудозатрат. Запрос на упреждающую выборку передается функции get block, подготавливающей кэш блоков к получению нескольких блоков за раз. Затем вызывается rw scattered, которой передается список блоков. Работу этой функции мы уже обсуждали. Вспомните, что rw scattered передает запрос драй- веру устройства, который в ответ имеет право обслужить столько запросов, сколько он способен выполнить эффективно. Все это звучит довольно витиевато, но зато позволяет на нужное много увеличить скорость приложений, считывающих с диска ожидаемое побольше количество данных. На рис. 5.32 показаны взаимосвязи между основными подпрограммами, участвующими в чтении файла. В том числе указано, кто кого вызывает. Точки входа Главная процедура для чтения и записи Специальные Каналы файлы ввода/вы Определение дискового ;readjTiap<h Передача Возврат данных от ФС блока rdjndir J) (et bloc* пользователю в кэш Доступ к косвенному блоку (если нужно)Qrw block (devjo Поиск в кэше (т Адрес в таблице тар ядру Рис. 5.32. Некоторые из процедур, участвующих в чтении файла Запись Код, обеспечивающий запись в файл, находится в write.c. Запись в файл в большинстве своем сходна с чтением, и do write просто вызывает read write с флагом WRITING. Основное отличие записи в том, что здесь может потребоваться выделение дополнительных блоков. Функция write map аналогична read map с той разницей, что, вместо поиска физического адреса блока по г-узлу и косвенным блокам, она добавляет новое (точнее, она добавляет номер новой зоны, а не блока). Код функции write map сложный и длинный, поскольку эта функция должна учитывать несколько различных ситуаций. Если новая зона вставляется в начало файла, она должна быть вставлена в его г-узел. Самый же худший случай, когда по мере роста файла простых косвенных блоков перестает хватать и приходится применять косвенные блоки второго уровня. После этого выделяется косвенный блок первого уровня, и его адрес заносится в блок второго. Как и в случае с чтением, для этого предусмотрена отдельная процедура, wrjndir. Если косвенный блок второго уровня выделить удалось и из-за этого диск переполнился, а на косвенный блок первого уровня места уже не хватает, то блок второго уровня нужно вернуть, чтобы избежать повреждения битовой карты. Опять же, если бы в случае неудачи можно было бы просто сообщить о фатальной ошибке ядра, код был бы намного компактнее. Но, с точки зрения пользователя, гораздо лучше, когда при переполнении диска write возвращает код ошибки вместо того, чтобы провоцировать крах, к тому же с порчей файловой системы. Функция wrjndir записывает новый зонный в косвенный блок, а чтобы преобразовать данные в нужный формат (порядок следования байтов), она вызывает одну из подпрограмм преобразования, conv2 или conv4. Пусть имя этой функции не вводит вас в заблуждение. Помните, что действительную запись данных на диск выполняют функции, обслуживающие кэш блоков. Далее в write.c следует функция clear zone. Она занимается очисткой блоков, оказавшихся в середине файла. Такое может случиться, если записать некоторое количество данных после конца файла. К счастью, это случается не очень часто. Функция new block вызывается из rw chunk, когда требуется новый блок. На рис. 5.33 показаны шесть последовательных стадий увеличения файла. В этом примере размер блока равен 1 Кбайт, а зоны - 2 Кбайт. Свободные зоны: 12 20 31 36.. 24 25 Номер бпока Рис. 5.33. Последовательное выделение блоков размером 1 Кбайт при размере зоны 2 Кбайт
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |