Содержание


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

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

Comments

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

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

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

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

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

Процесс связывания файловой системы с устройством в 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
Рисунок 1. Архитектурное представление компонентов файловой системы Linux

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

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

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

Это был общий взгляд на компоненты файловой системы и 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. Файловая система, зарегистрированная в ядре
Рисунок 2. Файловая система, зарегистрированная в ядре

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

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

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

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

Рисунок 4. Структура системного блока и работа узлов inode
 Рисунок 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 и связанные с ней операции
Рисунок 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, использующей архитектуру дополнений с несколькими уровнями преобразования функций.


Ресурсы для скачивания


Похожие темы

  • Оригинал статьи "Anatomy of the Linux file system" (EN).
  • Файловая система proc предоставляет новую схему связи пространства пользователя и ядра посредством виртуальной файловой системы. В статье "Доступ к ядру Linux посредством файловой системы /proc" (EN) (developerWorks, март 2006 г.) описывается виртуальная файловая система /proc и демонстрируются примеры ее использования.
  • Интерфейс системных вызовов Linux предоставляет средства управления переходом между пространством пользователя и ядром для вызова функций API ядра. В статье "Команды ядра с использованием системных вызовов Linux" (EN) (developerWorks, 2007) описывается интерфейс системных вызовов Linux.
  • На сайте Yolinux.com ведется огромный список файловых систем Linux, кластерных файловых систем и высокопроизводительных вычислительных кластеров. Кроме того, полный список файловых систем Linux можно найти в File systems HOWTO. На сайте Xenotime представлены описания множества файловых систем.
  • Более подробную информацию о программировании Linux в пространстве пользователя можно найти в книге Разработка приложений GNU/Linux (EN) , написанной автором этой статьи. (EN)
  • В разделе Linux сайта developerWorks можно найти дополнительные ресурсы для разработчиков Linux, а также познакомиться с самыми популярными статьями и руководствами. (EN)
  • Файловая система Filesystem in Userspace (FUSE) является модулем ядра, который позволяет разрабатывать файловые системы в пространстве пользователя. Реализация драйвера файловой системы направляет вызовы VFS обратно в пространство пользователя. Это отличный способ для проведения экспериментов с разработкой файловой системы без разработки ядра. Если вы используете Python, вы можете создавать файловые системы с помощью этого языка и с помощью LUFS-Python. (EN)
  • Ознакомьтесь со всеми советами Linux и руководствами Linux на developerWorks.
  • Загрузите ознакомительные версии продуктов IBM и получите инструменты разработки и системное программное обеспечение от DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.(EN)

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

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