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

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

в конец списка LRU, а также записать его на диск сразу или нет. Бит WRITE IMMED сигнализирует о том, что измененный блок должен быть перезаписан на диск немедленно. В обычных условиях этим битом помечается только суперблок. А что насчет других структур, помеченных MAYBE WRITE IMMED? Если в файле include/minix/config.h макрос ROBUST инициирован, это определение будет равно WRITEJMMED, а в противном случае - нулю. В стандартной конфигурации MINIX ROBUST равен О, поэтому блоки с такой пометкой будут записываться тогда же, когда и обычные блоки с данными.

Наконец, в последней строке на основе значения NR BUF HASH из include/ minix/config.h задается параметр HASH MASK. Это значение побитово объединяется с номером блока по принципу логического И (AND), с целью выяснить, в каком из списков массива buf hash следует искать буфер блока.

В следующем файле, dev.h, определяется таблица dmap. Сама эта таблица описана в table.c с начальными значениями, поэтому ее описание не может быть использовано в других файлах. Чтобы иметь возможность обращаться к ней из других мест, и создан файл dev.h. В нем таблица dmap описана с ключевым словом extern вместо EXTERN. Назначение данной таблицы в том, чтобы отображать старший номер устройства на номер соответствующей задачи.

Файл file.h содержит промежуточную таблицу filp (описанную как EXTERN), применяемую для хранения текущего положения в файле и указателя на его г-узел (см. рис. 5.29). Эта же таблица дает ответ на вопрос, был ли файл открыт на чтение и/или на запись, а также сколько файловых дескрипторов в текущий момент ссылаются на ее элемент.

Таблица file lock (объявленная как EXTERN) из файла lock.h хранит сведения о захвате файлов. Размер этого массива определяется параметром NR LOCKS, который определяется в файле const.h и по умолчанию равен 8. Если когда-либо потребуется реализовать на основе MINIX многопользовательскую базу данных, это значение необходимо будет увеличить.

В inode.h объявляется (опять же, как EXTERN) массив г-узлов inode. В нем хранятся все используемые в текущий момент г-узлы. Как уже говорилось ранее, г-узел файла загружается в память при его открытии и хранится там до тех пор, пока файл не будет закрыт. В структуре inode есть информация, присутствующая в памяти, но отсутствующая на диске. Заметьте, что здесь описывается только одна версия и нет никаких зависящих от версии файловой системы особенностей. Различия между файловыми системами VI и V2 учитываются при считывании г-узла с диска, и остальной системе не приходится задумываться о формате диска, по крайней мере до тех пор, пока не понадобится записать измененную информацию обратно.

К этому моменту вам должно быть понятно назначение большинства полей. Небольшого пояснения заслуживает только i seek. Ранее упоминалось, что при последовательном чтении файловая система, в качестве оптимизации, пытается заранее помещать следующий блок в кэш, до того как он запрошен. При произвольном доступе к файлу опережающее чтение не нужно. Поэтому, когда делается вызов Iseek, чтобы отключить опережающее чтение, устанавливается поле i seek.



Файл param.h аналогичен файлу менеджера памяти с тем же именем. В нем определяются имена для полей сообщений с параметрами, чтобы, например, можно было писать buffer вместо m.ml pl, имени одного из полей буфера сообщения т.

В файле super.h находится определение таблицы суперблоков. Она отвечает за загрузку суперблока корневой системы и сюда же записываются суперблоки монтируемых файловых систем. Как и другие таблицы, super block объявлена с ключевым словом EXTERN.

Выделение памяти для данных файловой системы

Последний файл, который мы обсудим, table.c, не является заголовочным. Но, как и за разговором о менеджере памяти, имеет смыл рассмотреть его сразу после заголовочных файлов, поскольку все они присоединяются при компиляции table.c. Большинство упомянутых нами структур данных объявлены при помощи EXTERN, это касается как глобальных переменных, так и локальной части таблицы процессов. Так же как и в других частях MINIX, память для таких переменных в действительности выделяется при компиляции table.c. Кроме того, в этом файле содержатся два важных неинициализированных массива. Массив call vector хранит указатели на функции, он нужен в главном цикле, чтобы определить, какая функция выполняет какой системный вызов. Похожую таблицу мы видели и внутри менеджера памяти.

Таблица dmap аналогов в менеджере памяти не имеет. Здесь есть строки для каждого из значений старшего номера устройства, начиная с нуля. Когда устройство закрывается или открывается или когда информация записывается на него или считывается с него, адрес процедуры, выполняющей соответствующую операцию, берется из этой таблицы. Все эти процедуры расположены в адресном пространстве файловой системы. Большинство из них ничего не делают, но некоторые передают вызов задаче, запрашивая ввод/вывод. Номер задачи тоже хранится в таблице dmap.

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

В таблице dmap есть строки для всех возможных значений старшего номера устройства, и все эти строки оформлены как макросы. У обязательных устройств аргумент макроса enable равен 1. Некоторые из записей не используются либо потому, что соответствующий драйвер еще не готов, либо потому, что драйвер был удален. У таких записей параметр enable равен 0. Тем устройствам, наличие которых управляется файлом конфигурации, соответствуют записи, где в качестве аргумента enable подставлен макрос, включающий данное устройство, например ENABLE.WINI.



5.7.2. Таблицы

с каждой важной таблицей, будь то таблица блоков, f-узлов, суперблоков и т. д., связан файл, содержащий процедуры для работы с ней. Эти процедуры широко используются в остальном коде и образуют основной интерфейс между таблицами и файловой системой. Поэтому наше изучение кода файловой системы имеет смысл начать с этих файлов.

Управление блоками

с кэшем блоков работают подпрофаммы из файла cache.c. Он содержит девять процедур, перечисленных в табл. 5.5. Первая из них, get block, реализует стандартный способ получить блок данных. Когда процедуре файловой системы необходимо прочитать блок пользовательских данных, каталог, суперблок или блок любого другого типа, она вызывает функцию get block, указывая ей номер блока и устройство.

Таблица 5.5. Процедуры управления блоками Процедура Действие

get block Извлекает блок для чтения или записи

put block Помещает обратно блок, ранее запрошенный с помощью get block

alloc zone Выделяет новую зону (чтобы увеличить файл)

free zone Освобождает зону (когда файл удаляется)

rw block Перемещает блок между диском и кэшем

invalidate Чистит все кэшированные блоки с одного из устройств

flushall Сбрасывает на диск все измененные блоки для некоторого устройства

n/v scattered Чтение разрозненных данных с устройства или их запись

rmjru Удаляет блок из LRU-списка

Когда вызывается функция get block, она прежде всего смотрит, есть ли запрошенный блок в кэше. Если да, возвращается указатель на него. Иначе запрошенный блок необходимо считать. Блоки в кэше объединены в списки, всего NR BUF HASH списков. Этот параметр, NR BUF HASH, можно настраивать, как и параметр NR BUFS, определяющий размер кэша блоков. Оба они устанавливаются в файле include/minix/config.h. В заключение скажем несколько слов об оптимизации размера кэша блоков и хеш-таблицы. Параметр HASH MASK равен NR BUF HASH-1. Если имеется 256 списков, маска равна 255, и все блоки, в номерах которых совпадают последние 8 бит, попадают в один список. Получится 256 списков для номеров 00000000, 00000001, 11111111.

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



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.
Копирование материалов разрешено исключительно при условии цититирования.