Почему так много данных btrfs-send для reflinks

Вопрос или проблема

Я испытываю очень странную проблему с “send” в Btrfs с файловыми ссылками, и после множества попыток я нашел некоторые детали:

Сначала я создал подтом “1”:

btrfs subvolume create 1

и записал в него файл:

dd if=/dev/urandom of=1/a bs=64 count=3110017

Теперь создаем снимок только для чтения с помощью sudo btrfs subvolume snapshot -r 1 1_ro0, а затем выполняем cp --reflink=always 1/a 1/b, снова создаем снимок только для чтения: sudo btrfs subvolume snapshot -r 1 1_ro1. Теперь подсчитаем размер данных с помощью “btrfs send”:

sudo btrfs send -p 1_ro0 1_ro1 | wc -c

Выводит 64864765, что примерно равно 61.9MiB. Это так аномально – я просто скопировал его с использованием reflink, не понимаю, почему “btrfs send” выводит так много данных.

Однако, если заменить count в dd на 3110016 (3110017-1), и снова выполнить указанные выше операции, с wc -c на “btrfs send”, вы получите 604 (604 Б), всего 604 байта, и это то, чего я ожидал.

Я также написал bash-скрипт для выполнения этих двух тестов:

#!/bin/bash

btrfs subvolume create 1

rm -rf 1/*
dd if=/dev/urandom of=1/a bs=64 count=3110017
sudo btrfs subvolume snapshot -r 1 1_ro0
cp --reflink=always 1/a 1/b
sudo btrfs subvolume snapshot -r 1 1_ro1
sudo btrfs send -p 1_ro0 1_ro1 | wc -c
sudo btrfs subvolume delete 1_ro0 1_ro1


rm -rf 1/*
dd if=/dev/urandom of=1/a bs=64 count=3110016
sudo btrfs subvolume snapshot -r 1 1_ro0
cp --reflink=always 1/a 1/b
sudo btrfs subvolume snapshot -r 1 1_ro1
sudo btrfs send -p 1_ro0 1_ro1 | wc -c
sudo btrfs subvolume delete 1_ro0 1_ro1

rm -r 1

Если заменить wc -c на btrfs receive --dump, чтобы исследовать данные вывода “btrfs send”, то при значении dd 3110016 он выведет несколько записей “clone” такого типа:

clone           ./1_ro1/b                       offset=0 len=134217728 from=./1_ro1/a clone_offset=0
clone           ./1_ro1/b                       offset=134217728 len=64823296 from=./1_ro1/a clone_offset=134217728
...

Но при значении dd 3110017 он выведет:

write           ./1_ro1/b                       offset=197918720 len=49152
write           ./1_ro1/b                       offset=197967872 len=49152
write           ./1_ro1/b                       offset=198017024 len=49152
write           ./1_ro1/b                       offset=198066176 len=49152
write           ./1_ro1/b                       offset=198115328 len=49152
write           ./1_ro1/b                       offset=198164480 len=49152
... (намного больше)

которые содержит множество записей “write”.

Я также искал и заметил этот сайт: https://www.spinics.net/lists/linux-btrfs/msg105951.html, и там, похоже, говорится о “дырах” в файлах, но в моем случае это явно не может быть.

Это так странно, и я не знаю, что я упускаю.

Моя версия btrfs-progs – 5.18.1-1

а параметры монтирования из /proc/mount: rw,relatime,space_cache=v2,subvolid=5,subvol=/

Спасибо!

Разработчики заметили это и что-то с этим сделали. https://github.com/kdave/btrfs-progs/issues/572

Ответ или решение

Проблема с объемом данных, получаемым при использовании команды btrfs send, связана с особенностями работы системы файлов Btrfs, особенно в контексте операций с референциями (reflinks) и тем, как они обрабатываются при создании снимков и отправке данных.

Причины высокой суммы данных при btrfs send

  1. Отличия в размере данных: Как вы заметили, различие в количестве записанных байтов (3110017 против 3110016) приводит к заметной разнице в размере данных, отправляемых через btrfs send. Это связано с тем, что при создании файла с размером, кратным определенному порогу, Btrfs может использовать более эффективные методы копирования, такие как clone, что позволяет избежать дублирования данных.

  2. Динамика управления данными: Когда вы используете cp --reflink=always, и размер файла не соответствует определенному критерию (например, не является кратным размеру блока), это может привести к тому, что Btrfs будет считывать данные из файла более фрагментированными кусками и записывать их в новом месте как обычные записи (write), а не как ссылки на существующие блоки. Это, в свою очередь, значительно увеличивает объем передаваемых данных.

  3. Структура данных Btrfs: В Btrfs данные организованы в формате, который оптимизирует использование пространства на диске через снапшоты и референции. Однако существует вероятность, что при использовании различных комбинаций снимков и референций Btrfs может решить, что данные были изменены, и соответственно, передает их как обычный запись вместо использования ссылок.

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

Рекомендации

  1. Использование одного размера блока: Если есть возможность, старайтесь использовать размеры файлов, которые кратны размеру блока вашей файловой системы. Это может помочь уменьшить количество записей write и увеличить количество записей clone при выполнении btrfs send.

  2. Обновление btrfs-progs: Убедитесь, что у вас установлена последняя версия btrfs-progs, так как разработчики могут внедрять исправления и улучшения, которые могут повлиять на производительность и поведение системы с точки зрения управления данными.

  3. Мониторинг и тестирование: Продолжайте тестировать разные подходы к созданию файлов и снимков. Важно понимать, как системные события влияют на ваши результаты, поскольку каждая операция может интерпретироваться Btrfs по-разному в зависимости от конфигурации и состояния файловой системы.

Заключение

Выводы из вашего тестирования показывают, что Btrfs является сложной системой, и ее поведение может варьироваться в зависимости от мелких изменений в данных и их размещении. Изучение особенностей работы этой файловой системы и экспериментирование с параметрами может привести к более предсказуемым и эффективным результатам.

Оцените материал
Добавить комментарий

Капча загружается...