Разработчики Btrfs подготовили для Linux 7.4 ускорение распаковки Zstd, сокращение блокировок при клонировании файлов и более экономную обработку кэша метаданных. Сопровождающий файловой системы Дэвид Стерба отправил запрос на включение изменений . В набор также вошли исправления квот, выделения памяти и работы при нехватке свободного места. По состоянию на стабильного Linux 7.4 ещё нет: kernel.org указывает Linux 7.3, выпущенный 18 октября.
Какие задачи ускоряют в Btrfs
Btrfs поддерживает прозрачное сжатие, контрольные суммы, подтома и снимки состояния. Например, на этих возможностях построены автоматические снимки пользовательских файлов в KDE Linux. Изменения для Linux 7.4 затрагивают несколько разных операций, поэтому оценивать их одним процентом прироста некорректно.
Копирование при записи, или CoW – механизм, позволяющий разным версиям данных совместно использовать блоки. При изменении общей области файловая система записывает новую версию отдельно, сохраняя данные, на которые ещё ссылаются другие файлы или снимки.
В предыдущем выпуске разработчики уже улучшили производительность Btrfs в Linux 7.3, в частности прямую запись с контрольными суммами. В наборе для 7.4 акцент сместился на распаковку сжатых данных, конкуренцию за блокировки и обработку ошибок.
Распаковка Zstd: меньше копирований в памяти
Патч Усамы Арифа убирает промежуточное копирование: распаковка записывает результат прямо в целевые страницы кэша. Временный буфер остаётся для участков потока без целевой страницы.
Условия теста: KVM x86-64, два виртуальных CPU, страницы 4 КиБ, RAM-диск, файл 64 МиБ со сжатием Zstd. Для последовательного чтения автор привёл медианы семи запусков с холодным кэшем в каждой из шести чередующихся пар загрузок исходного и изменённого ядра. Отсутствие страниц файла в памяти перед каждым запуском проверялось через mincore.
Результаты последовательного чтения с упреждающей загрузкой:
| Размер блока Btrfs | До изменения | После изменения | Сокращение времени по данным автора |
|---|---|---|---|
| 4 КиБ | 8,678 мс | 8,004 мс | 7,80% |
| 16 КиБ | 8,216 мс | 7,934 мс | 3,64% |
| 64 КиБ | 7,875 мс | 7,344 мс | 6,88% |
Проценты в последнем столбце приведены автором патча. При расчёте непосредственно по опубликованным значениям времени получаются 7,77%, 3,43% и 6,74% соответственно; причину расхождения источник не поясняет.
Случайное чтение pread блоками 4 КиБ при блоке Btrfs 4 КиБ ускорилось с 264,33 до 272,67 МБ/с: на 8,34 МБ/с, или 3,2%. Это средние по шести парам загрузок; патч выиграл в каждой. Результат относится к этой нагрузке.
По документации Btrfs, включение сжатия влияет на новые записи и само по себе не перепаковывает существующие данные. Улучшение распаковки полезно при чтении уже сжатых Zstd-экстентов; включать новый алгоритм для него не требуется. Несжатые данные и файлы с другими алгоритмами не используют этот путь.
Освобождение памяти: пропуск лишних блокировок
Другая оптимизация касается shrinker – механизма освобождения памяти, занятой кэшем отображений экстентов. Он перебирает inode, внутренние структуры файлов. Прежде код захватывал блокировку дерева отображений даже для inode, у которых это дерево пустое. Теперь предварительная проверка позволяет сразу пропустить такие структуры.
Брено Лейтан измерил затраты функции find_first_inode_to_shrink() на системе arm64 с Neoverse V2 и восемью CPU. В микротесте использовались Btrfs размером 6 ГиБ на loop-устройстве, 100 000 открытых пустых файлов и 200 файлов по 1 МиБ. Каждый запуск включал 15 циклов очистки кэша, повторного чтения и запуска shrinker; основную сборку проверяли без отладки блокировок. Ниже – медианные затраты на один просмотренный inode из описания патча и его проверки.
| Условия | До изменения | После изменения | Сокращение затрат |
|---|---|---|---|
| Без параллельного чтения | 46,4 нс | 40,1 нс | 13,6% |
| Четыре параллельных читателя | 47,8 нс | 38,4 нс | 19,7% |
В отдельной сборке с CONFIG_LOCK_STAT тот же тест дал следующие показатели блокировки дерева отображений:
| Показатель | До изменения | После изменения | Снижение |
|---|---|---|---|
| Захваты на запись | 628 016 | 228 000 | 63,7% |
| Суммарное время удержания | 47 512 мкс | 22 717 мкс | 52,2% |
| Перемещения строки кэша при захвате, acq cacheline bounces | 1574 | 1288 | 18,2% |
По профилированию серверов Meta, весь shrinker отображений экстентов занимал около 0,35% процессорного времени ядра без учёта простоя. Поэтому упомянутые 10–20% описывают сокращение затрат конкретной функции при обходе inode.
Reflink: меньше задержек при параллельном чтении
Reflink – клонирование файла с совместным использованием блоков данных. Файлы остаются независимыми: последующая запись в один из них не меняет другой. Клонирование работает в пределах одной файловой системы.
Типичный вызов из документации Btrfs:
cp --reflink=always source target
У источника и назначения должны быть совместимые настройки NOCOW и контрольных сумм. Параметр --reflink=always требует именно клонирования и не подменяет его обычным копированием, если операция недоступна.
Серия Бориса Буркова меняет порядок сброса данных и удержания блокировок исходного файла. Предварительный сброс выполняется до захвата блокировок, а после необходимой подготовки блокировка источника переводится из исключительного режима в совместный. Это позволяет другим операциям чтения обращаться к файлу во время обхода его экстентов.
В примере разработчика клонирование недавно записанного файла размером 4 ГиБ занимало около 0,5 секунды с патчем и без него. Однако параллельное прямое чтение 4 КиБ прежде ожидало почти всё время клонирования, а после изменения завершалось за несколько миллисекунд. В другом тесте с файлом из 32 000 экстентов отдельная правка устранила наблюдавшиеся задержки читателей свыше 100 мс.
Предварительный сброс пропускается, если исходный файл открыт для записи или имеет отображения памяти с разрешённой записью: иначе одни и те же страницы могли бы записываться повторно. Проверка носит рекомендательный характер, и при частом открытии и закрытии файла для записи она не исключает лишнюю работу полностью. Поэтому эффект зависит от сочетания чтения, записи и клонирования.
Какие ещё изменения подготовили для Linux 7.4
Помимо трёх оптимизаций, набор Btrfs включает следующие исправления:
- Выделение памяти. Для ряда буферов B-деревьев и сжатия используется kvmalloc; изменение связано с предупреждениями при фрагментированной памяти и применением крупных folio.
- Нехватка места. Системные чанки выделяются раньше; скорректирована фиксация транзакций после удаления неиспользуемых групп блоков.
- Квоты qgroup. Исправлены включение и отключение квот, обновление связей между группами и обработка ошибок.
- Проверка метаданных. Tree-checker отклоняет экстенты данных у специальных файлов.
- RAID5/6. Код пропускает проверку содержимого, когда контрольные суммы данных отсутствуют.
- Диагностика. В журнале устранена неоднозначность обозначения аварийного отключения и добавлено состояние блокировки отложенных iput.
- Сопровождение кода. Продолжается переход от page к folio, упрощаются состояния транзакций и параметры функций.
Отдельная группа патчей переносит выделение памяти для некоторых операций с каталогами на этап до изменения B-дерева. Например, переименование без замены существующего файла сможет вернуть ENOMEM до удаления исходного имени из старого каталога. Переименование с заменой существующего файла этим исправлением полностью не охвачено: при нехватке памяти транзакция всё ещё может прерываться.
Для квот исправлено обращение к уже освобождённой памяти при неудачном включении: после ошибки выделения структуры qgroup код мог сохранить ссылку на освобождённое дерево квот в списке изменённых корней транзакции. Исправление обеспечивает очистку этого состояния перед освобождением дерева.
Исправление RAID5/6 касается конкретной проверки и не означает изменения общего статуса этих режимов: документация Btrfs по-прежнему описывает их как экспериментальные и неготовые для производственного применения.
Восстановление: более точный выбор резервного корня
Изменится поведение rescue=usebackuproot: код будет выбирать второй по новизне резервный слот с корнями деревьев, пропуская самый новый. Для явного выбора добавляются варианты usebackuproot_N.
Эти параметры относятся к аварийному монтированию. Начиная с Linux 7.3, rescue=usebackuproot требует режима только для чтения; старую самостоятельную опцию usebackuproot в 7.3 удалили. В документации и старых инструкциях эти две формы нужно различать.
Что разрабатывают отдельно: уровень сжатия для каждого файла
За пределами проверенного набора для Linux 7.4 обсуждается серия патчей для индивидуальных уровней сжатия. Она предлагает сохранять в свойстве btrfs.compression не только алгоритм, но и уровень, например zstd:3 или zstd:10.
Для каталога такую настройку должны наследовать новые дочерние файлы и каталоги; уже существующие объекты не изменятся. Это позволит выбирать степень сжатия для разных наборов данных без назначения единого уровня через параметры монтирования.
Сейчас документация допускает выбор алгоритма свойством файла, но прямо указывает, что настройка уровня этим способом ещё не реализована. Серия также исправляет наследование числового уровня от параметра монтирования при выборе другого алгоритма и сохранение свойства сжатия при изменении атрибутов файла. В запросе Стербы от 15 октября этих патчей нет, поэтому относить функцию к Linux 7.4 пока нельзя.
Когда изменения получат пользователи
Для перечисленных изменений ядра потребуется Linux 7.4 с соответствующими патчами либо их перенос разработчиками дистрибутива в используемую ветку. Обновление одних утилит btrfs-progs не меняет реализацию файловой системы в работающем ядре. Даты появления пакетов в конкретных дистрибутивах запрос на включение не устанавливает.
Таблицы выше показывают результаты разработчиков в заданных нагрузках. Замеры Zstd на RAM-диске и обхода inode на loop-устройстве не позволяют обещать такой же прирост при загрузке рабочего стола, запуске игр или работе любого накопителя.
Вывод
Подготовленные изменения полезны прежде всего при чтении данных со сжатием Zstd, одновременном клонировании и чтении файлов, а также освобождении кэша Btrfs. Исправления выделения памяти, квот и служебного пространства дополняют оптимизации обработкой проблемных ситуаций. Пользователям стоит ориентироваться на состав ядра своего дистрибутива: индивидуальные уровни сжатия для файлов пока остаются отдельной разработкой.