struct vfsmount *root; /* объект монтирования корневого каталога */
struct list_head list; /* список точек монтирования */
struct rw_semaphore sem; /* семафор для защиты пространства имен */
};
Поле list
представляет собой двухсвязный список смонтированных файловых систем, которые составляют пространство имен.
Каждый дескриптор процесса имеет связанные с ним рассмотренные структуры данных. Для большинства процессов их дескриптор процесса указывает на уникальную структуру files_struct
и структуру fs_struct
. Однако для процессов, созданных с флагами CLONE_FILES
и CLONE_FS
, эти структуры являются совместно используемыми[74]. Отсюда следует, что несколько дескрипторов процессов могут указывать на одну и ту же структуру files_struct
, или структуру fs_struct
. Поле count
каждой структуры содержит счетчик использования, что предотвращает уничтожение структуры данных, когда ее использует хотя бы один процесс.
Структура namespace
используется несколько по-другому. По умолчанию вес процессы совместно используют одно пространство имен (и соответственно одну иерархию файловых систем). Только когда для системного вызова clone()
указан флаг CLONE_NEWNS
, для процесса создается уникальная копия пространства имен. Поскольку для большинства процессов этот флаг не указывается, процессы обычно наследуют пространство имен родительского процесса. Следовательно, для большинства систем существует только одно пространство имен.
Файловые системы в операционной системе Linux
Операционная система Linux поддерживает большой набор файловых систем, от "родных" ext2 и ext3 до сетевых файловых систем, таких как NFS или Coda. Сейчас в официальном ядре ОС Linux поддерживается более 50 файловых систем. Уровень VFS обеспечивает все эти разнообразные файловые системы общей базой для их реализации и общим интерфейсом для работы со стандартными системными вызовами. Следовательно, уровень виртуальной файловой системы позволяет четким образом реализовать поддержку новых файловых систем в операционной системе Linux, a также дает возможность работать с этими файловыми системами с помощью стандартных системных вызовов Unix.
В этой главе было описано назначение подсистемы VFS и рассмотрены соответствующие структуры данных, включая такие важные объекты, как inode, dentry и superblock. В главе 12, "Виртуальная файловая система", будет рассказано о том, как данные физически поступают на файловые системы.
Глава 13
Уровень блочного ввода-вывода
Устройства блочного ввода-вывода (блочные устройства, устройства ввода-вывода блоками, block devices) — это аппаратные устройства, которые позволяют случайным образом (т.е. не обязательно последовательно) осуществлять доступ к фрагментам данных фиксированного размера, называемых блоками. Наиболее часто встречающееся устройство блочного ввода-вывода — это жесткий диск, но существуют и другие блочные устройства, например устройства работы с гибкими дисками, оптическими компакт-дисками (CD-ROM) и флеш-памятью. Следует обратить внимание, что файловые системы монтируются с таких устройств. Именно таким образом обычно и осуществляется доступ к устройствам блочного ввода-вывода.
Другой фундаментальный тип устройства — это устройство посимвольного ввода-вывода (символьное устройство, character device, char device). Это — устройство, к которому можно обращаться, только как к последовательному потоку данных, т.е. байт за байтом. Пример символьных устройств — это последовательный порт и клавиатура. Если же устройство позволяет обращаться к данным случайным образом (не последовательно), то это блочное устройство.
Существенное различие между этими типами устройств проявляется, в основном, в возможности случайного доступа к данным, т.е. в возможности производить поиск (seek) по устройству, перемещаясь из одной позиции в другую. Как пример, рассмотрим клавиатуру. Драйвер устройства клавиатуры на выходе выдает поток данных. Когда печатают слово "fox", то драйвер клавиатуры возвращает поток данных, в котором три символа идут строго в указанном порядке. Считывание символов в другом порядке или считывание какого-нибудь другого символа, кроме следующего символа в потоке, имеет немного смысла. Поэтому драйвер клавиатуры — это устройство посимвольного ввода-вывода, он позволяет на выходе получить поток символов, которые пользователь вводит на клавиатуре. Операция чтения данных с устройства возвращает сначала символ "f", затем символ "о" и в конце символ "x". Когда нажатий клавиш нет, то поток — пустой. Жесткий диск же работает по-другому. Драйвер жесткого диска может потребовать чтения содержимого определенного блока, а затем прочитать содержимое другого блока, и эти блоки не обязательно должны следовать друг за другом. Поэтому доступ к данным жесткого диска может выполняться случайным образом, а не как к потоку данных, и поэтому жесткий диск — блочное устройство.
Управление блочными устройствами в ядре требует большего внимания, подготовки и работы, чем управление устройствами посимвольного ввода-вывода. Все это потому, что символьные устройства имеют всего одну позицию — текущую, в то время как блочные устройства должны иметь возможность перемещаться туда и обратно между любыми позициями на физическом носителе информации. Оказывается, что нет необходимости создавать в ядре целую подсистему для обслуживания символьных устройств, а для блочных устройств это необходимо. Такая подсистема необходима отчасти из-за сложности блочных устройств. Однако основная причина такой мощной поддержки в том, что блочные устройства достаточно чувствительны к производительности. Выжать максимум производительности из жесткого диска значительно важнее, чем получить некоторый прирост скорости при работе с клавиатурой. Более того, как будет видно дальше, сложность блочных устройств обеспечивает большой простор для таких оптимизаций. Предмет данной главы — как ядро управляет работой блочных устройств и запросами к этим устройствам. Рассматриваемая часть ядра называется уровнем, блочного ввода-вывода (block I/O layer). Интересно, что усовершенствование подсистемы блочного ввода-вывода было одной из целей разрабатываемой серии ядра 2.5. В этой главе рассматриваются все новые особенности уровня блочного ввода-вывода, которые появились в ядрах серии 2.6.
Анатомия блочного устройства
Наименьший адресуемый элемент блочного устройства называется сектором. Размеры секторов — это числа, которые являются целыми степенями двойки, однако наиболее часто встречающийся размер — 512 байт. Размер сектора — это физическая характеристика устройства, а сектор — фундаментальный элемент блочного устройства. Устройства не могут адресовать или другим образом работать с элементами данных, размер которых меньше, чем один сектор, тем не менее многие блочные устройства могут передавать несколько секторов за один раз. Хотя большинство блочных устройств и имеет размер сектора, равный 512 байт, все же существуют и другие стандартные размеры сектора (например, большинство компакт-дисков CD-ROM имеют размер сектора, равный 2 Кбайт).
У программного обеспечения несколько другие цели, и поэтому там существует другая минимально адресуемая единица, которая называется блок. Блок— это абстракция файловой системы, т.е. все обращения к файловым системам могут выполняться только с данными, кратными размеру блока. Хотя физические устройства сами по себе адресуются на уровне секторов, ядро выполняет все дисковые операции в терминах блоков. Так как наименьший возможный адресуемый элемент —- это сектор, то размер блока не может быть меньше размера одного сектора и должен быть кратен размеру сектора. Более того, для ядра (так же как и для аппаратного обеспечения в случае секторов) необходимо, чтобы размер блока был целой степенью двойки. Ядро также требует, чтобы блок имел размер, не больший, чем размер страницы памяти (см. главу 11, "Управление памятью" и главу 12, "Виртуальная файловая система")[75].
74
Для создания потоков обычно указываются флаги CLONE_FILES
и CLONE_FS
, поэтому они совместно используют структуры files_struct
и fs_struct
. С другой стороны, для обычных процессов эти флаги не указываются, поэтому для каждого процесса существует своя информация о файловой системе и своя таблица открытых файлов.
75
Это ограничение является искусственным и в будущем оно может быть отменено. Тем не менее требование, чтобы размер блока был меньше или равен размеру страницы памяти, позволяет значительно упростить ядро.