Анатомия файловой системы Linux

Обзор многоуровневой структуры

Если говорить о файловых системах, Linux® по сравнению с другими операционными системами напоминает швейцарский армейский нож. Linux поддерживает множество файловых систем, от журналируемых до кластерных и систем с шифрованием. Linux – это замечательная платформа для использования стандартных и экзотических файловых систем, а также для разработки файловых систем. В этой статье рассматривается виртуальная файловая система (VFS) ядра Linux, которая иногда называется виртуальным коммутатором файловой системы, а также приводится обзор некоторых основных структур, связывающих файловые системы.

М. Тим Джонс, инженер-консультант, Emulex

M. Тим Джонс (M. Tim Jones) является архитектором встраиваимого программного обеспечения и автором работ: Программирование Приложений под GNU/Linux, Программирование AI-приложений и Использование BSD-сокетов в различных языках программирования. Он имеет опыт разработки процессоров для геостационарных космических летательных аппаратов, а также разработки архитектуры встраиваемых систем и сетевых протоколов. Сейчас Тим работает инженером-консультантом в корпорации Эмулекс (Emulex Corp.) в г.Лонгмонт, Колорадо.



27.11.2007

Базовая архитектура файловой системы

Архитектура файловой системы Linux являет собой интересный образец абстрагирования сложностей. Единый набор функций API позволяет поддерживать множество файловых систем на множестве устройств хранения. Возьмем, например, вызов функции read, которая позволяет считывать определенное количество байт из заданного дескриптора файла. Функция read ничего не знает о типах файловых систем, будь то ext3 или NFS. Она также не знает о носителе, на котором смонтирована файловая система, будь то диск, подключенный по интерфейсу ATA, последовательному интерфейсу SCSI (SAS) или последовательному интерфейсу ATA (SATA). И, несмотря на это, при вызове функции read для открытого файла мы получаем, как нам и хотелось, данные. В этой статье будет описано, как это достигается, а также будут рассмотрены основные структуры уровня файловой системы Linux.


Что такое файловая система?

Я начну с наиболее общего вопроса – определения файловой системы. Файловой системой называется некоторая организация данных и метаданных на устройстве хранения. Вы понимаете, что при таком нечетком определении код, его реализующий, будет очень интересным. Как я уже упоминал, существует множество типов носителей и файловых систем. Стоит ожидать, что при таком многообразии интерфейс файловой системы Linux будет реализован с использованием многоуровневой архитектуры, отделяющей уровень интерфейса пользователя от реализации файловой системы и от драйверов, управляющих устройствами хранения.

Файловые системы как протоколы

Альтернативный способ состоит в том, чтобы рассматривать файловую систему как протокол. Так же, как сетевые протоколы (например, IP) придают смысл потокам данных, передаваемым через Интернет, файловая система придает значение данным на определенном носителе.

Монтирование

Процесс связывания файловой системы с устройством в Linux называется монтированием (mounting). Для подключения файловой системы к существующей иерархии файловых систем (корню) используется команда mount. При монтировании указывается файловая система, ее тип и точка монтирования.

Чтобы продемонстрировать возможности уровня файловой системы Linux (и монтирования), создадим файловую систему в файле, расположенном в существующей файловой системе. Это можно сделать путем создания файла заданного размера с помощью dd (копирование файла из источника /dev/zero) -- другими словами, инициализируя файл нулями, как показано в листинге 1.

Листинг 1. Создание инициализированного файла
$ dd if=/dev/zero of=file.img bs=1k count=10000
10000+0 records in
10000+0 records out
$

Теперь у нас есть файл file.img размером 10 МБ. Свяжем с файлом блочное устройство-заглушку (loop) с помощью команды losetup (чтобы он выглядел как блочное устройство, а не как обычный файл файловой системы):

$ losetup /dev/loop0 file.img
$

Теперь, имея файл, который выглядит как блочное устройство (представлен /dev/loop0), создадим на этом устройстве файловую систему с помощью mke2fs. Эта команда создает новую файловую систему ext2 определенного нами размера, как видно из Листинга 2.

Листинг 2. Создание файловой системы ext2 на устройстве loop
$ mke2fs -c /dev/loop0 10000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
2512 inodes, 10000 blocks
500 blocks (5.00%) reserved for the super user
...
$

Теперь файл file.img, представленный блочным устройством (/dev/loop0), смонтирован в точке /mnt/point1 с помощью команды mount. Обратите внимание, что указанный тип файловой системы - ext2. После монтирования вы можете обращаться к точке монтирования как к новой файловой системе с помощью команды ls, как видно из Листинга 3.

Листинг 3. Создание точки монтирования и монтирование файловой системы посредством устройства loop
$ mkdir /mnt/point1
$ mount -t ext2 /dev/loop0 /mnt/point1
$ ls /mnt/point1
lost+found
$

Как показано в листинге 4, этот процесс можно продолжить, создавая новый файл в новой файловой системе, связывая его с устройством loop и создавая в нем еще одну файловую систему.

Листинг 4. Создание новой файловой системы loop в уже существующей
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=1000
1000+0 records in
1000+0 records out
$ losetup /dev/loop1 /mnt/point1/file.img
$ mke2fs -c /dev/loop1 1000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3
Filesystem label=
...
$ mkdir /mnt/point2
$ mount -t ext2 /dev/loop1 /mnt/point2
$ ls /mnt/point2
lost+found
$ ls /mnt/point1
file.img lost+found
$

Из этого простого примера легко понять, насколько большие возможности предоставляет файловая система (и устройство loop) в Linux. Аналогичным образом с помощью устройства loop можно создавать в файле файловые системы с шифрованием. Это может быть полезно для защиты ваших данных; при необходимости такой файл можно быстро смонтировать с помощью устройства loop.


Архитектура файловой системы

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


Архитектура высокого уровня

Хотя большая часть кода файловой системы реализована в ядре (за исключением файловых систем пространства пользователя, о которых я расскажу ниже), архитектура, показанная на рисунке 1, характеризует отношения между основными компонентами файловой системы, как в пространстве пользователя, так и в ядре.

Рисунок 1. Архитектурное представление компонентов файловой системы Linux
Рисунок 1. Архитектурное представление компонентов файловой системы Linux

В пространстве пользователя размещаются приложения (в этом примере - пользователь файловой системы) и библиотека GNU C (glibc), которые предоставляют интерфейс для вызова файловой системы (открытие, чтение, запись, закрытие). Интерфейс системных вызовов действует как коммутатор, направляющий системные вызовы из пространства пользователя в соответствующую точку пространства ядра.

VFS является основным интерфейсом к файловым системам нижнего уровня. Этот компонент экспортирует набор интерфейсов и после этого абстрагирует их в отдельные файловые системы, образ поведения которых может быть весьма различным. Для объектов файловой системы (узлов inodes и записей dentries) существуют два кэша, о которых я скоро расскажу. Каждый из них предоставляет пул недавно использованных объектов файловой системы.

Реализация каждой файловой системы, например, ext2, JFS и так далее, экспортирует общий массив интерфейсов, который используется (и ожидается) VFS. Буферный кэш буферизирует запросы между файловыми системами и блочными устройствами, которыми они могут управлять. Например, через буферный кэш проходят запросы на чтение и запись к драйверам устройств. Это позволяет кэшировать запросы для более быстрого доступа (вместо обращения к физическому устройству). Буферный кэш управляется набором списков последних использованных элементов (least recently used, LRU). Обратите внимание, что командой sync можно сбросить буферный кэш на носитель (принудительно отправить все незаписанные данные на драйверы устройств и, в дальнейшем, на устройства хранения).

Что такое блочное устройство?

Блочным называется устройство, данные на которое и с которого передаются блоками (например, секторами диска), и которое поддерживает такие атрибуты, как буферизация и прямой доступ (устройство не требует последовательного доступа к блокам при чтении - любой блок может быть доступен в любое время). К блочным устройствам относятся жесткие диски, CD-ROM и диски в оперативной памяти. Они являются противоположностью символьным устройствам, отличие которых состоит в том, что у них нет носителя с физической адресацией. К символьным устройствам относятся последовательные порты и ленточные устройства, в которых данные передаются посимвольно.

Это был общий взгляд на компоненты файловой системы и VFS. Давайте теперь рассмотрим основные структуры, составляющие эту подсистему.

Основные структуры

В Linux все файловые системы рассматриваются с точки зрения общего набора объектов. К этим объектам относятся системные блоки, узлы inode, записи dentry и файлы. Корнем каждой файловой системы является системный блок, который описывает и поддерживает состояние файловой системы. Каждый объект, с которым работает файловая система (файл или директория) представлен в Linux узлом inode. Узел inode хранит в себе все метаданные для управления объектами файловой системы (в том числе и возможных операциях с ним). Другое множество структур, которое называют записями dentry, используется для осуществления преобразования между названиями и узлами inode, для чего существует кэш директорий, в котором хранятся последние использованные записи. В записях dentry также хранятся отношения между папками и файлами для обхода файловых систем. И, наконец, файл VFS представляет собой открытый файл (содержит состояние открытого файла, в том числе смещение для записи и т.п.).

Уровень виртуальной файловой системы

VFS действует как корневой уровень интерфейса файловой системы. VFS следит за всеми поддерживаемыми и всеми смонтированными на данный момент файловыми системами.

Файловые системы в Linux можно динамически добавлять и удалять с помощью нескольких функций регистрации. В ядре хранится список поддерживаемых файловых систем, который можно просмотреть из пространства пользователя посредством файловой системы /proc. В этом виртуальном файле также показаны устройства, связанные на текущий момент с файловыми системами. Для того, чтобы добавить новую файловую систему в Linux, вызывается register_filesystem. Эта команда имеет один аргумент - ссылку на структуру файловой системы (file_system_type), которая определяет название файловой системы, набор атрибутов и две функции системных блоков. Файловая система также может быть незарегистрированной.

Регистрация новой файловой системы заключается в добавлении этой системы и относящейся к ней информации в список file_systems (см. рисунок 2 и linux/include/linux/mount.h). Этот список определяет поддерживаемые файловые системы. Просмотреть его можно, введя в командной строке cat /proc/filesystems.

Рисунок 2. Файловая система, зарегистрированная в ядре
Рисунок 2. Файловая система, зарегистрированная в ядре

Другой структурой, поддерживаемой VFS, являются смонтированные файловые системы (см. рисунок 3). Она предоставляет список смонтированных на данный момент файловых систем (см. linux/include/linux/fs.h). Она ссылается на структуру системного блока superblock, о котором я расскажу ниже.

Рисунок 3. Список смонтированных файловых систем
Рисунок 3. Список смонтированных файловых систем

Системный блок

Системным блоком (superblock) называется структура, представляющая файловую систему. В нее входит информация, необходимая для управления файловой системой во время работы. К такой информации относится название файловой системы (например, ext2), размер файловой системы и ее состояние, ссылку на блочное устройство и информацию метаданных (например, списки свободных блоков и т.п.). Как правило, системный блок хранится на носителе, но если его нет, он может быть создан в реальном времени. Структуру системного блока (см. рисунок 4) можно найти в ./linux/include/linux/fs.h.

Рисунок 4. Структура системного блока и работа узлов inode
Рисунок 4. Структура системного блока и работа узлов inode

Одним из важнейших элементов системного блока является определение его операций. Эта структура определяет набор функций для управления узлами inodes файловой системы. Например, inodes могут выделяться с помощью alloc_inode и удаляться с помощью destroy_inode. Вы можете считывать и записывать inodes с помощью команд read_inode и write_inode и синхронизировать файловую систему с помощью команды sync_fs. Структура super_operations расположена в ./linux/include/linux/fs.h. В каждой файловой системе имеются собственные методы inode, которые реализуют работу и выполняют общую абстракцию на уровень VFS.

Узлы inode и dentry

Узел inode представляет объект файловой системы с уникальным идентификатором. Каждая файловая система предоставляет методы преобразования имен файлов в уникальные идентификаторы inode и затем – в ссылки на inode. На рисунке 5 показана часть структуры inode вместе с несколькими связанными структурами. Обратите внимание, в частности, на inode_operations и file_operations. Каждая из этих структур ссылается на отдельные операции, которые могут выполняться с inode. Например, inode_operations определяет операции, которые работают напрямую с inode, а file_operations относится к методам, которые работают с файлами и директориями (стандартные системные вызовы).

Рисунок 5. Структура inode и связанные с ней операции
Рисунок 5. Структура inode и связанные с ней операции

Последние использованные узлы inodes и записи dentries хранятся в кэше inode и кэше директорий соответственно. Обратите внимание, что каждому inode в кэше inode соответствует запись dentry в кэше директорий. Структуры inode и dentry определены в ./linux/include/linux/fs.h.

Буферный кэш

За исключением отдельных реализаций файловых систем (которые можно найти в ./linux/fs), в нижней части уровня файловой системы располагается буферный кэш. Здесь хранятся запросы на чтение и запись от отдельных файловых систем и физических устройств (посредством драйверов устройств). Из соображений производительности в Linux предусмотрен кэш запросов, позволяющий не обращаться по каждому запросу к физическому устройству. Вместо этого в нем кэшируются последние использованные буферы (страницы), которые могут быть быстро предоставлены отдельным файловым системам.


Интересные файловые системы

В этой статье не рассказывается о конкретных отдельных файловых системах, доступных в Linux, но здесь будет полезно их упомянуть, хотя бы мимоходом. Linux поддерживает множество файловых систем, начиная от самых старых - MINIX, MS-DOS и ext2. Linux также поддерживает новые файловые системы с журналированием, к которым относятся ext3, JFS и ReiserFS. Кроме того, в Linux поддерживаются файловые системы с шифрованием, такие как CFS, и виртуальные файловые системы, такие как /proc.

И, наконец, отдельно стоит отметить файловую систему Filesystem in Userspace или FUSE. Это интересный проект, который позволяет вам направлять запросы к файловой системе через VFS обратно в пространство пользователя. Поэтому, если вы задумывались о создании собственной файловой системы, то это отличный шанс для того, чтобы начать.


Заключение

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

Ресурсы

Научиться

Получить продукты и технологии

  • Файловая система Filesystem in Userspace (FUSE) является модулем ядра, который позволяет разрабатывать файловые системы в пространстве пользователя. Реализация драйвера файловой системы направляет вызовы VFS обратно в пространство пользователя. Это отличный способ для проведения экспериментов с разработкой файловой системы без разработки ядра. Если вы используете Python, вы можете создавать файловые системы с помощью этого языка и с помощью LUFS-Python. (EN)
  • Загрузите ознакомительные версии продуктов IBM и получите инструменты разработки и системное программное обеспечение от DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=271388
ArticleTitle=Анатомия файловой системы Linux
publish-date=11272007