Анатомия файловых систем: от FFS до современных вызовов

Когда мы работаем с файлами, мы редко задумываемся о том, что происходит «под капотом» операционной системы. Однако именно архитектура файловой системы определяет скорость работы приложений, надежность хранения данных и даже стоимость облачных сервисов.

В этой статье мы разберем ключевые механизмы, эволюция которых привела нас от механических жестких дисков к современным SSD и распределенным хранилищам.
Fast File System (FFS): Рождение локальности

В эпоху господства HDD главным врагом производительности было позиционирование головок. Каждое перемещение головки к другому цилиндру стоило драгоценных миллисекунд.

Решение FFS (BSD): Принцип географической локальности.
Вместо разбрасывания файлов по всему диску, система группирует связанные данные. Каталог и его файлы размещаются в пределах одной группы цилиндров.

Это положило начало современным подходам к организации метаданных.

В состав каждой группы цилиндров входят:
- резервная копия суперблока
- битовые карты свободных блоков и inode
- таблица inode
- блоки данных
Даже в современных файловых системах (ext4, XFS) используется понятие «групп блоков» (block groups), унаследованное от идей FFS.

Inode и жесткие ссылки

Inode (индексный дескриптор) содержит метаданные файла: права доступа, владельца, временные метки, счетчик ссылок и указатели на блоки данных. Каталог представляет собой особый тип файла, содержащий соответствия между именами и номерами inode.

Жесткая ссылка - это дополнительная запись в каталоге, указывающая на существующий inode. Файл может иметь произвольное количество имен в различных каталогах; все они разделяют один inode и, соответственно, идентичное содержимое. Счетчик ссылок отслеживает количество имен файла. Удаление одного имени декрементирует счетчик; физическое удаление данных происходит только при обнулении счётчика и отсутствии открытых файловых дескрипторов.

Все имена равноправны. Счетчик ссылок в inode показывает, сколько имен у файла. Физическое удаление данных происходит только при обнулении счетчика.

Важно: Жесткие ссылки не могут указывать на каталоги (из-за риска циклов) и не работают между разными файловыми системами.

Журналирование: Гарантия консистентности

Ранние файловые системы (FFS, ext2) требовали длительной проверки fsck после сбоя питания. Журналирование (ext3, ext4, XFS) решило эту проблему.

Как это работает:

  • Операция с метаданными записывается в журнал (логирующая область)
  • Система применяет изменения к основной структуре
  • После успеха операции пометка в журнале снимается (циклический буфер)
  • При краше система просто «доигрывает» или откатывает операции из журнала, избегая многоминутных проверок
Символические ссылки

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

Размещение данных символической ссылки зависит от ее длины. При небольшом размере путь хранится непосредственно в inode ссылки, что обеспечивает нулевой расход дополнительных блоков. При превышении емкости inode данные размещаются в отдельном блоке фиксированного размера (часто- 4 КБ), что приводит к дискретному росту фактического занимаемого пространства.

Интересная оптимизация хранения:

Если путь к файлу короткий (обычно до 60 байт), он хранится прямо в структуре inode ссылки. Это экономит место и ускоряет доступ.

Если путь длинный — выделяется отдельный блок данных (чаще всего 4 КБ).

Разреженные файлы (Sparse Files)
Представьте файл размером 4 ГБ, который занимает на диске всего 4 КБ. Это возможно благодаря поддержке «дыр» (holes).

Создать такой файл можно, например, так:

bash
dd if=/dev/zero of=sparse_file bs=1K seek=4M count=1
Здесь мы перемещаемся (seek) на 4 миллиона блоков вперед и записываем один блок. Все пропущенные блоки физически не выделяются.

Проблемы резервного копирования
Стандартные команды cp, scp, rsync (без флагов) могут «развернуть» разреженный файл в обычный, занимая всё выделенное место на диске приемника.
Правильно: cp --sparse=always или rsync --sparse.

Инкрементальное обновление дисков (Binary Delta)
В мире встроенных систем и IoT обновление прошивки по медленному каналу — нетривиальная задача. Вместо передачи полного образа диска используются алгоритмы бинарной разности.

Анализ выявляет:
- идентичные чанки, не требующие передачи
- чанки, присутствующие в целевой версии, но отсутствующие в текущей (требуют передачи)
- чанки, сдвинутые по смещению (перестановка без передачи данных)
- нулевые чанки (пропускаются)

Эффективность метода зависит от степени схожести версий и характеристик файловой системы (размера блоков, экстентов, фрагментации).


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