Устройство файловой системы: FHS, inode, ext4

Разбираемся, как Linux раскладывает файлы по дереву каталогов и что на самом деле такое «файл» с точки зрения файловой системы ext4.

inode — структура с метаданными одного файла (права, владелец, размер, время, указатели на блоки данных), но БЕЗ его имени. Имя живёт отдельно — в каталоге.

Зачем это знать на практике

Рано или поздно вы упрётесь в одну из классических ситуаций: df говорит, что диск занят на 100%, а du насчитывает в разы меньше; rm «удалил» файл, но место не освободилось; на разделе «закончились файлы», хотя свободных гигабайт полно. Все эти загадки объясняются устройством файловой системы — иерархией каталогов и тем, что файл и его имя — это две разные сущности. Понимание inode превращает магию в инженерию.

Стандарт иерархии: FHS

В Linux нет дисков C: и D:. Есть единый корень /, в который монтируется всё остальное. Раскладку каталогов описывает стандарт FHS (Filesystem Hierarchy Standard) — благодаря ему вы знаете, где искать конфиги в любом дистрибутиве.

КаталогЧто внутри
/etcсистемные конфиги (текстовые файлы): пользователи, сеть, сервисы
/varизменяемые данные: логи (/var/log), кэши, очереди, БД
/usrпрограммы и библиотеки, установленные пакетным менеджером (/usr/bin, /usr/lib)
/homeдомашние каталоги пользователей
/bin, /sbinбазовые утилиты (в современных системах — симлинки в /usr)
/tmpвременные файлы, чистится при перезагрузке
/proc, /sysвиртуальные ФС: окно в ядро и устройства, на диске их нет
/devфайлы устройств (диски, терминалы, /dev/null)

/proc — файлы, которых нет

/proc — не настоящий каталог на диске, а интерфейс ядра, прикинувшийся файловой системой. Каждый запущенный процесс получает там подкаталог по своему PID, а отдельные «файлы» отдают живое состояние системы:

cat /proc/cpuinfo        # модель и число ядер CPU
cat /proc/meminfo        # сколько памяти всего и свободно
cat /proc/loadavg        # средняя нагрузка за 1/5/15 минут
ls /proc/$$/             # каталог ТЕКУЩЕЙ оболочки ($$ — её PID)

Размер у этих файлов нулевой — они генерируются на лету в момент чтения. Это самый прямой способ «поговорить» с ядром без специальных утилит.

Что такое файл на самом деле

Файл — это inode плюс блоки данных. В inode хранится всё, КРОМЕ имени: тип (обычный файл, каталог, симлинк), права, UID/GID владельца, размер, временные метки и указатели на блоки с содержимым. Имя файла лежит в каталоге, который, по сути, является таблицей пар «имя → номер inode».

Каждый inode имеет уникальный в пределах файловой системы номер. Посмотреть его можно ключом -i:

ls -i /etc/hostname
# 131073 /etc/hostname

stat /etc/hostname
#   File: /etc/hostname
#   Size: 7    Blocks: 8    IO Block: 4096   regular file
# Device: 803h/2051d   Inode: 131073   Links: 1
# Access: (0644/-rw-r--r--)  Uid: (0/root)  Gid: (0/root)

Команда stat — это прямой дамп inode. Обратите внимание на поле Links: это счётчик жёстких ссылок (имён), указывающих на данный inode. К нему мы вернёмся в уроке про ссылки.

Три времени файла

  • atime — время последнего доступа (чтения);
  • mtime — время последнего изменения содержимого;
  • ctime — время последнего изменения метаданных inode (например, chmod меняет ctime, но не mtime).
stat -c '%n  atime=%x  mtime=%y  ctime=%z' /etc/hostname

Как это работает под капотом

Файловая система ext4 делит раздел на блоки (обычно по 4 КБ) и группы блоков. В начале раздела лежит суперблок с общими параметрами ФС, а в каждой группе — таблица inode фиксированного размера. Число inode задаётся при создании файловой системы (mkfs.ext4) и потом не меняется. Поэтому возможна ситуация «место есть, а inode кончились»: миллионы крошечных файлов исчерпали таблицу inode раньше, чем гигабайты.

df -i            # сколько inode свободно (а не байт)
# Filesystem      Inodes   IUsed   IFree IUse% Mounted on
# /dev/sda1      6553600  280143 6273457    5% /

Когда вы открываете файл, ядро по имени из каталога находит номер inode, читает inode, по его указателям добирается до блоков данных. ext4 хранит указатели не списком, а экстентами — диапазонами подряд идущих блоков, что ускоряет работу с большими файлами и снижает фрагментацию. Ещё ext4 ведёт журнал (journal): перед записью изменения сначала фиксируются в журнале, поэтому после внезапного выключения ФС восстанавливается в согласованное состояние, а не «разваливается».

Частые ошибки

  • Путать размер файла и занятое место. «Дырявый» (sparse) файл может показывать размер 10 ГБ, но занимать на диске килобайты. du --apparent-size покажет логический размер, обычный du — реально занятые блоки.
  • Думать, что rm стирает данные сразу. Удаление лишь убирает имя из каталога и уменьшает счётчик ссылок. Пока файл открыт хоть одним процессом, его inode и блоки живут — место освободится только после закрытия дескриптора.
  • Полагаться на atime. Многие системы монтируют ФС с relatime или noatime, чтобы не писать на диск при каждом чтении, поэтому atime может быть неточным.

Итоги

  • В Linux один корень /, раскладку каталогов диктует стандарт FHS: /etc — конфиги, /var — логи и данные, /usr — программы.
  • /proc и /sys — виртуальные ФС-окна в ядро; их «файлы» генерируются на лету.
  • Файл = inode (метаданные + указатели на блоки) + само имя в каталоге; имя и inode разделены.
  • ls -i и stat показывают inode; df -i — запас inode, который тоже может закончиться.
  • ext4 использует экстенты и журнал — отсюда скорость и устойчивость к сбоям.
Проверьте себя
1. Где хранится ИМЯ файла в файловой системе ext4?
AВ самом inode вместе с правами и размером
BВ каталоге — как пара «имя → номер inode»
CВ суперблоке раздела
DВ первом блоке данных файла
2. Команда df показывает, что на разделе ещё много свободных гигабайт, но создать новый файл не получается — система пишет, что места нет. Что проверить в первую очередь?
AЖурнал ext4 командой dmesg
BЗапас inode командой df -i
CРазмер суперблока через stat
DВремя atime у каталога