Главная страница  Межпроцессное взаимодействие (состязание) 

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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 [ 168 ] 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

ляет его файловой системе, блокируясь в ожидании ответа. Получив сообщение, файловая система выбирает из таблицы адрес функции-обработчика, пользуясь типом сообщения как индексом. В данном случае будет выбрана процедура, ответственная за чтение.

Процедура извлекает из сообщения дескриптор файла, определяет по нему соответствующую запись в filp, а затем i-узел файла, который будет считываться (см. рис. 5.29). Затем запрос разбивается на такие части, чтобы каждая из них уместилась в один блок. Например, если текущее значение файлового указателя равно 600 и запрощен 1 Кбайт данных, запрос будет разбит на две части, от 600 до 1023 и от 1024 до 1623 (если размер блока равен 1 Кбайт).

Затем проверяется наличие каждого из этих блоков в кэше. Если блок в кэше отсутствует, файловая система выбирает последний из использовавшихся незанятых буферов и передает задаче диска сообщение перезаписать его, если в нем есть мусор. Затем задаче диска передается просьба считать блок.

После того как блок оказался в кэше, файловая система посылает задаче системы сообщение, чтобы она поместила данные в соответствующее место в пользовательском буфере (то есть байты от 600 до 1023 скопировать в начало буфера, а байты от 1024 до 1623 - по смещению 424 от начала). Выполнив копирование, задача системы отправляет пользователю сообщение, указывая в нем, сколько байтов было обработано.

Когда ответ достигает пользователя, библиотечная подпрограмма read извлекает из него код возврата и передает его значение в вызвавший процесс.

Тут есть один дополнительный шаг, который в действительности не является частью самого системного вызова read. Файловая система, выполнив чтение и отправив ответ, инициирует чтение следующего блока, если считывание производится с блочного устройства и удовлетворены некоторые условия. Так как чаще всего производится последовательное чтение, разумно ожидать, что при следующем чтении будет запрошен следующий блок файла, который, таким образом, заранее окажется в кэше.

5.7. Реализация файловой системы MINIX

Код файловой системы MINIX относительно велик (более 100 страниц кода на С), но довольно прямолинеен. В нем запрос на выполнение системного вызова принимается, выполняется и отправляется ответ. В последующих разделах мы пройдемся по этому коду файл за файлом, указывая на основные моменты. Сам код также содержит немало комментариев, чтобы облегчить задачу читателя.

Рассматривая код остальных составляющих MINIX, мы обычно сначала изучали главный цикл процесса, а затем процедуры, обслуживающие различные типы сообщений. Здесь же мы возьмем за основу другой подход. Сначала мы изучим основные подсистемы (работу с кэшем, г-узлами и т. д). Затем рассмотрим главный цикл и системные вызовы, работающие с файлами. Потом настанет пора системных вызовов для управления каталогами, и, наконец, мы обсудим оставшиеся системные вызовы.



5.7.1. Заголовочные файлы

и глобальные структуры данных

Как и в ядре и менеджере памяти, в файловой системе применяется большое количество структур и таблиц, определяемых заголовочными файлами. Некоторые из этих структур помещены в общесистемные заголовочные файлы, лежащие в каталоге include/ и его подкаталогах. Например, файл include/sys/stat.h описывает формат представления информации г-узла для других программ, а структура данных каталога определяется файлом include/sys/dir.h. Оба этих файла предписаны стандартом POSIX. Управляют файловой системой множество глобальных определений, расположенных в файле include/minix/config.h, например, макрос ROBUST определяет, будут ли важные структуры данных записываться на диск немедленно, а NR BUFS и NR BUFS HASH отвечают за размер кэша блоков.

Заголовочные файлы файловой системы

Собственные заголовочные файлы файловой системы расположены в каталоге src/fs/. Имена многих из них уже знакомы вам из изучения других частей системы MINIX. Главный заголовочный файл, fs.h, очень сходен с src/kernel/kernel.h и src/mm/mm.h. Он включает остальные заголовочные файлы, необходимые всем другим файлам кода на С из файловой системы. Как и везде, в главный заголовочный файл включаются локальные заголовочные файлы const.h, type.h, proto.h и glo.h. Их мы и рассмотрим далее.

В файле const.h определяются некоторые константы, такие как размеры таблиц или флаги, используемые далее по всей файловой системе. У MINIX уже есть история. В предыдущих версиях применялась другая файловая система, и для тех пользователей, которые хотят обращаться к файлам, записанным предыдущей версией, предоставлена поддержка обеих версий, как VI, так и текущей, V2. Суперблок файловой системы содержит сигнатуру, при помощи которой операционная система может определить тип файловой системы. Константы SPER MAGIC и SUPER V2 определяют эти сигнатуры. О поддержке предыдущих версий не только приходится иногда читать в теоретических статьях, об этом всегда приходится задумываться разработчику новой версии программного обеспечения. Ему необходимо решить, сколько прикладывать усилий для упрощения жизни пользователей старой реализации.

В файле type.h описаны как структуры предыдущей версии VI, так и новой, V2, в том виде, в котором они записываются на диск. Размер нового г-узла вдвое больше, чем в старой системе, которая разрабатывалась как компактная система для машин без жесткого диска и дискетами по 360 Кбайт. В новой версии выделено место для всех трех полей времени, которые есть в UNIX-системах. В г-узле версии VI было всего одно поле времени, а вызовы stat и fstat, возвращающие структуру stat, содержащую все три поля, имитировали их наличие. При поддержке двух версий файловых систем есть небольшое затруднение, касающееся поля d2 gid структуры d2 inode. Старое программное обеспечение MINIX рассчитывает на то, что тип gid t восьмибитный, поэтому поле d2 gid необходимо явно объявлять как ul6 t.



В файле proto.h в форме, приемлемой как для стандартного ANSI С компилятора, так и для старых компиляторов а ля Керниган и Ричи, описаны прототипы функций. Это большой, но не очень интересный файл. Тем не менее тут нужно указать на один момент: так как файловая система обслуживает такое большое количество системных вызовов, код различных процедур do xxx рассеян по нескольким файлам. Описания в proto.h организованы в порядке файлов, поэтому им удобно пользоваться, если вы хотите узнать, в каком из файлов находится интересуюшая вас функция.

Наконец, в glo.h описываются глобальные переменные. Здесь же находятся буферы входящих и исходящих сообщений. При описании переменных применяется уже знакомый вам трюк с макросом EXTERN, поэтому они доступны из всех частей файловой системы. Как и в других компонентах MINIX, место в памяти для этих переменных выделяется при компиляции файла table.c.

Принадлежащая файловой системе часть таблицы процессов содержится в файле fsproc.h. В нем при помощи макроса EXTERN объявляется массив fsproc. В последнем хранятся маска режима доступа, указатели на г-узлы текущих рабочего и корневого каталогов, массив файловых дескрипторов, UID, GID и номер терминала для каждого процесса. Здесь же можно найти идентификатор процесса и группы процессов, которые дублируют поля таблицы процессов, принадлежащие ядру и менеджеру памяти.

Несколько полей отведены под хранение аргументов остановленных на полпути системных вызовов, таких как чтение из пустого канала. Для полей fp suspended и fp received в действительности требуется только один бит, но для символа компиляторы практически всегда генерируют лучший код. Кроме того, есть поле для битов FD CLOEXEC, требуемых стандартом POSIX. Их назначение в том, чтобы указать, что файл должен быть закрыт, когда делается системный вызов exec.

Теперь мы приступим к файлам, в которых описываются остальные таблицы, используемые файловой системой. Прежде всего, это файл buf.h, где задается кэш блоков. Все структуры в нем описаны при помощи EXTERN. Все буферы хранятся в массиве bufs, и каждый из них содержит область данных Ь, полный указателей заголовок и счетчики. Область данных объявлена как объединение пяти типов, поскольку иногда к блоку удобнее обращаться как к массиву символов, иногда как к каталогу и т. д.

Так, чтобы обратиться к области данных буфера 3 как к массиву символов,

нужно использовать запись buf[3].b.b data, так как buf[3].b ссылается на всю

область данных, из которой выделяется поле b data. Хотя такой синтаксис и

правилен, он неуклюж, поэтому далее создается макрос b data, позволяющий использовать запись bLif[3].b.b data. Обратите внимание: поле записывается как b data, с двумя символами подчеркивания, а макрос b data - с одним. Далее задаются аналогичные макросы для других способов обращения к данным блока.

Далее, сразу после этих макросов задается хеш-таблица буфера, buf hash. Каждый из ее элементов ссылается на список буферов, которые сначала пусты. Макросы в конце файла buf.h определяют различные типы блоков. Когда использованный блок возвращается обратно в кэш, с ним передается одно из этих значений, по которому менеджер кэша решает, поместить ли блок в начало или



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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 [ 168 ] 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2018 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.