# btrfs - copy-on-write, subvolumes и снапшоты _Файловая система · LinuxLab Knowledge Base_ **TL;DR:** btrfs - copy-on-write ФС с subvolume'ами, снапшотами за O(1), нативным RAID 0/1/10 и чексуммами данных. RAID 5/6 проблемен. COW-фрагментация бьёт БД и VM-image - выключай для них. ## Зачем btrfs Появилась в 2009 как ответ на ZFS. Дала Linux'у: - **Copy-on-write (COW)** - запись не правит блок, пишет в новое место и обновляет указатель - **Subvolume** - именованный поддиректорий, который можно отдельно монтировать, снапшотить, отправлять - **Снапшоты за O(1)** - дешёвая копия subvolume через хитрый COW - **Чексуммы данных + метаданных** - видим bit rot до того как он испортит файл - **Нативный RAID 0/1/10** - без mdraid сверху - **Send/receive** - инкрементальная репликация Default на openSUSE Tumbleweed, Fedora Workstation 33+. На прод-серверах встречается реже из-за **исторической нестабильности RAID 5/6** и COW-фрагментации. ## Copy-on-write - суть Когда меняется блок: - **Не-COW** ([ext4](/kb/ext4.md), [xfs](/kb/xfs.md)): пишем в тот же блок - **COW** (btrfs, ZFS): пишем в новый блок, обновляем указатель в дереве Плюсы: - Снапшот за O(1): просто новое имя, ссылающееся на те же блоки - Crash-safe без журнала: всегда есть консистентный момент - Чексуммы автоматически проверяются при чтении Минусы: - **Фрагментация** - частые правки одного файла раскидывают его по диску. Особенно бьёт БД (page-level правки) и VM-images. - Места не предсказать: один файл занимает места больше при смене блока, потому что старая версия может быть удержана снапшотом. Решение для БД/VM - `chattr +C` (отключить COW для конкретных файлов): ```bash mkdir /data/postgres chattr +C /data/postgres # для всех новых файлов внутри cp -a /old/postgres/* /data/postgres/ ``` `chattr +C` работает только при создании файла; на существующие не накатится без перекопирования. ## Subvolume Subvolume - это **отдельное дерево** внутри одной ФС. Не раздел в партициях, а логическая единица btrfs: ```bash mkfs.btrfs /dev/sdb1 mount /dev/sdb1 /mnt btrfs subvolume create /mnt/@home btrfs subvolume create /mnt/@var btrfs subvolume list /mnt ``` Преимущества: - Можно монтировать subvolume отдельно (`mount -o subvol=@home`) - Свои квоты, свои снапшоты - Изолированные ENOSPC-границы (опционально, через quotas) Распространённый layout: ``` /mnt/ ← top-level ├─ @ ← root / ├─ @home ← /home ├─ @var ← /var └─ @snapshots ← /.snapshots ``` В fstab: ```fstab UUID=... / btrfs defaults,subvol=@,compress=zstd:1 0 0 UUID=... /home btrfs defaults,subvol=@home,compress=zstd:1 0 0 ``` ## Снапшоты ```bash # Снапшот subvolume btrfs subvolume snapshot /mnt/@home /mnt/@snapshots/home-$(date +%F) # Read-only снапшот (для бэкапов через send) btrfs subvolume snapshot -r /mnt/@home /mnt/@snapshots/home-ro # Откат: переименовать btrfs subvolume delete /mnt/@home_broken btrfs subvolume snapshot /mnt/@snapshots/home-2026-05-01 /mnt/@home ``` Снапшот мгновенный, занимает 0 места изначально. По мере правок оригинал и снапшот расходятся - и место расходуется на различие. ## Send / receive Инкрементальная репликация на другой btrfs: ```bash # Полный send первого снапшота btrfs send /mnt/@snapshots/home-2026-05-01 | ssh remote 'btrfs receive /backup/' # Инкрементальный btrfs send -p /mnt/@snapshots/home-2026-05-01 /mnt/@snapshots/home-2026-05-02 \ | ssh remote 'btrfs receive /backup/' ``` Шлёт только дельту между снапшотами - бэкапы быстрые и компактные. Это лучшая альтернатива rsync для большого датасета. ## RAID btrfs умеет RAID **по блокам, не по дискам**: ```bash mkfs.btrfs -d raid1 -m raid1 /dev/sdb /dev/sdc # data + metadata mirror mkfs.btrfs -d raid10 -m raid1 /dev/sd{b,c,d,e} # data RAID10, meta mirror mkfs.btrfs -d single -m raid1 /dev/sdb /dev/sdc # данные не зеркалят, метаданные да ``` Уровни: - `single` - без избыточности - `dup` - две копии на одном диске (default для metadata на single-disk) - `raid0` - страйп без избыточности - `raid1` - **зеркало (но N-way: 2 копии на N+ дисках, не как mdraid)** - `raid1c3`, `raid1c4` - 3-way и 4-way mirror - `raid10` - страйп зеркал - `raid5`, `raid6` - **исторически нестабильны**, write hole. До 2024 избегали. С новыми ядрами (6.x) ситуация улучшилась, но multi-disk проды всё ещё чаще на mdraid + ext4/xfs. Добавить/убрать диск online: ```bash btrfs device add /dev/sdd /mnt btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt btrfs device remove /dev/sdc /mnt ``` ## Чексуммы и scrub btrfs хранит **crc32c** (или blake2/sha256/xxhash) на каждый блок. При чтении - проверка. Если нет совпадения и есть RAID - читает с другого диска и **чинит на лету**. Превентивная проверка: ```bash btrfs scrub start /mnt btrfs scrub status /mnt ``` Прогон по всему диску, проверяет каждый блок. На SAS/NVMe - фоновый, на HDD заметен. Раз в неделю/месяц по cron'у - норма. ## Сжатие ```fstab ... compress=zstd:1 ... ``` Прозрачное сжатие. Алгоритмы: `zlib`, `lzo`, `zstd:1..15`. zstd:1 - быстрый, ~30% экономии на типичных текстовых данных. Уже записанные файлы можно пересжать: ```bash btrfs filesystem defragment -r -czstd /mnt/data ``` ## Когда что-то пошло не так - **`No space left` при свободных ГБ** - btrfs аллоцирует chunks отдельно для data/metadata; metadata кончились. `btrfs balance start -musage=50 /mnt` пересобирает chunks. На full-FS даже balance может не запуститься - удалить хоть что-то сначала. - **БД медленная и фрагментируется** - не выключили COW. `chattr +C` на директорию ДО создания файлов БД. - **Снапшоты съели всё место** - удалить старые: `btrfs subvolume delete /mnt/@snapshots/old-*`. Полное освобождение - после балансировки. - **`parent transid verify failed`** - corruption. `btrfs check` (только diagnostics), для починки `btrfs check --repair` (РИСК!), лучше mount `-o ro,recovery` и спасать данные. - **RAID 5/6 после crash'а потерял данные** - известная проблема write-hole. Используй RAID 1/10 для multi-disk. - **Диск заполнен на 90% и тормозит** - btrfs не любит near-full. Держи под 80%. ## Когда выбирать btrfs | Use case | Btrfs? | |----------|--------| | Workstation с автоснапшотами | ✓ - openSUSE/Snapper интеграция | | NAS с дедупликацией нет | ✗ - бери ZFS | | NAS с снапшотами и RAID 1/10 | ✓ | | БД-сервер | ✗ - ext4/xfs + LVM-snapshot | | VM-host с qcow2 | ✗ или с `chattr +C` | | Контейнерный хост | ✓ - native overlayfs или snapshotting | | Нужен RAID 5/6 в проде | ✗ - mdraid + ext4/xfs | ## Команды ```bash sudo mkfs.btrfs -L data -f /dev/sdb ``` Создать btrfs на одном диске; -f форсирует если есть signature ```bash sudo btrfs subvolume snapshot -r /mnt/@home /mnt/@snap-$(date +%F) ``` Read-only снапшот - база для send/receive репликации ```bash sudo btrfs scrub start /mnt && sudo btrfs scrub status /mnt ``` Запустить полную проверку чексумм - находит bit rot до того как он навредит ```bash sudo btrfs filesystem usage /mnt ``` Реальное использование data/metadata - df обманывает на btrfs ```bash sudo btrfs balance start -dusage=50 /mnt ``` Перепаковать недозаполненные chunks - освободить metadata-allocation ```bash sudo btrfs send -p old.snap new.snap | ssh remote 'btrfs receive /backup' ``` Инкрементальный send - бэкап только дельты между снапшотами ```bash sudo chattr +C /data/postgres ``` Отключить COW для директории - до создания файлов БД! ## См. также - [Файловые системы: ext4, xfs, btrfs, zfs](/kb/filesystems.md) - [ext4 - рабочая лошадь Linux-ФС](/kb/ext4.md) - [XFS - extents и параллельный I/O](/kb/xfs.md) - [LVM - Logical Volume Manager](/kb/lvm.md) - [fsck и recovery - проверка и восстановление ФС](/kb/fsck-and-recovery.md)