Операционные системы

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

При каждом сохранении фото, скачивании файла, запуске игры - за кулисами работает файловая система. Она превращает хаос из миллиардов байт на диске в упорядоченную библиотеку, где каждый файл на своём месте. Магнитные дорожки HDD или флеш-ячейки SSD - всё это спрятано за простой абстракцией: open/read/write. Понимание файловых систем - это понимание того, как компьютер хранит данные.

  • **Почему восстановление удалённых файлов возможно?** После нажатия Delete данные остаются на диске! FS просто помечает блоки как свободные в bitmap. Программы типа PhotoRec сканируют диск, ищут "сироты" - блоки данных без записей в директориях. Пока блоки не перезаписаны, файл можно вернуть.
  • **Почему macOS копирует файлы на флешку быстрее, чем удаляет?** На флешках обычно FAT32. При копировании FS просто пишет данные в свободные блоки. При удалении большой папки нужно обойти всё дерево директорий, обновить FAT таблицу для каждого файла - много операций метаданных.
  • **Как Git хранит миллионы версий файлов без дублирования?** Git использует content-addressable storage: имя файла = хэш содержимого. Одинаковые файлы → один хэш → одна копия на диске. Это похоже на hard links в UNIX: множество "имён" (версий) указывают на одни данные.

Цели урока

  • Понимать inode: метаданные файла без имени; hard link vs symbolic link
  • Различать allocation: contiguous, linked, indexed (inode block pointers)
  • Сравнить ext4, XFS, Btrfs, ZFS по фичам (snapshots, COW, integrity, scale)
  • Объяснить journaling (data vs metadata) и почему он спасает после crash
  • Знать VFS abstraction в Linux: единый API над разными FS

Концепция файла

**Файл** - именованная последовательность байт на устройстве хранения. Абстракция файла прячет физическую раскладку (магнитные дорожки, флеш-ячейки, секторы) за крошечным интерфейсом: open/read/write/close. Те же системные вызовы работают на HDD, SSD, сетевом монтировании, /proc, /dev/null.

Файл как черный ящик

Аналогия: библиотека. Читатель просит книгу по названию - библиотекарь приносит её. Знать, на каком этаже, в каком шкафу и на какой полке - не нужно. **Файловая система - это библиотекарь**, а **файл - это название книги**. Физическое расположение на диске скрыто от программиста.

С точки зрения OS, файл характеризуется **метаданными** (metadata): - **Имя** - для идентификации - **Тип** - расширение (.txt, .exe, .mp4) - **Размер** - количество байт - **Права доступа** - кто может читать/писать/выполнять - **Временные метки** - создание, изменение, последний доступ - **Указатели на данные** - где физически лежат блоки файла

**В UNIX "всё есть файл":** - Обычные файлы (regular files) - Директории (специальный тип файла) - Устройства: `/dev/sda` (жесткий диск), `/dev/null` (черная дыра) - Pipes и sockets для межпроцессного взаимодействия - Виртуальные файлы: `/proc/cpuinfo` (информация о CPU) Единый интерфейс `open/read/write/close` работает для всех!

**Файловые операции** - основной способ взаимодействия программ с данными. Системные вызовы (syscalls) предоставляют единый интерфейс независимо от типа устройства хранения (HDD, SSD, сетевой диск).

Почему SSD быстрее HDD?

**HDD (Hard Disk Drive):** механический диск с вращающимися пластинами и движущейся головкой. Чтение файла требует физического перемещения головки к нужной дорожке - это медленно (~10мс latency). Типичная скорость: 100-200 MB/s. **SSD (Solid State Drive):** флеш-память без движущихся частей. Доступ к любой ячейке памяти почти мгновенный (~0.1мс latency). Типичная скорость: 500-7000 MB/s (NVMe SSD). Файловая система одна и та же (ext4, NTFS), но железо определяет производительность.

**Файловый дескриптор (file descriptor)** - это целое число, представляющее открытый файл в процессе. OS ведет таблицу открытых файлов для каждого процесса. При открытии файла возвращается дескриптор, через который происходит вся дальнейшая работа.

Что происходит, когда программа выполняет системный вызов read(fd, buffer, 1024)?

Структура директорий

**Директория (каталог)** - это специальный файл, содержащий список других файлов и директорий. Директории организуют файлы в иерархическую древовидную структуру, упрощая навигацию и управление.

**Абсолютный путь** начинается с корня `/` и указывает точное местоположение файла: `/home/alice/documents/report.pdf`. **Относительный путь** зависит от текущей рабочей директории (current working directory): `./documents/report.pdf` или просто `documents/report.pdf`.

**Специальные директории:** - `.` (точка) - текущая директория - `..` (две точки) - родительская директория - `~` (тильда) - домашняя директория пользователя (в bash) - `/` (слеш) - корневая директория Пример: `/home/alice/../bob/file.txt` → `/home/bob/file.txt`

Как директория хранится на диске?

Директория - это **таблица**, где каждая запись содержит: - **Имя файла** (например, `document.txt`) - **Inode number** (указатель на метаданные файла) В ext4 (Linux) директория хранится как файл специального типа. Системный вызов `readdir()` читает эту таблицу и возвращает список файлов.

**Жесткие ссылки (hard links)** позволяют одному файлу иметь несколько имен в разных (или одной) директориях. Все имена указывают на один и тот же inode. Файл удаляется с диска только когда счетчик ссылок достигает нуля.

**Символические ссылки (symlinks)** - это специальный файл, содержащий путь к другому файлу. В отличие от hard link, symlink может указывать на файл в другой файловой системе или даже на несуществующий файл ("мёртвая ссылка").

Windows vs UNIX: разные подходы

**UNIX:** единое дерево с корнем `/`. Все диски, USB-флешки монтируются в поддиректории: `/mnt/usb`, `/media/cdrom`. **Windows:** множественные корни (drive letters): `C:\`, `D:\`, `E:\`. Каждый диск - отдельное дерево. Нет единой точки входа. Преимущество UNIX-подхода: программа не зависит от того, на каком физическом диске лежит файл. Путь `/data/file.txt` может быть на SSD, HDD или сетевом хранилище - программе всё равно.

В чем ключевое отличие жесткой ссылки (hard link) от символической (symlink)?

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

Файловая система - это не просто способ организации файлов, это **сложная структура данных на диске**. Она решает задачи: где хранить данные файла, где хранить метаданные, как отслеживать свободное место, как обеспечить целостность при сбоях.

**Superblock** - главная структура метаданных файловой системы. Содержит критическую информацию: - Размер файловой системы - Размер блока (обычно 4096 байт) - Количество свободных блоков и inode - Magic number (идентификатор типа FS) - Дата последнего монтирования - Счетчик монтирований (для проверки целостности) Повреждение superblock делает FS нечитаемой, поэтому хранятся резервные копии.

**Inode (Index Node)** - структура данных, хранящая метаданные файла: - Размер файла (в байтах) - Права доступа (owner, group, permissions) - Временные метки (creation, modification, access) - Количество hard links - **Указатели на блоки данных** (где лежит содержимое) Имя файла НЕ хранится в inode! Имя - это запись в директории, связывающая имя с номером inode.

Почему удаление файла быстрое?

При удалении файла командой `rm` OS **НЕ стирает данные с диска**. Вместо этого: 1. Запись в директории удаляется (имя → inode) 2. Счетчик hard links в inode уменьшается 3. Если счетчик = 0, блоки файла помечаются как свободные в bitmap Данные остаются на диске до перезаписи! Поэтому возможно восстановление удаленных файлов специальными утилитами (пока блоки не заняты новыми данными).

**Указатели на блоки данных в inode:** как файл может быть больше, чем количество указателей? В ext4 inode содержит 15 указателей: - **12 прямых** (direct blocks) - указывают непосредственно на блоки данных - **1 одноуровневый косвенный** (indirect) - указывает на блок, содержащий указатели на данные - **1 двухуровневый косвенный** (double indirect) - указатель на блок указателей на блоки указателей - **1 трехуровневый косвенный** (triple indirect)

ext4 vs NTFS vs APFS

**ext4 (Linux):** inode-based, журналирование, поддержка огромных файлов (до 16TB). Оптимизирован для серверов и десктопов. **NTFS (Windows):** Master File Table (MFT) вместо inode, встроенное сжатие и шифрование. Поддержка файлов до 16EB (эксабайт!). **APFS (macOS, iOS):** copy-on-write (COW), мгновенные снимки (snapshots), шифрование на уровне FS. Оптимизирован для SSD. Общее: все современные FS используют журналирование для защиты от сбоев (подробнее позже).

**Журналирование (journaling)** защищает файловую систему от повреждений при сбоях питания или краше системы. Перед изменением данных на диске, операция записывается в журнал (log). Если сбой произошел в момент записи, при перезагрузке FS читает журнал и завершает/откатывает операцию.

Почему inode хранит указатели на блоки данных, но не хранит имя файла?

Методы размещения файлов

**Как разместить файл на диске?** Ключевой design choice ФС. Trade-off: скорость доступа vs эффективность места vs фрагментация. Три классических метода, у каждого свои издержки.

**Три основных метода размещения:** 1. **Contiguous (последовательное)** - файл занимает непрерывный блок секторов 2. **Linked (связанное)** - блоки файла связаны указателями (как linked list) 3. **Indexed (индексированное)** - все указатели на блоки в одном месте (inode, FAT)

**Contiguous allocation (последовательное размещение):** Файл хранится в последовательных блоках диска. Для доступа к файлу нужно знать только начальный блок и длину. **Плюсы:** - Отличная производительность (особенно на HDD - минимум перемещений головки) - Простота: нужно хранить только start_block и length **Минусы:** - **Внешняя фрагментация:** со временем между файлами образуются дыры - Сложно расширить файл (нужно перемещать на новое место)

**Linked allocation (связанное размещение):** Каждый блок файла содержит указатель на следующий блок (как linked list). Директория хранит указатель на первый блок. **Плюсы:** - Нет внешней фрагментации - Легко расширить файл (добавить блок в конец списка) **Минусы:** - **Медленный произвольный доступ:** чтобы прочитать блок N, нужно пройти N-1 указателей - Потеря одного блока (повреждение) ломает всю цепочку - Накладные расходы: каждый блок тратит место на указатель

FAT (File Allocation Table) - улучшенный linked

FAT (используется на флешках, SD-картах) решает проблему медленного доступа: вместо хранения указателей в блоках данных, создаётся **отдельная таблица** всех указателей. Таблица FAT хранится в начале диска и кешируется в памяти. Чтобы найти N-й блок файла, достаточно N раз прочитать таблицу в RAM (быстро!), без обращений к диску.

**Indexed allocation (индексированное размещение):** Все указатели на блоки файла хранятся в **индексном блоке** (inode в UNIX, MFT в NTFS). Это как оглавление книги: один взгляд - и ясно, где какие данные. **Плюсы:** - Быстрый произвольный доступ: индекс в памяти → прямое чтение блока - Нет внешней фрагментации - Поддержка огромных файлов (через многоуровневые индексы) **Минусы:** - Накладные расходы на хранение индекса (особенно для маленьких файлов)

**Фрагментация:** - **Внешняя фрагментация** (external fragmentation) - свободное место разбито на мелкие непрерывные куски. Много суммарного места, но нельзя выделить большой непрерывный блок. Проблема contiguous allocation. - **Внутренняя фрагментация** (internal fragmentation) - файл занимает блок не полностью. Например, файл 100 байт в блоке 4096 байт → 3996 байт потрачено впустую. Проблема всех методов с фиксированным размером блока.

Почему современные SSD любят indexed allocation?

На HDD contiguous allocation быстрее: головка читает последовательные секторы без перемещений. Но на SSD нет механических частей! Произвольный доступ так же быстр, как последовательный. Indexed allocation (ext4, APFS, NTFS) идеальна для SSD: - Быстрый произвольный доступ к любому блоку - Нет фрагментации производительности - Легко реализовать TRIM (сообщение SSD о свободных блоках для garbage collection)

Ключевые идеи

  • **Файл - абстракция хранения данных.** OS скрывает сложность физического диска (секторы, дорожки) за простым API: open/read/write/close. Единый интерфейс работает для HDD, SSD, сетевых дисков, виртуальных файлов /proc.
  • **Директории организуют файлы в иерархию.** Директория - это таблица (имя → inode number). Жесткие ссылки (hard links) позволяют одному файлу иметь несколько имён. Символические ссылки (symlinks) - отдельные файлы, хранящие пути к другим файлам.
  • **Inode хранит метаданные, не имя.** В ext4/UNIX: inode = размер, права, временные метки, указатели на блоки данных. Имя файла - это запись в директории. Один inode может иметь много имён (hard links). При удалении имени файл живёт, пока счётчик ссылок > 0.
  • **Три метода размещения файлов: Contiguous (быстро, но фрагментация), Linked (гибко, но медленный доступ), Indexed (баланс - используется в ext4, NTFS, APFS).** Современные FS используют indexed allocation с многоуровневыми индексами для поддержки огромных файлов. SSD предпочитают indexed (произвольный доступ быстрый), HDD исторически любили contiguous.

Связанные темы

Файловые системы связывают абстракции OS с физическим железом:

  • Управление памятью — Page cache: FS кеширует блоки диска в RAM для ускорения. Виртуальная память использует файлы swap. mmap() проецирует файл в адресное пространство процесса
  • Устройства ввода-вывода — Драйверы дисков (SATA, NVMe) преобразуют запросы FS в команды контроллеру. Буферизация, DMA, прерывания - всё для эффективного I/O
  • Процессы и системные вызовы — Файловые дескрипторы (fd) - способ процессов работать с файлами. fork() копирует таблицу fd. exec() наследует открытые файлы. Pipes - тоже файлы!
  • Безопасность OS — Права доступа к файлам (rwx для owner/group/others), ACL (Access Control Lists), SELinux. FS - первая линия защиты данных

Вопросы для размышления

  • Файловая система для космического корабля (экстремальная надёжность, радиация может повредить данные): какие механизмы защиты добавить? Как хранить метаданные?
  • Git и Docker используют copy-on-write (COW) файловые системы. Как это связано с эффективностью хранения миллионов версий и слоёв образов?
  • Почему UNIX-философия "всё есть файл" (устройства, процессы, сокеты) оказалась так успешна? Какие альтернативные абстракции существуют?

Связанные уроки

  • os-10-io — Файловая система работает поверх I/O подсистемы
  • os-08-virtual-memory — mmap объединяет файловую систему и виртуальную память
  • db-09-indexes-btree — B-tree индексы в БД - те же структуры, что в ext4/NTFS
  • db-34-lsm
  • db-07-postgresql
Файловые системы

0

1

Войти

**Управление свободным пространством:** Как FS отслеживает свободные блоки? 1. **Bitmap (битовая карта):** 1 бит на блок. 0 = свободен, 1 = занят. Для диска 1TB с блоками 4KB нужно ~32MB для bitmap. 2. **Linked list свободных блоков:** каждый свободный блок указывает на следующий. Медленный поиск свободного пространства. 3. **Группированная карта (ext4):** диск разбит на группы блоков, у каждой группы своя bitmap. Быстрее, чем глобальный поиск.

Дефрагментация диска всегда ускоряет работу компьютера

Дефрагментация полезна для HDD с contiguous allocation, но бесполезна (и даже вредна) для SSD

На HDD фрагментированные файлы требуют частых перемещений головки → медленно. Дефрагментация переносит блоки в непрерывные области → меньше seek-ов → быстрее. На SSD нет механических частей - произвольный доступ так же быстр, как последовательный. Хуже того: дефрагментация жжёт циклы записи и сокращает срок службы SSD (у каждой ячейки ограниченное число записей). Современные FS (ext4, APFS, NTFS) используют indexed allocation с extents (группами последовательных блоков), и фрагментация остаётся низкой без ручного дефрага.

Файловая система использует блоки размером 4096 байт. Файл размером 10000 байт хранится методом indexed allocation. Сколько блоков будет выделено?