Зачем XFS
XFS родился у SGI в 1993 для IRIX и больших стораджей. Главные отличия от ext4:
- Allocation groups - ФС разбита на N независимых регионов; разные процессы пишут в разные AG параллельно
- Extent-based allocation - фрагмент описывается одним extent'ом (start, length), а не списком блоков
- Динамическое выделение inode'ов - не фиксируется при mkfs
- Delayed allocation - блоки выделяются при flush, а не при write
- Журналирует только метаданные - агрессивно
- Online grow есть, shrink - нет
С RHEL 7 (2014) - default. Хорошо ложится на БД (PostgreSQL, MySQL), файловые серверы, kvm/qemu-диски, mail-spool с большими mbox.
Allocation Groups - ключ к параллелизму
ФС делится на N равных регионов (по дефолту - по 4 на CPU при mkfs). Каждый AG - почти независимая мини-ФС: свои свободные блоки, свои inode'ы. Это позволяет:
- Несколько процессов пишут одновременно в разные AG без блокировок
- Allocation решения локальны (близкие inode'ы → близкие блоки)
- Быстрый mkfs (форматируешь по AG параллельно)
$ mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=...
Можно переопределить:
mkfs.xfs -d agcount=16 /dev/sdb1
Больше AG = больше параллелизма, но и больше overhead. Default обычно ок.
Inode - динамические
В отличие от ext4 (фиксированы при mkfs), XFS выделяет inode'ы по мере необходимости. Никогда не упрёшься в "no space, but free GB".
Минусы: inode разбросаны по ФС, директорный обход медленнее на HDD. На SSD неактуально.
Размер inode по дефолту 512B (раньше был 256B). Большой inode хорош для встроенных extended-attributes и ACL без выделения отдельных блоков.
mkfs.xfs -i size=1024 /dev/sdb1 # ещё больше места под xattr
Журналирование
XFS журналит только метаданные. Данные защищаются delayed allocation + barriers. Журнал лежит во встроенной зоне (можно вынести):
mkfs.xfs -l logdev=/dev/nvme0n1p1,size=128m /dev/sdb1
mount -o logdev=/dev/nvme0n1p1 /dev/sdb1 /mnt/data
Обычно log на NVMe ускоряет тяжёлый metadata-load (создание/удаление миллионов файлов).
Mount-опции
UUID=... /data xfs defaults,noatime,nodiratime,inode64,logbsize=256k 0 0
| Опция | Что |
|---|---|
noatime | как везде - выкл. atime |
inode64 (default с RHEL7) | inode'ы могут быть в любой AG; без этого они только в нижних 1 TiB |
logbsize=256k | размер log buffer'а; больше = быстрее на metadata-heavy |
largeio | optimal-I/O size в st_blksize - подсказка приложениям |
nobarrier | выкл барьеры - быстрее, но опасно на не-battery RAID |
pquota, uquota, gquota | квоты по project/user/group |
Барьеры (barrier=1) гарантируют, что журнал на диске до
данных. На HW-RAID с battery-backed cache можно без них (ставь
nobarrier), но это ответственность за корректность сторадж-стэка.
Online grow
# Сначала ресайз раздела/LV
parted /dev/sdb resizepart 1 100%
# или
lvextend -L+100G /dev/vg/lv-data
# Затем XFS подхватывает
xfs_growfs /mnt/data
xfs_growfs принимает mountpoint, не device. ФС должна быть
смонтирована.
Shrink невозможен. Если нужно уменьшить - бэкап, mkfs, restore. Это самое больное место XFS.
xfs_info, xfs_db
xfs_info /mnt/data # структура: AG count, block size, log
xfs_db -r /dev/sdb1 -c "version" # внутренние детали (read-only безопасно)
xfs_io -c "stat" /path/to/file # parent inode, extents
xfs_io -c "fiemap" file # карта extents
xfs_bmap -v file # альтернатива fiemap
xfs_db - низкоуровневый дебаггер; в RW-режиме можно случайно поломать ФС.
xfs_repair vs e2fsck
XFS делает journal replay автоматически при mount. Если этого недостаточно (corruption после crash'а контроллера, bad sectors):
umount /mnt/data
xfs_repair /dev/sdb1 # размонтировано обязательно
xfs_repair -L /dev/sdb1 # форс с обнулением журнала (РИСК!)
-L - последний шанс: обнуляет log, теряя то что не успело
закоммититься. Только если обычный repair падает с "log is corrupt".
В отличие от [[ext4|e2fsck]], xfs_repair не правит мелочи на здоровой ФС - он либо нужен, либо нет.
Quota
XFS quota - три измерения:
- uquota - per user
- gquota - per group
- pquota - per project (группа inode'ов помеченных одним id)
pquota уникальна для XFS: можно квотировать произвольное поддерево
директорий, не привязанное к user/group:
mount -o pquota /dev/sdb1 /data
echo '42:/data/projects/foo' >> /etc/projects
echo 'foo:42' >> /etc/projid
xfs_quota -x -c 'project -s foo' /data
xfs_quota -x -c 'limit -p bhard=10g foo' /data
XFS vs ext4
| Признак | XFS | ext4 |
|---|---|---|
| Inode | динамические | фиксированные при mkfs |
| Параллельный I/O | сильно (AG) | слабее |
| Огромные ФС (>16 TiB) | хорошо | хуже из-за structure |
| Мелкие файлы | хорошо | хорошо (плотнее упаковка) |
| Online resize | grow only | grow + shrink |
| Crash recovery | journal replay | journal replay + extensive fsck |
| RAM на metadata | больше | меньше |
| Default где | RHEL 7+, CentOS, Oracle Linux | Debian/Ubuntu/Mint |
Для root-FS на хосте без особых требований - оба ок. Для data-партиции с БД, виртуалками, parallel-load - выбирай XFS.
Когда что-то пошло не так
xfs_growfs: data size unchanged- раздел/LV ещё не ресайзнут. Сначалаparted resizepartилиlvextend, потомxfs_growfs.Structure needs cleaningпри mount после краша - runxfs_repair. Если жалуется на log --L(с понимаем риска).- fragmentation - XFS обычно сама не фрагментируется, но при
near-full ФС начинает.
xfs_db -c frag /dev/sdb1(только R/O).xfs_fsr- online defrag. - mkfs на NVME упрямится про block size 4K - старые xfsprogs
не умели; обнови
xfsprogs >= 5.0. - Quota не считает project - забыл
mount -o pquotaили мисксprjquota(более старое имя). Cannot allocate memoryпри mount после crash'а - очень большой журнал; нужно больше RAM или вынести log на отдельный диск.